diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 4cb5eed6556..df60d23ee0c 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -19,7 +19,7 @@ parameters: - name: ENABLE_TERRAPIN displayName: "Enable Terrapin" type: boolean - default: false + default: true - name: VSCODE_BUILD_WIN32 displayName: "🎯 Windows x64" type: boolean diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index 60d6a79c926..504babe93b0 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -199,7 +199,38 @@ exports.watchExtensionsTask = watchExtensionsTask; const compileExtensionsBuildLegacyTask = task.define('compile-extensions-build-legacy', task.parallel(...tasks.map(t => t.compileBuildTask))); gulp.task(compileExtensionsBuildLegacyTask); -// Azure Pipelines +//#region Extension media + +// Additional projects to webpack. These typically build code for webviews +const mediaCompilations = [ + 'markdown-language-features/webpack.config.js', + 'markdown-language-features/webpack.notebook.js', + 'notebook-markdown-extensions/webpack.notebook.js', +]; + +const compileExtensionMediaTask = task.define('compile-extension-media', () => buildExtensionMedia(false)); +gulp.task(compileExtensionMediaTask); +exports.compileExtensionMediaTask = compileExtensionMediaTask; + +const watchExtensionMedia = task.define('watch-extension-media', () => buildExtensionMedia(true)); +gulp.task(watchExtensionMedia); +exports.watchExtensionMedia = watchExtensionMedia; + +function buildExtensionMedia(isWatch, outputRoot) { + const webpackConfigLocations = mediaCompilations.map(p => { + return { + configPath: path.join(extensionsPath, p), + outputRoot: outputRoot ? path.join(root, outputRoot, path.dirname(p)) : undefined + }; + }); + return webpackExtensions('packaging extension media', isWatch, webpackConfigLocations); +} +const compileExtensionMediaBuildTask = task.define('compile-extension-media-build', () => buildExtensionMedia(false, '.build/extensions')); +gulp.task(compileExtensionMediaBuildTask); + +//#endregion + +//#region Azure Pipelines const cleanExtensionsBuildTask = task.define('clean-extensions-build', util.rimraf('.build/extensions')); const compileExtensionsBuildTask = task.define('compile-extensions-build', task.series( @@ -209,10 +240,12 @@ const compileExtensionsBuildTask = task.define('compile-extensions-build', task. )); gulp.task(compileExtensionsBuildTask); -gulp.task(task.define('extensions-ci', task.series(compileExtensionsBuildTask))); +gulp.task(task.define('extensions-ci', task.series(compileExtensionsBuildTask, compileExtensionMediaBuildTask))); exports.compileExtensionsBuildTask = compileExtensionsBuildTask; +//#endregion + const compileWebExtensionsTask = task.define('compile-web', () => buildWebExtensions(false)); gulp.task(compileWebExtensionsTask); exports.compileWebExtensionsTask = compileWebExtensionsTask; @@ -222,23 +255,39 @@ gulp.task(watchWebExtensionsTask); exports.watchWebExtensionsTask = watchWebExtensionsTask; async function buildWebExtensions(isWatch) { - const webpack = require('webpack'); - const webpackConfigLocations = await nodeUtil.promisify(glob)( 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 webpackConfigPath of webpackConfigLocations) { - const configOrFnOrArray = require(webpackConfigPath); + for (const { configPath, outputRoot } of webpackConfigLocations) { + const configOrFnOrArray = require(configPath); function addConfig(configOrFn) { + let config; if (typeof configOrFn === 'function') { - webpackConfigs.push(configOrFn({}, {})); + config = configOrFn({}, {}); + webpackConfigs.push(config); } else { - webpackConfigs.push(configOrFn); + config = configOrFn; } + + if (outputRoot) { + config.output.path = path.join(outputRoot, path.relative(path.dirname(configPath), config.output.path)); + } + + webpackConfigs.push(configOrFn); } addConfig(configOrFnOrArray); } @@ -249,7 +298,7 @@ async function buildWebExtensions(isWatch) { if (outputPath) { const relativePath = path.relative(extensionsPath, outputPath).replace(/\\/g, '/'); const match = relativePath.match(/[^\/]+(\/server|\/client)?/); - fancyLog(`Finished ${ansiColors.green('packaging web extension')} ${ansiColors.cyan(match[0])} with ${stats.errors.length} errors.`); + fancyLog(`Finished ${ansiColors.green(taskName)} ${ansiColors.cyan(match[0])} with ${stats.errors.length} errors.`); } if (Array.isArray(stats.errors)) { stats.errors.forEach(error => { diff --git a/build/gulpfile.js b/build/gulpfile.js index 69b37c7c667..8b991e27a16 100644 --- a/build/gulpfile.js +++ b/build/gulpfile.js @@ -13,7 +13,7 @@ const util = require('./lib/util'); const task = require('./lib/task'); const compilation = require('./lib/compilation'); const { monacoTypecheckTask/* , monacoTypecheckWatchTask */ } = require('./gulpfile.editor'); -const { compileExtensionsTask, watchExtensionsTask } = require('./gulpfile.extensions'); +const { compileExtensionsTask, watchExtensionsTask, compileExtensionMediaTask } = require('./gulpfile.extensions'); // Fast compile for development time const compileClientTask = task.define('compile-client', task.series(util.rimraf('out'), compilation.compileTask('src', 'out', false))); @@ -23,7 +23,7 @@ const watchClientTask = task.define('watch-client', task.series(util.rimraf('out gulp.task(watchClientTask); // All -const compileTask = task.define('compile', task.parallel(monacoTypecheckTask, compileClientTask, compileExtensionsTask)); +const compileTask = task.define('compile', task.parallel(monacoTypecheckTask, compileClientTask, compileExtensionsTask, compileExtensionMediaTask)); gulp.task(compileTask); gulp.task(task.define('watch', task.parallel(/* monacoTypecheckWatchTask, */ watchClientTask, watchExtensionsTask))); diff --git a/extensions/github/src/pushErrorHandler.ts b/extensions/github/src/pushErrorHandler.ts index 0303dfc5c0e..7f1eb7d0120 100644 --- a/extensions/github/src/pushErrorHandler.ts +++ b/extensions/github/src/pushErrorHandler.ts @@ -3,35 +3,91 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { PushErrorHandler, GitErrorCodes, Repository, Remote } from './typings/git'; -import { window, ProgressLocation, commands, Uri } from 'vscode'; +import { commands, env, ProgressLocation, UIKind, Uri, window } from 'vscode'; import * as nls from 'vscode-nls'; import { getOctokit } from './auth'; +import { GitErrorCodes, PushErrorHandler, Remote, Repository } from './typings/git'; const localize = nls.loadMessageBundle(); +type Awaited = T extends PromiseLike ? Awaited : T; + +export function isInCodespaces(): boolean { + return env.remoteName === 'codespaces'; +} + async function handlePushError(repository: Repository, remote: Remote, refspec: string, owner: string, repo: string): Promise { + const inCodespaces = isInCodespaces(); + let codespace: string | undefined; + if (inCodespaces) { + if (env.uiKind === UIKind.Web) { + // TODO@eamodio Find a better way to get the codespace id + // HACK to get the codespace id + try { + const codespaceUrl = (await env.asExternalUri(Uri.parse(`${env.uriScheme}://codespace/`))).authority; + if (codespaceUrl.endsWith('.github.dev')) { + codespace = codespaceUrl.slice(0, -11); + } else { + [codespace] = codespaceUrl.split('.'); + } + } catch { } + } else { + // TODO@eamodio Figure out how to get the codespace id when on the desktop + } + + if (!codespace) { + const ok = localize('ok', "OK"); + await window.showErrorMessage(localize('fork unable', "You don't have permissions to push to '{0}/{1}' on GitHub.", owner, repo), ok); + return; + } + } + const yes = localize('create a fork', "Create Fork"); const no = localize('no', "No"); const answer = await window.showInformationMessage(localize('fork', "You don't have permissions to push to '{0}/{1}' on GitHub. Would you like to create a fork and push to it instead?", owner, repo), yes, no); - if (answer === no) { return; } const match = /^([^:]*):([^:]*)$/.exec(refspec); const localName = match ? match[1] : refspec; - const remoteName = match ? match[2] : refspec; + let remoteName = match ? match[2] : refspec; const [octokit, ghRepository] = await window.withProgress({ location: ProgressLocation.Notification, cancellable: false, title: localize('create fork', 'Create GitHub fork') }, async progress => { progress.report({ message: localize('forking', "Forking '{0}/{1}'...", owner, repo), increment: 33 }); const octokit = await getOctokit(); + type CreateForkResponseData = Awaited>['data']; + // Issue: what if the repo already exists? - const res = await octokit.repos.createFork({ owner, repo }); - const ghRepository = res.data; + let ghRepository: CreateForkResponseData; + try { + if (inCodespaces) { + const userResp = await octokit.users.getAuthenticated(); + const user = userResp.data.login; + + const resp = await octokit.request<{ repository: CreateForkResponseData, ref: string }>({ method: 'POST', url: `/vscs_internal/user/${user}/codespaces/${codespace}/fork_repo` }); + ghRepository = resp.data.repository; + + if (resp.data.ref) { + let ref = resp.data.ref; + if (ref.startsWith('refs/heads/')) { + ref = ref.substr(11); + } + + remoteName = ref; + } + } else { + const resp = await octokit.repos.createFork({ owner, repo }); + ghRepository = resp.data; + } + } catch (ex) { + console.error(ex); + throw ex; + } + progress.report({ message: localize('forking_pushing', "Pushing changes..."), increment: 33 }); diff --git a/extensions/html-language-features/client/src/htmlClient.ts b/extensions/html-language-features/client/src/htmlClient.ts index 064cab91cdc..2c6e911910c 100644 --- a/extensions/html-language-features/client/src/htmlClient.ts +++ b/extensions/html-language-features/client/src/htmlClient.ts @@ -199,7 +199,7 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua languages.setLanguageConfiguration('html', { indentationRules: { - increaseIndentPattern: /<(?!\?|(?:area|base|br|col|frame|hr|html|img|input|link|meta|param)\b|[^>]*\/>)([-_\.A-Za-z0-9]+)(?=\s|>)\b[^>]*>(?!.*<\/\1>)|)|\{[^}"']*$/, + increaseIndentPattern: /<(?!\?|(?:area|base|br|col|frame|hr|html|img|input|keygen|link|menuitem|meta|param|source|track|wbr)\b|[^>]*\/>)([-_\.A-Za-z0-9]+)(?=\s|>)\b[^>]*>(?!.*<\/\1>)|)|\{[^}"']*$/, decreaseIndentPattern: /^\s*(<\/(?!html)[-_\.A-Za-z0-9]+\b[^>]*>|-->|\})/ }, wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g, diff --git a/extensions/markdown-language-features/media/index.js b/extensions/markdown-language-features/media/index.js deleted file mode 100644 index 3215cd6a04e..00000000000 --- a/extensions/markdown-language-features/media/index.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){var t={};function n(o){if(t[o])return t[o].exports;var i=t[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(o,i,function(t){return e[t]}.bind(null,i));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=3)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getSettings=t.getData=void 0;let o=void 0;function i(e){const t=document.getElementById("vscode-markdown-preview-data");if(t){const n=t.getAttribute(e);if(n)return JSON.parse(n)}throw new Error("Could not load data for "+e)}t.getData=i,t.getSettings=function(){if(o)return o;if(o=i("data-settings"),o)return o;throw new Error("Could not load settings")}},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getLineElementForFragment=t.getEditorLineNumberForPageOffset=t.scrollToRevealSourceLine=t.getLineElementsAtPageOffset=t.getElementsForSourceLine=void 0;const o=n(0);function i(e){return t=0,n=o.getSettings().lineCount-1,i=e,Math.min(n,Math.max(t,i));var t,n,i}const r=(()=>{let e;return()=>{if(!e){e=[{element:document.body,line:0}];for(const t of document.getElementsByClassName("code-line")){const n=+t.getAttribute("data-line");isNaN(n)||("CODE"===t.tagName&&t.parentElement&&"PRE"===t.parentElement.tagName?e.push({element:t.parentElement,line:n}):e.push({element:t,line:n}))}}return e}})();function s(e){const t=Math.floor(e),n=r();let o=n[0]||null;for(const e of n){if(e.line===t)return{previous:e,next:void 0};if(e.line>t)return{previous:o,next:e};o=e}return{previous:o}}function a(e){const t=r(),n=e-window.scrollY;let o=-1,i=t.length-1;for(;o+1=n?i=e:o=e}const s=t[i],a=c(s);if(i>=1&&a.top>n){return{previous:t[o],next:s}}return i>1&&in?{previous:s,next:t[i+1]}:{previous:s}}function c({element:e}){const t=e.getBoundingClientRect(),n=e.querySelector(".code-line");if(n){const e=n.getBoundingClientRect(),o=Math.max(1,e.top-t.top);return{top:t.top,height:o}}return t}t.getElementsForSourceLine=s,t.getLineElementsAtPageOffset=a,t.scrollToRevealSourceLine=function(e){if(!o.getSettings().scrollPreviewWithEditor)return;if(e<=0)return void window.scroll(window.scrollX,0);const{previous:t,next:n}=s(e);if(!t)return;let i=0;const r=c(t),a=r.top;if(n&&n.line!==t.line){i=a+(e-t.line)/(n.line-t.line)*(n.element.getBoundingClientRect().top-a)}else{const t=e-Math.floor(e);i=a+r.height*t}i=Math.abs(i)<1?Math.sign(i):i,window.scroll(window.scrollX,Math.max(1,window.scrollY+i))},t.getEditorLineNumberForPageOffset=function(e){const{previous:t,next:n}=a(e);if(t){const o=c(t),r=e-window.scrollY-o.top;if(n){const e=r/(c(n).top-o.top);return i(t.line+e*(n.line-t.line))}{const e=r/o.height;return i(t.line+e)}}return null},t.getLineElementForFragment=function(e){return r().find(t=>t.element.id===e)}},function(e,t,n){"use strict";(function(e){Object.defineProperty(t,"__esModule",{value:!0});const o=n(7),i=n(8),r=n(9),s=n(2),a=n(0),c=n(10);let u=0;const l=new o.ActiveLineMarker,f=a.getSettings(),d=acquireVsCodeApi(),m=d.getState(),g={..."object"==typeof m?m:{},...a.getData("data-state")};d.setState(g);const p=r.createPosterForVsCode(d);function h(t){const n=document.getElementsByTagName("img");if(n.length>0){const o=Array.from(n).map(e=>e.complete?Promise.resolve():new Promise(t=>{e.addEventListener("load",()=>t()),e.addEventListener("error",()=>t())}));Promise.all(o).then(()=>e(t))}else e(t)}window.cspAlerter.setPoster(p),window.styleLoadingMonitor.setPoster(p),window.onload=()=>{y()},i.onceDocumentLoaded(()=>{const e=g.scrollProgress;"number"!=typeof e||f.fragment?f.scrollPreviewWithEditor&&h(()=>{if(f.fragment){g.fragment=void 0,d.setState(g);const e=s.getLineElementForFragment(f.fragment);e&&(u+=1,s.scrollToRevealSourceLine(e.line))}else isNaN(f.line)||(u+=1,s.scrollToRevealSourceLine(f.line))}):h(()=>{u+=1,window.scrollTo(0,e*document.body.clientHeight)})});const v=(()=>{const e=c(e=>{u+=1,h(()=>s.scrollToRevealSourceLine(e))},50);return t=>{isNaN(t)||(g.line=t,e(t))}})();let y=c(()=>{const e=[];let t=document.getElementsByTagName("img");if(t){let n;for(n=0;n{u+=1,b(),y()},!0),window.addEventListener("message",e=>{if(e.data.source===f.source)switch(e.data.type){case"onDidChangeTextEditorSelection":l.onDidChangeTextEditorSelection(e.data.line);break;case"updateView":v(e.data.line)}},!1),document.addEventListener("dblclick",e=>{if(!f.doubleClickToSwitchToEditor)return;for(let t=e.target;t;t=t.parentNode)if("A"===t.tagName)return;const t=e.pageY,n=s.getEditorLineNumberForPageOffset(t);"number"!=typeof n||isNaN(n)||p.postMessage("didClick",{line:Math.floor(n)})});const w=["http:","https:","mailto:","vscode:","vscode-insiders:"];function b(){g.scrollProgress=window.scrollY/document.body.clientHeight,d.setState(g)}document.addEventListener("click",e=>{if(!e)return;let t=e.target;for(;t;){if(t.tagName&&"A"===t.tagName&&t.href){if(t.getAttribute("href").startsWith("#"))return;let n=t.getAttribute("data-href");if(!n){if(w.some(e=>t.href.startsWith(e)))return;n=t.getAttribute("href")}return/^[a-z\-]+:/i.test(n)?void 0:(p.postMessage("openLink",{href:n}),e.preventDefault(),void e.stopPropagation())}t=t.parentNode}},!0),window.addEventListener("scroll",c(()=>{if(b(),u>0)u-=1;else{const e=s.getEditorLineNumberForPageOffset(window.scrollY);"number"!=typeof e||isNaN(e)||p.postMessage("revealLine",{line:e})}},50))}).call(this,n(4).setImmediate)},function(e,t,n){(function(e){var o=void 0!==e&&e||"undefined"!=typeof self&&self||window,i=Function.prototype.apply;function r(e,t){this._id=e,this._clearFn=t}t.setTimeout=function(){return new r(i.call(setTimeout,o,arguments),clearTimeout)},t.setInterval=function(){return new r(i.call(setInterval,o,arguments),clearInterval)},t.clearTimeout=t.clearInterval=function(e){e&&e.close()},r.prototype.unref=r.prototype.ref=function(){},r.prototype.close=function(){this._clearFn.call(o,this._id)},t.enroll=function(e,t){clearTimeout(e._idleTimeoutId),e._idleTimeout=t},t.unenroll=function(e){clearTimeout(e._idleTimeoutId),e._idleTimeout=-1},t._unrefActive=t.active=function(e){clearTimeout(e._idleTimeoutId);var t=e._idleTimeout;t>=0&&(e._idleTimeoutId=setTimeout((function(){e._onTimeout&&e._onTimeout()}),t))},n(5),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(this,n(1))},function(e,t,n){(function(e,t){!function(e,n){"use strict";if(!e.setImmediate){var o,i,r,s,a,c=1,u={},l=!1,f=e.document,d=Object.getPrototypeOf&&Object.getPrototypeOf(e);d=d&&d.setTimeout?d:e,"[object process]"==={}.toString.call(e.process)?o=function(e){t.nextTick((function(){g(e)}))}:!function(){if(e.postMessage&&!e.importScripts){var t=!0,n=e.onmessage;return e.onmessage=function(){t=!1},e.postMessage("","*"),e.onmessage=n,t}}()?e.MessageChannel?((r=new MessageChannel).port1.onmessage=function(e){g(e.data)},o=function(e){r.port2.postMessage(e)}):f&&"onreadystatechange"in f.createElement("script")?(i=f.documentElement,o=function(e){var t=f.createElement("script");t.onreadystatechange=function(){g(e),t.onreadystatechange=null,i.removeChild(t),t=null},i.appendChild(t)}):o=function(e){setTimeout(g,0,e)}:(s="setImmediate$"+Math.random()+"$",a=function(t){t.source===e&&"string"==typeof t.data&&0===t.data.indexOf(s)&&g(+t.data.slice(s.length))},e.addEventListener?e.addEventListener("message",a,!1):e.attachEvent("onmessage",a),o=function(t){e.postMessage(s+t,"*")}),d.setImmediate=function(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),n=0;n1)for(var n=1;nnew class{postMessage(t,n){e.postMessage({type:t,source:o.getSettings().source,body:n})}}},function(e,t,n){(function(t){var n=/^\s+|\s+$/g,o=/^[-+]0x[0-9a-f]+$/i,i=/^0b[01]+$/i,r=/^0o[0-7]+$/i,s=parseInt,a="object"==typeof t&&t&&t.Object===Object&&t,c="object"==typeof self&&self&&self.Object===Object&&self,u=a||c||Function("return this")(),l=Object.prototype.toString,f=Math.max,d=Math.min,m=function(){return u.Date.now()};function g(e,t,n){var o,i,r,s,a,c,u=0,l=!1,g=!1,v=!0;if("function"!=typeof e)throw new TypeError("Expected a function");function y(t){var n=o,r=i;return o=i=void 0,u=t,s=e.apply(r,n)}function w(e){return u=e,a=setTimeout(T,t),l?y(e):s}function b(e){var n=e-c;return void 0===c||n>=t||n<0||g&&e-u>=r}function T(){var e=m();if(b(e))return E(e);a=setTimeout(T,function(e){var n=t-(e-c);return g?d(n,r-(e-u)):n}(e))}function E(e){return a=void 0,v&&o?y(e):(o=i=void 0,s)}function L(){var e=m(),n=b(e);if(o=arguments,i=this,c=e,n){if(void 0===a)return w(c);if(g)return a=setTimeout(T,t),y(c)}return void 0===a&&(a=setTimeout(T,t)),s}return t=h(t)||0,p(n)&&(l=!!n.leading,r=(g="maxWait"in n)?f(h(n.maxWait)||0,t):r,v="trailing"in n?!!n.trailing:v),L.cancel=function(){void 0!==a&&clearTimeout(a),u=0,o=c=i=a=void 0},L.flush=function(){return void 0===a?s:E(m())},L}function p(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function h(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==l.call(e)}(e))return NaN;if(p(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=p(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(n,"");var a=i.test(e);return a||r.test(e)?s(e.slice(2),a?2:8):o.test(e)?NaN:+e}e.exports=function(e,t,n){var o=!0,i=!0;if("function"!=typeof e)throw new TypeError("Expected a function");return p(n)&&(o="leading"in n?!!n.leading:o,i="trailing"in n?!!n.trailing:i),g(e,t,{leading:o,maxWait:t,trailing:i})}}).call(this,n(1))}]); \ No newline at end of file diff --git a/extensions/markdown-language-features/media/pre.js b/extensions/markdown-language-features/media/pre.js deleted file mode 100644 index 5a2fa42624c..00000000000 --- a/extensions/markdown-language-features/media/pre.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){var t={};function n(o){if(t[o])return t[o].exports;var s=t[o]={i:o,l:!1,exports:{}};return e[o].call(s.exports,s,s.exports,n),s.l=!0,s.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)n.d(o,s,function(t){return e[t]}.bind(null,s));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=11)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getSettings=t.getData=void 0;let o=void 0;function s(e){const t=document.getElementById("vscode-markdown-preview-data");if(t){const n=t.getAttribute(e);if(n)return JSON.parse(n)}throw new Error("Could not load data for "+e)}t.getData=s,t.getSettings=function(){if(o)return o;if(o=s("data-settings"),o)return o;throw new Error("Could not load settings")}},,,,,,,,,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(12),s=n(14);window.cspAlerter=new o.CspAlerter,window.styleLoadingMonitor=new s.StyleLoadingMonitor},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.CspAlerter=void 0;const o=n(0),s=n(13);t.CspAlerter=class{constructor(){this.didShow=!1,this.didHaveCspWarning=!1,document.addEventListener("securitypolicyviolation",()=>{this.onCspWarning()}),window.addEventListener("message",e=>{e&&e.data&&"vscode-did-block-svg"===e.data.name&&this.onCspWarning()})}setPoster(e){this.messaging=e,this.didHaveCspWarning&&this.showCspWarning()}onCspWarning(){this.didHaveCspWarning=!0,this.showCspWarning()}showCspWarning(){const e=s.getStrings(),t=o.getSettings();if(this.didShow||t.disableSecurityWarnings||!this.messaging)return;this.didShow=!0;const n=document.createElement("a");n.innerText=e.cspAlertMessageText,n.setAttribute("id","code-csp-warning"),n.setAttribute("title",e.cspAlertMessageTitle),n.setAttribute("role","button"),n.setAttribute("aria-label",e.cspAlertMessageLabel),n.onclick=()=>{this.messaging.postMessage("showPreviewSecuritySelector",{source:t.source})},document.body.appendChild(n)}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getStrings=void 0,t.getStrings=function(){const e=document.getElementById("vscode-markdown-preview-data");if(e){const t=e.getAttribute("data-strings");if(t)return JSON.parse(t)}throw new Error("Could not load strings")}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.StyleLoadingMonitor=void 0;t.StyleLoadingMonitor=class{constructor(){this.unloadedStyles=[],this.finishedLoading=!1;const e=e=>{const t=e.target.dataset.source;this.unloadedStyles.push(t)};window.addEventListener("DOMContentLoaded",()=>{for(const t of document.getElementsByClassName("code-user-style"))t.dataset.source&&(t.onerror=e)}),window.addEventListener("load",()=>{this.unloadedStyles.length&&(this.finishedLoading=!0,this.poster&&this.poster.postMessage("previewStyleLoadError",{unloadedStyles:this.unloadedStyles}))})}setPoster(e){this.poster=e,this.finishedLoading&&e.postMessage("previewStyleLoadError",{unloadedStyles:this.unloadedStyles})}}}]); \ No newline at end of file diff --git a/extensions/markdown-language-features/notebook-out/index.js b/extensions/markdown-language-features/notebook-out/index.js deleted file mode 100644 index 66df08f4026..00000000000 --- a/extensions/markdown-language-features/notebook-out/index.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){var t={};function r(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,r),s.l=!0,s.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)r.d(n,s,function(t){return e[t]}.bind(null,s));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=9)}([function(e,t,r){"use strict";var n=Object.prototype.hasOwnProperty;function s(e,t){return n.call(e,t)}function o(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!=(65535&e)&&65534!=(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function i(e){if(e>65535){var t=55296+((e-=65536)>>10),r=56320+(1023&e);return String.fromCharCode(t,r)}return String.fromCharCode(e)}var a=/\\([!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~])/g,u=new RegExp(a.source+"|"+/&([a-z#][a-z0-9]{1,31});/gi.source,"gi"),c=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,l=r(3);var p=/[&<>"]/,h=/[&<>"]/g,f={"&":"&","<":"<",">":">",'"':"""};function d(e){return f[e]}var m=/[.?*+^$[\]\\(){}|-]/g;var g=r(4);t.lib={},t.lib.mdurl=r(5),t.lib.ucmicro=r(17),t.assign=function(e){var t=Array.prototype.slice.call(arguments,1);return t.forEach((function(t){if(t){if("object"!=typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach((function(r){e[r]=t[r]}))}})),e},t.isString=function(e){return"[object String]"===function(e){return Object.prototype.toString.call(e)}(e)},t.has=s,t.unescapeMd=function(e){return e.indexOf("\\")<0?e:e.replace(a,"$1")},t.unescapeAll=function(e){return e.indexOf("\\")<0&&e.indexOf("&")<0?e:e.replace(u,(function(e,t,r){return t||function(e,t){var r=0;return s(l,t)?l[t]:35===t.charCodeAt(0)&&c.test(t)&&o(r="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10))?i(r):e}(e,r)}))},t.isValidEntityCode=o,t.fromCodePoint=i,t.escapeHtml=function(e){return p.test(e)?e.replace(h,d):e},t.arrayReplaceAt=function(e,t,r){return[].concat(e.slice(0,t),r,e.slice(t+1))},t.isSpace=function(e){switch(e){case 9:case 32:return!0}return!1},t.isWhiteSpace=function(e){if(e>=8192&&e<=8202)return!0;switch(e){case 9:case 10:case 11:case 12:case 13:case 32:case 160:case 5760:case 8239:case 8287:case 12288:return!0}return!1},t.isMdAsciiPunct=function(e){switch(e){case 33:case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:case 58:case 59:case 60:case 61:case 62:case 63:case 64:case 91:case 92:case 93:case 94:case 95:case 96:case 123:case 124:case 125:case 126:return!0;default:return!1}},t.isPunctChar=function(e){return g.test(e)},t.escapeRE=function(e){return e.replace(m,"\\$&")},t.normalizeReference=function(e){return e=e.trim().replace(/\s+/g," "),"Ṿ"==="ẞ".toLowerCase()&&(e=e.replace(/ẞ/g,"ß")),e.toLowerCase().toUpperCase()}},function(e,t,r){"use strict";function n(){this.__rules__=[],this.__cache__=null}n.prototype.__find__=function(e){for(var t=0;t=0&&(r=this.attrs[t][1]),r},n.prototype.attrJoin=function(e,t){var r=this.attrIndex(e);r<0?this.attrPush([e,t]):this.attrs[r][1]=this.attrs[r][1]+" "+t},e.exports=n},function(e,t,r){"use strict";e.exports=r(12)},function(e,t){e.exports=/[!-#%-\*,-/:;\?@\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E49\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD806[\uDE3F-\uDE46\uDE9A-\uDE9C\uDE9E-\uDEA2]|\uD807[\uDC41-\uDC45\uDC70\uDC71]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/},function(e,t,r){"use strict";e.exports.encode=r(13),e.exports.decode=r(14),e.exports.format=r(15),e.exports.parse=r(16)},function(e,t,r){"use strict";var n="<[A-Za-z][A-Za-z0-9\\-]*(?:\\s+[a-zA-Z_:][a-zA-Z0-9:._-]*(?:\\s*=\\s*(?:[^\"'=<>`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*\\/?>",s="<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>",o=new RegExp("^(?:"+n+"|"+s+"|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|<[?][\\s\\S]*?[?]>|]*>|)"),i=new RegExp("^(?:"+n+"|"+s+")");e.exports.HTML_TAG_RE=o,e.exports.HTML_OPEN_CLOSE_TAG_RE=i},function(e,t,r){"use strict";function n(e,t){var r,n,s,o,i,a=[],u=t.length;for(r=0;r=0;r--)95!==(n=t[r]).marker&&42!==n.marker||-1!==n.end&&(s=t[n.end],a=r>0&&t[r-1].end===n.end+1&&t[r-1].token===n.token-1&&t[n.end+1].token===s.token+1&&t[r-1].marker===n.marker,i=String.fromCharCode(n.marker),(o=e.tokens[n.token]).type=a?"strong_open":"em_open",o.tag=a?"strong":"em",o.nesting=1,o.markup=a?i+i:i,o.content="",(o=e.tokens[s.token]).type=a?"strong_close":"em_close",o.tag=a?"strong":"em",o.nesting=-1,o.markup=a?i+i:i,o.content="",a&&(e.tokens[t[r-1].token].content="",e.tokens[t[n.end+1].token].content="",r--))}e.exports.tokenize=function(e,t){var r,n,s=e.pos,o=e.src.charCodeAt(s);if(t)return!1;if(95!==o&&42!==o)return!1;for(n=e.scanDelims(e.pos,42===o),r=0;r{t(e)};acquireNotebookRendererApi("notebookCoreTestRenderer").onDidCreateMarkdown(({element:t,content:r})=>{const n=e.render(r);t.innerHTML=n})}()},function(e,t,r){"use strict";e.exports=r(11)},function(e,t,r){"use strict";var n=r(0),s=r(22),o=r(26),i=r(27),a=r(35),u=r(49),c=r(62),l=r(5),p=r(68),h={default:r(71),zero:r(72),commonmark:r(73)},f=/^(vbscript|javascript|file|data):/,d=/^data:image\/(gif|png|jpeg|webp);/;function m(e){var t=e.trim().toLowerCase();return!f.test(t)||!!d.test(t)}var g=["http:","https:","mailto:"];function _(e){var t=l.parse(e,!0);if(t.hostname&&(!t.protocol||g.indexOf(t.protocol)>=0))try{t.hostname=p.toASCII(t.hostname)}catch(e){}return l.encode(l.format(t))}function b(e){var t=l.parse(e,!0);if(t.hostname&&(!t.protocol||g.indexOf(t.protocol)>=0))try{t.hostname=p.toUnicode(t.hostname)}catch(e){}return l.decode(l.format(t),l.decode.defaultChars+"%")}function k(e,t){if(!(this instanceof k))return new k(e,t);t||n.isString(e)||(t=e||{},e="default"),this.inline=new u,this.block=new a,this.core=new i,this.renderer=new o,this.linkify=new c,this.validateLink=m,this.normalizeLink=_,this.normalizeLinkText=b,this.utils=n,this.helpers=n.assign({},s),this.options={},this.configure(e),t&&this.set(t)}k.prototype.set=function(e){return n.assign(this.options,e),this},k.prototype.configure=function(e){var t,r=this;if(n.isString(e)&&!(e=h[t=e]))throw new Error('Wrong `markdown-it` preset "'+t+'", check name');if(!e)throw new Error("Wrong `markdown-it` preset, can't be empty");return e.options&&r.set(e.options),e.components&&Object.keys(e.components).forEach((function(t){e.components[t].rules&&r[t].ruler.enableOnly(e.components[t].rules),e.components[t].rules2&&r[t].ruler2.enableOnly(e.components[t].rules2)})),this},k.prototype.enable=function(e,t){var r=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach((function(t){r=r.concat(this[t].ruler.enable(e,!0))}),this),r=r.concat(this.inline.ruler2.enable(e,!0));var n=e.filter((function(e){return r.indexOf(e)<0}));if(n.length&&!t)throw new Error("MarkdownIt. Failed to enable unknown rule(s): "+n);return this},k.prototype.disable=function(e,t){var r=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach((function(t){r=r.concat(this[t].ruler.disable(e,!0))}),this),r=r.concat(this.inline.ruler2.disable(e,!0));var n=e.filter((function(e){return r.indexOf(e)<0}));if(n.length&&!t)throw new Error("MarkdownIt. Failed to disable unknown rule(s): "+n);return this},k.prototype.use=function(e){var t=[this].concat(Array.prototype.slice.call(arguments,1));return e.apply(e,t),this},k.prototype.parse=function(e,t){if("string"!=typeof e)throw new Error("Input data should be a String");var r=new this.core.State(e,this,t);return this.core.process(r),r.tokens},k.prototype.render=function(e,t){return t=t||{},this.renderer.render(this.parse(e,t),this.options,t)},k.prototype.parseInline=function(e,t){var r=new this.core.State(e,this,t);return r.inlineMode=!0,this.core.process(r),r.tokens},k.prototype.renderInline=function(e,t){return t=t||{},this.renderer.render(this.parseInline(e,t),this.options,t)},e.exports=k},function(e){e.exports=JSON.parse('{"Aacute":"Á","aacute":"á","Abreve":"Ă","abreve":"ă","ac":"∾","acd":"∿","acE":"∾̳","Acirc":"Â","acirc":"â","acute":"´","Acy":"А","acy":"а","AElig":"Æ","aelig":"æ","af":"⁡","Afr":"𝔄","afr":"𝔞","Agrave":"À","agrave":"à","alefsym":"ℵ","aleph":"ℵ","Alpha":"Α","alpha":"α","Amacr":"Ā","amacr":"ā","amalg":"⨿","amp":"&","AMP":"&","andand":"⩕","And":"⩓","and":"∧","andd":"⩜","andslope":"⩘","andv":"⩚","ang":"∠","ange":"⦤","angle":"∠","angmsdaa":"⦨","angmsdab":"⦩","angmsdac":"⦪","angmsdad":"⦫","angmsdae":"⦬","angmsdaf":"⦭","angmsdag":"⦮","angmsdah":"⦯","angmsd":"∡","angrt":"∟","angrtvb":"⊾","angrtvbd":"⦝","angsph":"∢","angst":"Å","angzarr":"⍼","Aogon":"Ą","aogon":"ą","Aopf":"𝔸","aopf":"𝕒","apacir":"⩯","ap":"≈","apE":"⩰","ape":"≊","apid":"≋","apos":"\'","ApplyFunction":"⁡","approx":"≈","approxeq":"≊","Aring":"Å","aring":"å","Ascr":"𝒜","ascr":"𝒶","Assign":"≔","ast":"*","asymp":"≈","asympeq":"≍","Atilde":"Ã","atilde":"ã","Auml":"Ä","auml":"ä","awconint":"∳","awint":"⨑","backcong":"≌","backepsilon":"϶","backprime":"‵","backsim":"∽","backsimeq":"⋍","Backslash":"∖","Barv":"⫧","barvee":"⊽","barwed":"⌅","Barwed":"⌆","barwedge":"⌅","bbrk":"⎵","bbrktbrk":"⎶","bcong":"≌","Bcy":"Б","bcy":"б","bdquo":"„","becaus":"∵","because":"∵","Because":"∵","bemptyv":"⦰","bepsi":"϶","bernou":"ℬ","Bernoullis":"ℬ","Beta":"Β","beta":"β","beth":"ℶ","between":"≬","Bfr":"𝔅","bfr":"𝔟","bigcap":"⋂","bigcirc":"◯","bigcup":"⋃","bigodot":"⨀","bigoplus":"⨁","bigotimes":"⨂","bigsqcup":"⨆","bigstar":"★","bigtriangledown":"▽","bigtriangleup":"△","biguplus":"⨄","bigvee":"⋁","bigwedge":"⋀","bkarow":"⤍","blacklozenge":"⧫","blacksquare":"▪","blacktriangle":"▴","blacktriangledown":"▾","blacktriangleleft":"◂","blacktriangleright":"▸","blank":"␣","blk12":"▒","blk14":"░","blk34":"▓","block":"█","bne":"=⃥","bnequiv":"≡⃥","bNot":"⫭","bnot":"⌐","Bopf":"𝔹","bopf":"𝕓","bot":"⊥","bottom":"⊥","bowtie":"⋈","boxbox":"⧉","boxdl":"┐","boxdL":"╕","boxDl":"╖","boxDL":"╗","boxdr":"┌","boxdR":"╒","boxDr":"╓","boxDR":"╔","boxh":"─","boxH":"═","boxhd":"┬","boxHd":"╤","boxhD":"╥","boxHD":"╦","boxhu":"┴","boxHu":"╧","boxhU":"╨","boxHU":"╩","boxminus":"⊟","boxplus":"⊞","boxtimes":"⊠","boxul":"┘","boxuL":"╛","boxUl":"╜","boxUL":"╝","boxur":"└","boxuR":"╘","boxUr":"╙","boxUR":"╚","boxv":"│","boxV":"║","boxvh":"┼","boxvH":"╪","boxVh":"╫","boxVH":"╬","boxvl":"┤","boxvL":"╡","boxVl":"╢","boxVL":"╣","boxvr":"├","boxvR":"╞","boxVr":"╟","boxVR":"╠","bprime":"‵","breve":"˘","Breve":"˘","brvbar":"¦","bscr":"𝒷","Bscr":"ℬ","bsemi":"⁏","bsim":"∽","bsime":"⋍","bsolb":"⧅","bsol":"\\\\","bsolhsub":"⟈","bull":"•","bullet":"•","bump":"≎","bumpE":"⪮","bumpe":"≏","Bumpeq":"≎","bumpeq":"≏","Cacute":"Ć","cacute":"ć","capand":"⩄","capbrcup":"⩉","capcap":"⩋","cap":"∩","Cap":"⋒","capcup":"⩇","capdot":"⩀","CapitalDifferentialD":"ⅅ","caps":"∩︀","caret":"⁁","caron":"ˇ","Cayleys":"ℭ","ccaps":"⩍","Ccaron":"Č","ccaron":"č","Ccedil":"Ç","ccedil":"ç","Ccirc":"Ĉ","ccirc":"ĉ","Cconint":"∰","ccups":"⩌","ccupssm":"⩐","Cdot":"Ċ","cdot":"ċ","cedil":"¸","Cedilla":"¸","cemptyv":"⦲","cent":"¢","centerdot":"·","CenterDot":"·","cfr":"𝔠","Cfr":"ℭ","CHcy":"Ч","chcy":"ч","check":"✓","checkmark":"✓","Chi":"Χ","chi":"χ","circ":"ˆ","circeq":"≗","circlearrowleft":"↺","circlearrowright":"↻","circledast":"⊛","circledcirc":"⊚","circleddash":"⊝","CircleDot":"⊙","circledR":"®","circledS":"Ⓢ","CircleMinus":"⊖","CirclePlus":"⊕","CircleTimes":"⊗","cir":"○","cirE":"⧃","cire":"≗","cirfnint":"⨐","cirmid":"⫯","cirscir":"⧂","ClockwiseContourIntegral":"∲","CloseCurlyDoubleQuote":"”","CloseCurlyQuote":"’","clubs":"♣","clubsuit":"♣","colon":":","Colon":"∷","Colone":"⩴","colone":"≔","coloneq":"≔","comma":",","commat":"@","comp":"∁","compfn":"∘","complement":"∁","complexes":"ℂ","cong":"≅","congdot":"⩭","Congruent":"≡","conint":"∮","Conint":"∯","ContourIntegral":"∮","copf":"𝕔","Copf":"ℂ","coprod":"∐","Coproduct":"∐","copy":"©","COPY":"©","copysr":"℗","CounterClockwiseContourIntegral":"∳","crarr":"↵","cross":"✗","Cross":"⨯","Cscr":"𝒞","cscr":"𝒸","csub":"⫏","csube":"⫑","csup":"⫐","csupe":"⫒","ctdot":"⋯","cudarrl":"⤸","cudarrr":"⤵","cuepr":"⋞","cuesc":"⋟","cularr":"↶","cularrp":"⤽","cupbrcap":"⩈","cupcap":"⩆","CupCap":"≍","cup":"∪","Cup":"⋓","cupcup":"⩊","cupdot":"⊍","cupor":"⩅","cups":"∪︀","curarr":"↷","curarrm":"⤼","curlyeqprec":"⋞","curlyeqsucc":"⋟","curlyvee":"⋎","curlywedge":"⋏","curren":"¤","curvearrowleft":"↶","curvearrowright":"↷","cuvee":"⋎","cuwed":"⋏","cwconint":"∲","cwint":"∱","cylcty":"⌭","dagger":"†","Dagger":"‡","daleth":"ℸ","darr":"↓","Darr":"↡","dArr":"⇓","dash":"‐","Dashv":"⫤","dashv":"⊣","dbkarow":"⤏","dblac":"˝","Dcaron":"Ď","dcaron":"ď","Dcy":"Д","dcy":"д","ddagger":"‡","ddarr":"⇊","DD":"ⅅ","dd":"ⅆ","DDotrahd":"⤑","ddotseq":"⩷","deg":"°","Del":"∇","Delta":"Δ","delta":"δ","demptyv":"⦱","dfisht":"⥿","Dfr":"𝔇","dfr":"𝔡","dHar":"⥥","dharl":"⇃","dharr":"⇂","DiacriticalAcute":"´","DiacriticalDot":"˙","DiacriticalDoubleAcute":"˝","DiacriticalGrave":"`","DiacriticalTilde":"˜","diam":"⋄","diamond":"⋄","Diamond":"⋄","diamondsuit":"♦","diams":"♦","die":"¨","DifferentialD":"ⅆ","digamma":"ϝ","disin":"⋲","div":"÷","divide":"÷","divideontimes":"⋇","divonx":"⋇","DJcy":"Ђ","djcy":"ђ","dlcorn":"⌞","dlcrop":"⌍","dollar":"$","Dopf":"𝔻","dopf":"𝕕","Dot":"¨","dot":"˙","DotDot":"⃜","doteq":"≐","doteqdot":"≑","DotEqual":"≐","dotminus":"∸","dotplus":"∔","dotsquare":"⊡","doublebarwedge":"⌆","DoubleContourIntegral":"∯","DoubleDot":"¨","DoubleDownArrow":"⇓","DoubleLeftArrow":"⇐","DoubleLeftRightArrow":"⇔","DoubleLeftTee":"⫤","DoubleLongLeftArrow":"⟸","DoubleLongLeftRightArrow":"⟺","DoubleLongRightArrow":"⟹","DoubleRightArrow":"⇒","DoubleRightTee":"⊨","DoubleUpArrow":"⇑","DoubleUpDownArrow":"⇕","DoubleVerticalBar":"∥","DownArrowBar":"⤓","downarrow":"↓","DownArrow":"↓","Downarrow":"⇓","DownArrowUpArrow":"⇵","DownBreve":"̑","downdownarrows":"⇊","downharpoonleft":"⇃","downharpoonright":"⇂","DownLeftRightVector":"⥐","DownLeftTeeVector":"⥞","DownLeftVectorBar":"⥖","DownLeftVector":"↽","DownRightTeeVector":"⥟","DownRightVectorBar":"⥗","DownRightVector":"⇁","DownTeeArrow":"↧","DownTee":"⊤","drbkarow":"⤐","drcorn":"⌟","drcrop":"⌌","Dscr":"𝒟","dscr":"𝒹","DScy":"Ѕ","dscy":"ѕ","dsol":"⧶","Dstrok":"Đ","dstrok":"đ","dtdot":"⋱","dtri":"▿","dtrif":"▾","duarr":"⇵","duhar":"⥯","dwangle":"⦦","DZcy":"Џ","dzcy":"џ","dzigrarr":"⟿","Eacute":"É","eacute":"é","easter":"⩮","Ecaron":"Ě","ecaron":"ě","Ecirc":"Ê","ecirc":"ê","ecir":"≖","ecolon":"≕","Ecy":"Э","ecy":"э","eDDot":"⩷","Edot":"Ė","edot":"ė","eDot":"≑","ee":"ⅇ","efDot":"≒","Efr":"𝔈","efr":"𝔢","eg":"⪚","Egrave":"È","egrave":"è","egs":"⪖","egsdot":"⪘","el":"⪙","Element":"∈","elinters":"⏧","ell":"ℓ","els":"⪕","elsdot":"⪗","Emacr":"Ē","emacr":"ē","empty":"∅","emptyset":"∅","EmptySmallSquare":"◻","emptyv":"∅","EmptyVerySmallSquare":"▫","emsp13":" ","emsp14":" ","emsp":" ","ENG":"Ŋ","eng":"ŋ","ensp":" ","Eogon":"Ę","eogon":"ę","Eopf":"𝔼","eopf":"𝕖","epar":"⋕","eparsl":"⧣","eplus":"⩱","epsi":"ε","Epsilon":"Ε","epsilon":"ε","epsiv":"ϵ","eqcirc":"≖","eqcolon":"≕","eqsim":"≂","eqslantgtr":"⪖","eqslantless":"⪕","Equal":"⩵","equals":"=","EqualTilde":"≂","equest":"≟","Equilibrium":"⇌","equiv":"≡","equivDD":"⩸","eqvparsl":"⧥","erarr":"⥱","erDot":"≓","escr":"ℯ","Escr":"ℰ","esdot":"≐","Esim":"⩳","esim":"≂","Eta":"Η","eta":"η","ETH":"Ð","eth":"ð","Euml":"Ë","euml":"ë","euro":"€","excl":"!","exist":"∃","Exists":"∃","expectation":"ℰ","exponentiale":"ⅇ","ExponentialE":"ⅇ","fallingdotseq":"≒","Fcy":"Ф","fcy":"ф","female":"♀","ffilig":"ffi","fflig":"ff","ffllig":"ffl","Ffr":"𝔉","ffr":"𝔣","filig":"fi","FilledSmallSquare":"◼","FilledVerySmallSquare":"▪","fjlig":"fj","flat":"♭","fllig":"fl","fltns":"▱","fnof":"ƒ","Fopf":"𝔽","fopf":"𝕗","forall":"∀","ForAll":"∀","fork":"⋔","forkv":"⫙","Fouriertrf":"ℱ","fpartint":"⨍","frac12":"½","frac13":"⅓","frac14":"¼","frac15":"⅕","frac16":"⅙","frac18":"⅛","frac23":"⅔","frac25":"⅖","frac34":"¾","frac35":"⅗","frac38":"⅜","frac45":"⅘","frac56":"⅚","frac58":"⅝","frac78":"⅞","frasl":"⁄","frown":"⌢","fscr":"𝒻","Fscr":"ℱ","gacute":"ǵ","Gamma":"Γ","gamma":"γ","Gammad":"Ϝ","gammad":"ϝ","gap":"⪆","Gbreve":"Ğ","gbreve":"ğ","Gcedil":"Ģ","Gcirc":"Ĝ","gcirc":"ĝ","Gcy":"Г","gcy":"г","Gdot":"Ġ","gdot":"ġ","ge":"≥","gE":"≧","gEl":"⪌","gel":"⋛","geq":"≥","geqq":"≧","geqslant":"⩾","gescc":"⪩","ges":"⩾","gesdot":"⪀","gesdoto":"⪂","gesdotol":"⪄","gesl":"⋛︀","gesles":"⪔","Gfr":"𝔊","gfr":"𝔤","gg":"≫","Gg":"⋙","ggg":"⋙","gimel":"ℷ","GJcy":"Ѓ","gjcy":"ѓ","gla":"⪥","gl":"≷","glE":"⪒","glj":"⪤","gnap":"⪊","gnapprox":"⪊","gne":"⪈","gnE":"≩","gneq":"⪈","gneqq":"≩","gnsim":"⋧","Gopf":"𝔾","gopf":"𝕘","grave":"`","GreaterEqual":"≥","GreaterEqualLess":"⋛","GreaterFullEqual":"≧","GreaterGreater":"⪢","GreaterLess":"≷","GreaterSlantEqual":"⩾","GreaterTilde":"≳","Gscr":"𝒢","gscr":"ℊ","gsim":"≳","gsime":"⪎","gsiml":"⪐","gtcc":"⪧","gtcir":"⩺","gt":">","GT":">","Gt":"≫","gtdot":"⋗","gtlPar":"⦕","gtquest":"⩼","gtrapprox":"⪆","gtrarr":"⥸","gtrdot":"⋗","gtreqless":"⋛","gtreqqless":"⪌","gtrless":"≷","gtrsim":"≳","gvertneqq":"≩︀","gvnE":"≩︀","Hacek":"ˇ","hairsp":" ","half":"½","hamilt":"ℋ","HARDcy":"Ъ","hardcy":"ъ","harrcir":"⥈","harr":"↔","hArr":"⇔","harrw":"↭","Hat":"^","hbar":"ℏ","Hcirc":"Ĥ","hcirc":"ĥ","hearts":"♥","heartsuit":"♥","hellip":"…","hercon":"⊹","hfr":"𝔥","Hfr":"ℌ","HilbertSpace":"ℋ","hksearow":"⤥","hkswarow":"⤦","hoarr":"⇿","homtht":"∻","hookleftarrow":"↩","hookrightarrow":"↪","hopf":"𝕙","Hopf":"ℍ","horbar":"―","HorizontalLine":"─","hscr":"𝒽","Hscr":"ℋ","hslash":"ℏ","Hstrok":"Ħ","hstrok":"ħ","HumpDownHump":"≎","HumpEqual":"≏","hybull":"⁃","hyphen":"‐","Iacute":"Í","iacute":"í","ic":"⁣","Icirc":"Î","icirc":"î","Icy":"И","icy":"и","Idot":"İ","IEcy":"Е","iecy":"е","iexcl":"¡","iff":"⇔","ifr":"𝔦","Ifr":"ℑ","Igrave":"Ì","igrave":"ì","ii":"ⅈ","iiiint":"⨌","iiint":"∭","iinfin":"⧜","iiota":"℩","IJlig":"IJ","ijlig":"ij","Imacr":"Ī","imacr":"ī","image":"ℑ","ImaginaryI":"ⅈ","imagline":"ℐ","imagpart":"ℑ","imath":"ı","Im":"ℑ","imof":"⊷","imped":"Ƶ","Implies":"⇒","incare":"℅","in":"∈","infin":"∞","infintie":"⧝","inodot":"ı","intcal":"⊺","int":"∫","Int":"∬","integers":"ℤ","Integral":"∫","intercal":"⊺","Intersection":"⋂","intlarhk":"⨗","intprod":"⨼","InvisibleComma":"⁣","InvisibleTimes":"⁢","IOcy":"Ё","iocy":"ё","Iogon":"Į","iogon":"į","Iopf":"𝕀","iopf":"𝕚","Iota":"Ι","iota":"ι","iprod":"⨼","iquest":"¿","iscr":"𝒾","Iscr":"ℐ","isin":"∈","isindot":"⋵","isinE":"⋹","isins":"⋴","isinsv":"⋳","isinv":"∈","it":"⁢","Itilde":"Ĩ","itilde":"ĩ","Iukcy":"І","iukcy":"і","Iuml":"Ï","iuml":"ï","Jcirc":"Ĵ","jcirc":"ĵ","Jcy":"Й","jcy":"й","Jfr":"𝔍","jfr":"𝔧","jmath":"ȷ","Jopf":"𝕁","jopf":"𝕛","Jscr":"𝒥","jscr":"𝒿","Jsercy":"Ј","jsercy":"ј","Jukcy":"Є","jukcy":"є","Kappa":"Κ","kappa":"κ","kappav":"ϰ","Kcedil":"Ķ","kcedil":"ķ","Kcy":"К","kcy":"к","Kfr":"𝔎","kfr":"𝔨","kgreen":"ĸ","KHcy":"Х","khcy":"х","KJcy":"Ќ","kjcy":"ќ","Kopf":"𝕂","kopf":"𝕜","Kscr":"𝒦","kscr":"𝓀","lAarr":"⇚","Lacute":"Ĺ","lacute":"ĺ","laemptyv":"⦴","lagran":"ℒ","Lambda":"Λ","lambda":"λ","lang":"⟨","Lang":"⟪","langd":"⦑","langle":"⟨","lap":"⪅","Laplacetrf":"ℒ","laquo":"«","larrb":"⇤","larrbfs":"⤟","larr":"←","Larr":"↞","lArr":"⇐","larrfs":"⤝","larrhk":"↩","larrlp":"↫","larrpl":"⤹","larrsim":"⥳","larrtl":"↢","latail":"⤙","lAtail":"⤛","lat":"⪫","late":"⪭","lates":"⪭︀","lbarr":"⤌","lBarr":"⤎","lbbrk":"❲","lbrace":"{","lbrack":"[","lbrke":"⦋","lbrksld":"⦏","lbrkslu":"⦍","Lcaron":"Ľ","lcaron":"ľ","Lcedil":"Ļ","lcedil":"ļ","lceil":"⌈","lcub":"{","Lcy":"Л","lcy":"л","ldca":"⤶","ldquo":"“","ldquor":"„","ldrdhar":"⥧","ldrushar":"⥋","ldsh":"↲","le":"≤","lE":"≦","LeftAngleBracket":"⟨","LeftArrowBar":"⇤","leftarrow":"←","LeftArrow":"←","Leftarrow":"⇐","LeftArrowRightArrow":"⇆","leftarrowtail":"↢","LeftCeiling":"⌈","LeftDoubleBracket":"⟦","LeftDownTeeVector":"⥡","LeftDownVectorBar":"⥙","LeftDownVector":"⇃","LeftFloor":"⌊","leftharpoondown":"↽","leftharpoonup":"↼","leftleftarrows":"⇇","leftrightarrow":"↔","LeftRightArrow":"↔","Leftrightarrow":"⇔","leftrightarrows":"⇆","leftrightharpoons":"⇋","leftrightsquigarrow":"↭","LeftRightVector":"⥎","LeftTeeArrow":"↤","LeftTee":"⊣","LeftTeeVector":"⥚","leftthreetimes":"⋋","LeftTriangleBar":"⧏","LeftTriangle":"⊲","LeftTriangleEqual":"⊴","LeftUpDownVector":"⥑","LeftUpTeeVector":"⥠","LeftUpVectorBar":"⥘","LeftUpVector":"↿","LeftVectorBar":"⥒","LeftVector":"↼","lEg":"⪋","leg":"⋚","leq":"≤","leqq":"≦","leqslant":"⩽","lescc":"⪨","les":"⩽","lesdot":"⩿","lesdoto":"⪁","lesdotor":"⪃","lesg":"⋚︀","lesges":"⪓","lessapprox":"⪅","lessdot":"⋖","lesseqgtr":"⋚","lesseqqgtr":"⪋","LessEqualGreater":"⋚","LessFullEqual":"≦","LessGreater":"≶","lessgtr":"≶","LessLess":"⪡","lesssim":"≲","LessSlantEqual":"⩽","LessTilde":"≲","lfisht":"⥼","lfloor":"⌊","Lfr":"𝔏","lfr":"𝔩","lg":"≶","lgE":"⪑","lHar":"⥢","lhard":"↽","lharu":"↼","lharul":"⥪","lhblk":"▄","LJcy":"Љ","ljcy":"љ","llarr":"⇇","ll":"≪","Ll":"⋘","llcorner":"⌞","Lleftarrow":"⇚","llhard":"⥫","lltri":"◺","Lmidot":"Ŀ","lmidot":"ŀ","lmoustache":"⎰","lmoust":"⎰","lnap":"⪉","lnapprox":"⪉","lne":"⪇","lnE":"≨","lneq":"⪇","lneqq":"≨","lnsim":"⋦","loang":"⟬","loarr":"⇽","lobrk":"⟦","longleftarrow":"⟵","LongLeftArrow":"⟵","Longleftarrow":"⟸","longleftrightarrow":"⟷","LongLeftRightArrow":"⟷","Longleftrightarrow":"⟺","longmapsto":"⟼","longrightarrow":"⟶","LongRightArrow":"⟶","Longrightarrow":"⟹","looparrowleft":"↫","looparrowright":"↬","lopar":"⦅","Lopf":"𝕃","lopf":"𝕝","loplus":"⨭","lotimes":"⨴","lowast":"∗","lowbar":"_","LowerLeftArrow":"↙","LowerRightArrow":"↘","loz":"◊","lozenge":"◊","lozf":"⧫","lpar":"(","lparlt":"⦓","lrarr":"⇆","lrcorner":"⌟","lrhar":"⇋","lrhard":"⥭","lrm":"‎","lrtri":"⊿","lsaquo":"‹","lscr":"𝓁","Lscr":"ℒ","lsh":"↰","Lsh":"↰","lsim":"≲","lsime":"⪍","lsimg":"⪏","lsqb":"[","lsquo":"‘","lsquor":"‚","Lstrok":"Ł","lstrok":"ł","ltcc":"⪦","ltcir":"⩹","lt":"<","LT":"<","Lt":"≪","ltdot":"⋖","lthree":"⋋","ltimes":"⋉","ltlarr":"⥶","ltquest":"⩻","ltri":"◃","ltrie":"⊴","ltrif":"◂","ltrPar":"⦖","lurdshar":"⥊","luruhar":"⥦","lvertneqq":"≨︀","lvnE":"≨︀","macr":"¯","male":"♂","malt":"✠","maltese":"✠","Map":"⤅","map":"↦","mapsto":"↦","mapstodown":"↧","mapstoleft":"↤","mapstoup":"↥","marker":"▮","mcomma":"⨩","Mcy":"М","mcy":"м","mdash":"—","mDDot":"∺","measuredangle":"∡","MediumSpace":" ","Mellintrf":"ℳ","Mfr":"𝔐","mfr":"𝔪","mho":"℧","micro":"µ","midast":"*","midcir":"⫰","mid":"∣","middot":"·","minusb":"⊟","minus":"−","minusd":"∸","minusdu":"⨪","MinusPlus":"∓","mlcp":"⫛","mldr":"…","mnplus":"∓","models":"⊧","Mopf":"𝕄","mopf":"𝕞","mp":"∓","mscr":"𝓂","Mscr":"ℳ","mstpos":"∾","Mu":"Μ","mu":"μ","multimap":"⊸","mumap":"⊸","nabla":"∇","Nacute":"Ń","nacute":"ń","nang":"∠⃒","nap":"≉","napE":"⩰̸","napid":"≋̸","napos":"ʼn","napprox":"≉","natural":"♮","naturals":"ℕ","natur":"♮","nbsp":" ","nbump":"≎̸","nbumpe":"≏̸","ncap":"⩃","Ncaron":"Ň","ncaron":"ň","Ncedil":"Ņ","ncedil":"ņ","ncong":"≇","ncongdot":"⩭̸","ncup":"⩂","Ncy":"Н","ncy":"н","ndash":"–","nearhk":"⤤","nearr":"↗","neArr":"⇗","nearrow":"↗","ne":"≠","nedot":"≐̸","NegativeMediumSpace":"​","NegativeThickSpace":"​","NegativeThinSpace":"​","NegativeVeryThinSpace":"​","nequiv":"≢","nesear":"⤨","nesim":"≂̸","NestedGreaterGreater":"≫","NestedLessLess":"≪","NewLine":"\\n","nexist":"∄","nexists":"∄","Nfr":"𝔑","nfr":"𝔫","ngE":"≧̸","nge":"≱","ngeq":"≱","ngeqq":"≧̸","ngeqslant":"⩾̸","nges":"⩾̸","nGg":"⋙̸","ngsim":"≵","nGt":"≫⃒","ngt":"≯","ngtr":"≯","nGtv":"≫̸","nharr":"↮","nhArr":"⇎","nhpar":"⫲","ni":"∋","nis":"⋼","nisd":"⋺","niv":"∋","NJcy":"Њ","njcy":"њ","nlarr":"↚","nlArr":"⇍","nldr":"‥","nlE":"≦̸","nle":"≰","nleftarrow":"↚","nLeftarrow":"⇍","nleftrightarrow":"↮","nLeftrightarrow":"⇎","nleq":"≰","nleqq":"≦̸","nleqslant":"⩽̸","nles":"⩽̸","nless":"≮","nLl":"⋘̸","nlsim":"≴","nLt":"≪⃒","nlt":"≮","nltri":"⋪","nltrie":"⋬","nLtv":"≪̸","nmid":"∤","NoBreak":"⁠","NonBreakingSpace":" ","nopf":"𝕟","Nopf":"ℕ","Not":"⫬","not":"¬","NotCongruent":"≢","NotCupCap":"≭","NotDoubleVerticalBar":"∦","NotElement":"∉","NotEqual":"≠","NotEqualTilde":"≂̸","NotExists":"∄","NotGreater":"≯","NotGreaterEqual":"≱","NotGreaterFullEqual":"≧̸","NotGreaterGreater":"≫̸","NotGreaterLess":"≹","NotGreaterSlantEqual":"⩾̸","NotGreaterTilde":"≵","NotHumpDownHump":"≎̸","NotHumpEqual":"≏̸","notin":"∉","notindot":"⋵̸","notinE":"⋹̸","notinva":"∉","notinvb":"⋷","notinvc":"⋶","NotLeftTriangleBar":"⧏̸","NotLeftTriangle":"⋪","NotLeftTriangleEqual":"⋬","NotLess":"≮","NotLessEqual":"≰","NotLessGreater":"≸","NotLessLess":"≪̸","NotLessSlantEqual":"⩽̸","NotLessTilde":"≴","NotNestedGreaterGreater":"⪢̸","NotNestedLessLess":"⪡̸","notni":"∌","notniva":"∌","notnivb":"⋾","notnivc":"⋽","NotPrecedes":"⊀","NotPrecedesEqual":"⪯̸","NotPrecedesSlantEqual":"⋠","NotReverseElement":"∌","NotRightTriangleBar":"⧐̸","NotRightTriangle":"⋫","NotRightTriangleEqual":"⋭","NotSquareSubset":"⊏̸","NotSquareSubsetEqual":"⋢","NotSquareSuperset":"⊐̸","NotSquareSupersetEqual":"⋣","NotSubset":"⊂⃒","NotSubsetEqual":"⊈","NotSucceeds":"⊁","NotSucceedsEqual":"⪰̸","NotSucceedsSlantEqual":"⋡","NotSucceedsTilde":"≿̸","NotSuperset":"⊃⃒","NotSupersetEqual":"⊉","NotTilde":"≁","NotTildeEqual":"≄","NotTildeFullEqual":"≇","NotTildeTilde":"≉","NotVerticalBar":"∤","nparallel":"∦","npar":"∦","nparsl":"⫽⃥","npart":"∂̸","npolint":"⨔","npr":"⊀","nprcue":"⋠","nprec":"⊀","npreceq":"⪯̸","npre":"⪯̸","nrarrc":"⤳̸","nrarr":"↛","nrArr":"⇏","nrarrw":"↝̸","nrightarrow":"↛","nRightarrow":"⇏","nrtri":"⋫","nrtrie":"⋭","nsc":"⊁","nsccue":"⋡","nsce":"⪰̸","Nscr":"𝒩","nscr":"𝓃","nshortmid":"∤","nshortparallel":"∦","nsim":"≁","nsime":"≄","nsimeq":"≄","nsmid":"∤","nspar":"∦","nsqsube":"⋢","nsqsupe":"⋣","nsub":"⊄","nsubE":"⫅̸","nsube":"⊈","nsubset":"⊂⃒","nsubseteq":"⊈","nsubseteqq":"⫅̸","nsucc":"⊁","nsucceq":"⪰̸","nsup":"⊅","nsupE":"⫆̸","nsupe":"⊉","nsupset":"⊃⃒","nsupseteq":"⊉","nsupseteqq":"⫆̸","ntgl":"≹","Ntilde":"Ñ","ntilde":"ñ","ntlg":"≸","ntriangleleft":"⋪","ntrianglelefteq":"⋬","ntriangleright":"⋫","ntrianglerighteq":"⋭","Nu":"Ν","nu":"ν","num":"#","numero":"№","numsp":" ","nvap":"≍⃒","nvdash":"⊬","nvDash":"⊭","nVdash":"⊮","nVDash":"⊯","nvge":"≥⃒","nvgt":">⃒","nvHarr":"⤄","nvinfin":"⧞","nvlArr":"⤂","nvle":"≤⃒","nvlt":"<⃒","nvltrie":"⊴⃒","nvrArr":"⤃","nvrtrie":"⊵⃒","nvsim":"∼⃒","nwarhk":"⤣","nwarr":"↖","nwArr":"⇖","nwarrow":"↖","nwnear":"⤧","Oacute":"Ó","oacute":"ó","oast":"⊛","Ocirc":"Ô","ocirc":"ô","ocir":"⊚","Ocy":"О","ocy":"о","odash":"⊝","Odblac":"Ő","odblac":"ő","odiv":"⨸","odot":"⊙","odsold":"⦼","OElig":"Œ","oelig":"œ","ofcir":"⦿","Ofr":"𝔒","ofr":"𝔬","ogon":"˛","Ograve":"Ò","ograve":"ò","ogt":"⧁","ohbar":"⦵","ohm":"Ω","oint":"∮","olarr":"↺","olcir":"⦾","olcross":"⦻","oline":"‾","olt":"⧀","Omacr":"Ō","omacr":"ō","Omega":"Ω","omega":"ω","Omicron":"Ο","omicron":"ο","omid":"⦶","ominus":"⊖","Oopf":"𝕆","oopf":"𝕠","opar":"⦷","OpenCurlyDoubleQuote":"“","OpenCurlyQuote":"‘","operp":"⦹","oplus":"⊕","orarr":"↻","Or":"⩔","or":"∨","ord":"⩝","order":"ℴ","orderof":"ℴ","ordf":"ª","ordm":"º","origof":"⊶","oror":"⩖","orslope":"⩗","orv":"⩛","oS":"Ⓢ","Oscr":"𝒪","oscr":"ℴ","Oslash":"Ø","oslash":"ø","osol":"⊘","Otilde":"Õ","otilde":"õ","otimesas":"⨶","Otimes":"⨷","otimes":"⊗","Ouml":"Ö","ouml":"ö","ovbar":"⌽","OverBar":"‾","OverBrace":"⏞","OverBracket":"⎴","OverParenthesis":"⏜","para":"¶","parallel":"∥","par":"∥","parsim":"⫳","parsl":"⫽","part":"∂","PartialD":"∂","Pcy":"П","pcy":"п","percnt":"%","period":".","permil":"‰","perp":"⊥","pertenk":"‱","Pfr":"𝔓","pfr":"𝔭","Phi":"Φ","phi":"φ","phiv":"ϕ","phmmat":"ℳ","phone":"☎","Pi":"Π","pi":"π","pitchfork":"⋔","piv":"ϖ","planck":"ℏ","planckh":"ℎ","plankv":"ℏ","plusacir":"⨣","plusb":"⊞","pluscir":"⨢","plus":"+","plusdo":"∔","plusdu":"⨥","pluse":"⩲","PlusMinus":"±","plusmn":"±","plussim":"⨦","plustwo":"⨧","pm":"±","Poincareplane":"ℌ","pointint":"⨕","popf":"𝕡","Popf":"ℙ","pound":"£","prap":"⪷","Pr":"⪻","pr":"≺","prcue":"≼","precapprox":"⪷","prec":"≺","preccurlyeq":"≼","Precedes":"≺","PrecedesEqual":"⪯","PrecedesSlantEqual":"≼","PrecedesTilde":"≾","preceq":"⪯","precnapprox":"⪹","precneqq":"⪵","precnsim":"⋨","pre":"⪯","prE":"⪳","precsim":"≾","prime":"′","Prime":"″","primes":"ℙ","prnap":"⪹","prnE":"⪵","prnsim":"⋨","prod":"∏","Product":"∏","profalar":"⌮","profline":"⌒","profsurf":"⌓","prop":"∝","Proportional":"∝","Proportion":"∷","propto":"∝","prsim":"≾","prurel":"⊰","Pscr":"𝒫","pscr":"𝓅","Psi":"Ψ","psi":"ψ","puncsp":" ","Qfr":"𝔔","qfr":"𝔮","qint":"⨌","qopf":"𝕢","Qopf":"ℚ","qprime":"⁗","Qscr":"𝒬","qscr":"𝓆","quaternions":"ℍ","quatint":"⨖","quest":"?","questeq":"≟","quot":"\\"","QUOT":"\\"","rAarr":"⇛","race":"∽̱","Racute":"Ŕ","racute":"ŕ","radic":"√","raemptyv":"⦳","rang":"⟩","Rang":"⟫","rangd":"⦒","range":"⦥","rangle":"⟩","raquo":"»","rarrap":"⥵","rarrb":"⇥","rarrbfs":"⤠","rarrc":"⤳","rarr":"→","Rarr":"↠","rArr":"⇒","rarrfs":"⤞","rarrhk":"↪","rarrlp":"↬","rarrpl":"⥅","rarrsim":"⥴","Rarrtl":"⤖","rarrtl":"↣","rarrw":"↝","ratail":"⤚","rAtail":"⤜","ratio":"∶","rationals":"ℚ","rbarr":"⤍","rBarr":"⤏","RBarr":"⤐","rbbrk":"❳","rbrace":"}","rbrack":"]","rbrke":"⦌","rbrksld":"⦎","rbrkslu":"⦐","Rcaron":"Ř","rcaron":"ř","Rcedil":"Ŗ","rcedil":"ŗ","rceil":"⌉","rcub":"}","Rcy":"Р","rcy":"р","rdca":"⤷","rdldhar":"⥩","rdquo":"”","rdquor":"”","rdsh":"↳","real":"ℜ","realine":"ℛ","realpart":"ℜ","reals":"ℝ","Re":"ℜ","rect":"▭","reg":"®","REG":"®","ReverseElement":"∋","ReverseEquilibrium":"⇋","ReverseUpEquilibrium":"⥯","rfisht":"⥽","rfloor":"⌋","rfr":"𝔯","Rfr":"ℜ","rHar":"⥤","rhard":"⇁","rharu":"⇀","rharul":"⥬","Rho":"Ρ","rho":"ρ","rhov":"ϱ","RightAngleBracket":"⟩","RightArrowBar":"⇥","rightarrow":"→","RightArrow":"→","Rightarrow":"⇒","RightArrowLeftArrow":"⇄","rightarrowtail":"↣","RightCeiling":"⌉","RightDoubleBracket":"⟧","RightDownTeeVector":"⥝","RightDownVectorBar":"⥕","RightDownVector":"⇂","RightFloor":"⌋","rightharpoondown":"⇁","rightharpoonup":"⇀","rightleftarrows":"⇄","rightleftharpoons":"⇌","rightrightarrows":"⇉","rightsquigarrow":"↝","RightTeeArrow":"↦","RightTee":"⊢","RightTeeVector":"⥛","rightthreetimes":"⋌","RightTriangleBar":"⧐","RightTriangle":"⊳","RightTriangleEqual":"⊵","RightUpDownVector":"⥏","RightUpTeeVector":"⥜","RightUpVectorBar":"⥔","RightUpVector":"↾","RightVectorBar":"⥓","RightVector":"⇀","ring":"˚","risingdotseq":"≓","rlarr":"⇄","rlhar":"⇌","rlm":"‏","rmoustache":"⎱","rmoust":"⎱","rnmid":"⫮","roang":"⟭","roarr":"⇾","robrk":"⟧","ropar":"⦆","ropf":"𝕣","Ropf":"ℝ","roplus":"⨮","rotimes":"⨵","RoundImplies":"⥰","rpar":")","rpargt":"⦔","rppolint":"⨒","rrarr":"⇉","Rrightarrow":"⇛","rsaquo":"›","rscr":"𝓇","Rscr":"ℛ","rsh":"↱","Rsh":"↱","rsqb":"]","rsquo":"’","rsquor":"’","rthree":"⋌","rtimes":"⋊","rtri":"▹","rtrie":"⊵","rtrif":"▸","rtriltri":"⧎","RuleDelayed":"⧴","ruluhar":"⥨","rx":"℞","Sacute":"Ś","sacute":"ś","sbquo":"‚","scap":"⪸","Scaron":"Š","scaron":"š","Sc":"⪼","sc":"≻","sccue":"≽","sce":"⪰","scE":"⪴","Scedil":"Ş","scedil":"ş","Scirc":"Ŝ","scirc":"ŝ","scnap":"⪺","scnE":"⪶","scnsim":"⋩","scpolint":"⨓","scsim":"≿","Scy":"С","scy":"с","sdotb":"⊡","sdot":"⋅","sdote":"⩦","searhk":"⤥","searr":"↘","seArr":"⇘","searrow":"↘","sect":"§","semi":";","seswar":"⤩","setminus":"∖","setmn":"∖","sext":"✶","Sfr":"𝔖","sfr":"𝔰","sfrown":"⌢","sharp":"♯","SHCHcy":"Щ","shchcy":"щ","SHcy":"Ш","shcy":"ш","ShortDownArrow":"↓","ShortLeftArrow":"←","shortmid":"∣","shortparallel":"∥","ShortRightArrow":"→","ShortUpArrow":"↑","shy":"­","Sigma":"Σ","sigma":"σ","sigmaf":"ς","sigmav":"ς","sim":"∼","simdot":"⩪","sime":"≃","simeq":"≃","simg":"⪞","simgE":"⪠","siml":"⪝","simlE":"⪟","simne":"≆","simplus":"⨤","simrarr":"⥲","slarr":"←","SmallCircle":"∘","smallsetminus":"∖","smashp":"⨳","smeparsl":"⧤","smid":"∣","smile":"⌣","smt":"⪪","smte":"⪬","smtes":"⪬︀","SOFTcy":"Ь","softcy":"ь","solbar":"⌿","solb":"⧄","sol":"/","Sopf":"𝕊","sopf":"𝕤","spades":"♠","spadesuit":"♠","spar":"∥","sqcap":"⊓","sqcaps":"⊓︀","sqcup":"⊔","sqcups":"⊔︀","Sqrt":"√","sqsub":"⊏","sqsube":"⊑","sqsubset":"⊏","sqsubseteq":"⊑","sqsup":"⊐","sqsupe":"⊒","sqsupset":"⊐","sqsupseteq":"⊒","square":"□","Square":"□","SquareIntersection":"⊓","SquareSubset":"⊏","SquareSubsetEqual":"⊑","SquareSuperset":"⊐","SquareSupersetEqual":"⊒","SquareUnion":"⊔","squarf":"▪","squ":"□","squf":"▪","srarr":"→","Sscr":"𝒮","sscr":"𝓈","ssetmn":"∖","ssmile":"⌣","sstarf":"⋆","Star":"⋆","star":"☆","starf":"★","straightepsilon":"ϵ","straightphi":"ϕ","strns":"¯","sub":"⊂","Sub":"⋐","subdot":"⪽","subE":"⫅","sube":"⊆","subedot":"⫃","submult":"⫁","subnE":"⫋","subne":"⊊","subplus":"⪿","subrarr":"⥹","subset":"⊂","Subset":"⋐","subseteq":"⊆","subseteqq":"⫅","SubsetEqual":"⊆","subsetneq":"⊊","subsetneqq":"⫋","subsim":"⫇","subsub":"⫕","subsup":"⫓","succapprox":"⪸","succ":"≻","succcurlyeq":"≽","Succeeds":"≻","SucceedsEqual":"⪰","SucceedsSlantEqual":"≽","SucceedsTilde":"≿","succeq":"⪰","succnapprox":"⪺","succneqq":"⪶","succnsim":"⋩","succsim":"≿","SuchThat":"∋","sum":"∑","Sum":"∑","sung":"♪","sup1":"¹","sup2":"²","sup3":"³","sup":"⊃","Sup":"⋑","supdot":"⪾","supdsub":"⫘","supE":"⫆","supe":"⊇","supedot":"⫄","Superset":"⊃","SupersetEqual":"⊇","suphsol":"⟉","suphsub":"⫗","suplarr":"⥻","supmult":"⫂","supnE":"⫌","supne":"⊋","supplus":"⫀","supset":"⊃","Supset":"⋑","supseteq":"⊇","supseteqq":"⫆","supsetneq":"⊋","supsetneqq":"⫌","supsim":"⫈","supsub":"⫔","supsup":"⫖","swarhk":"⤦","swarr":"↙","swArr":"⇙","swarrow":"↙","swnwar":"⤪","szlig":"ß","Tab":"\\t","target":"⌖","Tau":"Τ","tau":"τ","tbrk":"⎴","Tcaron":"Ť","tcaron":"ť","Tcedil":"Ţ","tcedil":"ţ","Tcy":"Т","tcy":"т","tdot":"⃛","telrec":"⌕","Tfr":"𝔗","tfr":"𝔱","there4":"∴","therefore":"∴","Therefore":"∴","Theta":"Θ","theta":"θ","thetasym":"ϑ","thetav":"ϑ","thickapprox":"≈","thicksim":"∼","ThickSpace":"  ","ThinSpace":" ","thinsp":" ","thkap":"≈","thksim":"∼","THORN":"Þ","thorn":"þ","tilde":"˜","Tilde":"∼","TildeEqual":"≃","TildeFullEqual":"≅","TildeTilde":"≈","timesbar":"⨱","timesb":"⊠","times":"×","timesd":"⨰","tint":"∭","toea":"⤨","topbot":"⌶","topcir":"⫱","top":"⊤","Topf":"𝕋","topf":"𝕥","topfork":"⫚","tosa":"⤩","tprime":"‴","trade":"™","TRADE":"™","triangle":"▵","triangledown":"▿","triangleleft":"◃","trianglelefteq":"⊴","triangleq":"≜","triangleright":"▹","trianglerighteq":"⊵","tridot":"◬","trie":"≜","triminus":"⨺","TripleDot":"⃛","triplus":"⨹","trisb":"⧍","tritime":"⨻","trpezium":"⏢","Tscr":"𝒯","tscr":"𝓉","TScy":"Ц","tscy":"ц","TSHcy":"Ћ","tshcy":"ћ","Tstrok":"Ŧ","tstrok":"ŧ","twixt":"≬","twoheadleftarrow":"↞","twoheadrightarrow":"↠","Uacute":"Ú","uacute":"ú","uarr":"↑","Uarr":"↟","uArr":"⇑","Uarrocir":"⥉","Ubrcy":"Ў","ubrcy":"ў","Ubreve":"Ŭ","ubreve":"ŭ","Ucirc":"Û","ucirc":"û","Ucy":"У","ucy":"у","udarr":"⇅","Udblac":"Ű","udblac":"ű","udhar":"⥮","ufisht":"⥾","Ufr":"𝔘","ufr":"𝔲","Ugrave":"Ù","ugrave":"ù","uHar":"⥣","uharl":"↿","uharr":"↾","uhblk":"▀","ulcorn":"⌜","ulcorner":"⌜","ulcrop":"⌏","ultri":"◸","Umacr":"Ū","umacr":"ū","uml":"¨","UnderBar":"_","UnderBrace":"⏟","UnderBracket":"⎵","UnderParenthesis":"⏝","Union":"⋃","UnionPlus":"⊎","Uogon":"Ų","uogon":"ų","Uopf":"𝕌","uopf":"𝕦","UpArrowBar":"⤒","uparrow":"↑","UpArrow":"↑","Uparrow":"⇑","UpArrowDownArrow":"⇅","updownarrow":"↕","UpDownArrow":"↕","Updownarrow":"⇕","UpEquilibrium":"⥮","upharpoonleft":"↿","upharpoonright":"↾","uplus":"⊎","UpperLeftArrow":"↖","UpperRightArrow":"↗","upsi":"υ","Upsi":"ϒ","upsih":"ϒ","Upsilon":"Υ","upsilon":"υ","UpTeeArrow":"↥","UpTee":"⊥","upuparrows":"⇈","urcorn":"⌝","urcorner":"⌝","urcrop":"⌎","Uring":"Ů","uring":"ů","urtri":"◹","Uscr":"𝒰","uscr":"𝓊","utdot":"⋰","Utilde":"Ũ","utilde":"ũ","utri":"▵","utrif":"▴","uuarr":"⇈","Uuml":"Ü","uuml":"ü","uwangle":"⦧","vangrt":"⦜","varepsilon":"ϵ","varkappa":"ϰ","varnothing":"∅","varphi":"ϕ","varpi":"ϖ","varpropto":"∝","varr":"↕","vArr":"⇕","varrho":"ϱ","varsigma":"ς","varsubsetneq":"⊊︀","varsubsetneqq":"⫋︀","varsupsetneq":"⊋︀","varsupsetneqq":"⫌︀","vartheta":"ϑ","vartriangleleft":"⊲","vartriangleright":"⊳","vBar":"⫨","Vbar":"⫫","vBarv":"⫩","Vcy":"В","vcy":"в","vdash":"⊢","vDash":"⊨","Vdash":"⊩","VDash":"⊫","Vdashl":"⫦","veebar":"⊻","vee":"∨","Vee":"⋁","veeeq":"≚","vellip":"⋮","verbar":"|","Verbar":"‖","vert":"|","Vert":"‖","VerticalBar":"∣","VerticalLine":"|","VerticalSeparator":"❘","VerticalTilde":"≀","VeryThinSpace":" ","Vfr":"𝔙","vfr":"𝔳","vltri":"⊲","vnsub":"⊂⃒","vnsup":"⊃⃒","Vopf":"𝕍","vopf":"𝕧","vprop":"∝","vrtri":"⊳","Vscr":"𝒱","vscr":"𝓋","vsubnE":"⫋︀","vsubne":"⊊︀","vsupnE":"⫌︀","vsupne":"⊋︀","Vvdash":"⊪","vzigzag":"⦚","Wcirc":"Ŵ","wcirc":"ŵ","wedbar":"⩟","wedge":"∧","Wedge":"⋀","wedgeq":"≙","weierp":"℘","Wfr":"𝔚","wfr":"𝔴","Wopf":"𝕎","wopf":"𝕨","wp":"℘","wr":"≀","wreath":"≀","Wscr":"𝒲","wscr":"𝓌","xcap":"⋂","xcirc":"◯","xcup":"⋃","xdtri":"▽","Xfr":"𝔛","xfr":"𝔵","xharr":"⟷","xhArr":"⟺","Xi":"Ξ","xi":"ξ","xlarr":"⟵","xlArr":"⟸","xmap":"⟼","xnis":"⋻","xodot":"⨀","Xopf":"𝕏","xopf":"𝕩","xoplus":"⨁","xotime":"⨂","xrarr":"⟶","xrArr":"⟹","Xscr":"𝒳","xscr":"𝓍","xsqcup":"⨆","xuplus":"⨄","xutri":"△","xvee":"⋁","xwedge":"⋀","Yacute":"Ý","yacute":"ý","YAcy":"Я","yacy":"я","Ycirc":"Ŷ","ycirc":"ŷ","Ycy":"Ы","ycy":"ы","yen":"¥","Yfr":"𝔜","yfr":"𝔶","YIcy":"Ї","yicy":"ї","Yopf":"𝕐","yopf":"𝕪","Yscr":"𝒴","yscr":"𝓎","YUcy":"Ю","yucy":"ю","yuml":"ÿ","Yuml":"Ÿ","Zacute":"Ź","zacute":"ź","Zcaron":"Ž","zcaron":"ž","Zcy":"З","zcy":"з","Zdot":"Ż","zdot":"ż","zeetrf":"ℨ","ZeroWidthSpace":"​","Zeta":"Ζ","zeta":"ζ","zfr":"𝔷","Zfr":"ℨ","ZHcy":"Ж","zhcy":"ж","zigrarr":"⇝","zopf":"𝕫","Zopf":"ℤ","Zscr":"𝒵","zscr":"𝓏","zwj":"‍","zwnj":"‌"}')},function(e,t,r){"use strict";var n={};function s(e,t,r){var o,i,a,u,c,l="";for("string"!=typeof t&&(r=t,t=s.defaultChars),void 0===r&&(r=!0),c=function(e){var t,r,s=n[e];if(s)return s;for(s=n[e]=[],t=0;t<128;t++)r=String.fromCharCode(t),/^[0-9a-z]$/i.test(r)?s.push(r):s.push("%"+("0"+t.toString(16).toUpperCase()).slice(-2));for(t=0;t=55296&&a<=57343){if(a>=55296&&a<=56319&&o+1=56320&&u<=57343){l+=encodeURIComponent(e[o]+e[o+1]),o++;continue}l+="%EF%BF%BD"}else l+=encodeURIComponent(e[o]);return l}s.defaultChars=";/?:@&=+$,-_.!~*'()#",s.componentChars="-_.!~*'()",e.exports=s},function(e,t,r){"use strict";var n={};function s(e,t){var r;return"string"!=typeof t&&(t=s.defaultChars),r=function(e){var t,r,s=n[e];if(s)return s;for(s=n[e]=[],t=0;t<128;t++)r=String.fromCharCode(t),s.push(r);for(t=0;t=55296&&u<=57343?"���":String.fromCharCode(u),t+=6):240==(248&s)&&t+91114111?c+="����":(u-=65536,c+=String.fromCharCode(55296+(u>>10),56320+(1023&u))),t+=9):c+="�";return c}))}s.defaultChars=";/?:@&=+$,#",s.componentChars="",e.exports=s},function(e,t,r){"use strict";e.exports=function(e){var t="";return t+=e.protocol||"",t+=e.slashes?"//":"",t+=e.auth?e.auth+"@":"",e.hostname&&-1!==e.hostname.indexOf(":")?t+="["+e.hostname+"]":t+=e.hostname||"",t+=e.port?":"+e.port:"",t+=e.pathname||"",t+=e.search||"",t+=e.hash||""}},function(e,t,r){"use strict";function n(){this.protocol=null,this.slashes=null,this.auth=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.pathname=null}var s=/^([a-z0-9.+-]+:)/i,o=/:[0-9]*$/,i=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,a=["{","}","|","\\","^","`"].concat(["<",">",'"',"`"," ","\r","\n","\t"]),u=["'"].concat(a),c=["%","/","?",";","#"].concat(u),l=["/","?","#"],p=/^[+a-z0-9A-Z_-]{0,63}$/,h=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,f={javascript:!0,"javascript:":!0},d={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0};n.prototype.parse=function(e,t){var r,n,o,a,u,m=e;if(m=m.trim(),!t&&1===e.split("#").length){var g=i.exec(m);if(g)return this.pathname=g[1],g[2]&&(this.search=g[2]),this}var _=s.exec(m);if(_&&(o=(_=_[0]).toLowerCase(),this.protocol=_,m=m.substr(_.length)),(t||_||m.match(/^\/\/[^@\/]+@[^@\/]+/))&&(!(u="//"===m.substr(0,2))||_&&f[_]||(m=m.substr(2),this.slashes=!0)),!f[_]&&(u||_&&!d[_])){var b,k,C=-1;for(r=0;r127?x+="x":x+=y[F];if(!x.match(p)){var w=A.slice(0,r),q=A.slice(r+1),S=y.match(h);S&&(w.push(S[1]),q.unshift(S[2])),q.length&&(m=q.join(".")+m),this.hostname=w.join(".");break}}}}this.hostname.length>255&&(this.hostname=""),D&&(this.hostname=this.hostname.substr(1,this.hostname.length-2))}var L=m.indexOf("#");-1!==L&&(this.hash=m.substr(L),m=m.slice(0,L));var z=m.indexOf("?");return-1!==z&&(this.search=m.substr(z),m=m.slice(0,z)),m&&(this.pathname=m),d[o]&&this.hostname&&!this.pathname&&(this.pathname=""),this},n.prototype.parseHost=function(e){var t=o.exec(e);t&&(":"!==(t=t[0])&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)},e.exports=function(e,t){if(e&&e instanceof n)return e;var r=new n;return r.parse(e,t),r}},function(e,t,r){"use strict";t.Any=r(18),t.Cc=r(19),t.Cf=r(20),t.P=r(4),t.Z=r(21)},function(e,t){e.exports=/[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/},function(e,t){e.exports=/[\0-\x1F\x7F-\x9F]/},function(e,t){e.exports=/[\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804\uDCBD|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/},function(e,t){e.exports=/[ \xA0\u1680\u2000-\u200A\u202F\u205F\u3000]/},function(e,t,r){"use strict";t.parseLinkLabel=r(23),t.parseLinkDestination=r(24),t.parseLinkTitle=r(25)},function(e,t,r){"use strict";e.exports=function(e,t,r){var n,s,o,i,a=-1,u=e.posMax,c=e.pos;for(e.pos=t+1,n=1;e.pos32)return a;if(41===s){if(0===o)break;o--}t++}return i===t||0!==o||(a.str=n(e.slice(i,t)),a.lines=0,a.pos=t,a.ok=!0),a}},function(e,t,r){"use strict";var n=r(0).unescapeAll;e.exports=function(e,t,r){var s,o,i=0,a=t,u={ok:!1,pos:0,lines:0,str:""};if(t>=r)return u;if(34!==(o=e.charCodeAt(t))&&39!==o&&40!==o)return u;for(t++,40===o&&(o=41);t"+o(e[t].content)+""},i.code_block=function(e,t,r,n,s){var i=e[t];return""+o(e[t].content)+"\n"},i.fence=function(e,t,r,n,i){var a,u,c,l,p,h=e[t],f=h.info?s(h.info).trim():"",d="",m="";return f&&(d=(c=f.split(/(\s+)/g))[0],m=c.slice(2).join("")),0===(a=r.highlight&&r.highlight(h.content,d,m)||o(h.content)).indexOf(""+a+"\n"):"
"+a+"
\n"},i.image=function(e,t,r,n,s){var o=e[t];return o.attrs[o.attrIndex("alt")][1]=s.renderInlineAsText(o.children,r,n),s.renderToken(e,t,r)},i.hardbreak=function(e,t,r){return r.xhtmlOut?"
\n":"
\n"},i.softbreak=function(e,t,r){return r.breaks?r.xhtmlOut?"
\n":"
\n":"\n"},i.text=function(e,t){return o(e[t].content)},i.html_block=function(e,t){return e[t].content},i.html_inline=function(e,t){return e[t].content},a.prototype.renderAttrs=function(e){var t,r,n;if(!e.attrs)return"";for(n="",t=0,r=e.attrs.length;t\n":">")},a.prototype.renderInline=function(e,t,r){for(var n,s="",o=this.rules,i=0,a=e.length;i/i.test(e)}e.exports=function(e){var t,r,o,i,a,u,c,l,p,h,f,d,m,g,_,b,k,C,v=e.tokens;if(e.md.options.linkify)for(r=0,o=v.length;r=0;t--)if("link_close"!==(u=i[t]).type){if("html_inline"===u.type&&(C=u.content,/^\s]/i.test(C)&&m>0&&m--,s(u.content)&&m++),!(m>0)&&"text"===u.type&&e.md.linkify.test(u.content)){for(p=u.content,k=e.md.linkify.match(p),c=[],d=u.level,f=0,l=0;lf&&((a=new e.Token("text","",0)).content=p.slice(f,h),a.level=d,c.push(a)),(a=new e.Token("link_open","a",1)).attrs=[["href",_]],a.level=d++,a.markup="linkify",a.info="auto",c.push(a),(a=new e.Token("text","",0)).content=b,a.level=d,c.push(a),(a=new e.Token("link_close","a",-1)).level=--d,a.markup="linkify",a.info="auto",c.push(a),f=k[l].lastIndex);f=0;t--)"text"!==(r=e[t]).type||n||(r.content=r.content.replace(o,a)),"link_open"===r.type&&"auto"===r.info&&n--,"link_close"===r.type&&"auto"===r.info&&n++}function c(e){var t,r,s=0;for(t=e.length-1;t>=0;t--)"text"!==(r=e[t]).type||s||n.test(r.content)&&(r.content=r.content.replace(/\+-/g,"±").replace(/\.{2,}/g,"…").replace(/([?!])…/g,"$1..").replace(/([?!]){4,}/g,"$1$1$1").replace(/,{2,}/g,",").replace(/(^|[^-])---(?=[^-]|$)/gm,"$1—").replace(/(^|\s)--(?=\s|$)/gm,"$1–").replace(/(^|[^-\s])--(?=[^-\s]|$)/gm,"$1–")),"link_open"===r.type&&"auto"===r.info&&s--,"link_close"===r.type&&"auto"===r.info&&s++}e.exports=function(e){var t;if(e.md.options.typographer)for(t=e.tokens.length-1;t>=0;t--)"inline"===e.tokens[t].type&&(s.test(e.tokens[t].content)&&u(e.tokens[t].children),n.test(e.tokens[t].content)&&c(e.tokens[t].children))}},function(e,t,r){"use strict";var n=r(0).isWhiteSpace,s=r(0).isPunctChar,o=r(0).isMdAsciiPunct,i=/['"]/,a=/['"]/g;function u(e,t,r){return e.substr(0,t)+r+e.substr(t+1)}function c(e,t){var r,i,c,l,p,h,f,d,m,g,_,b,k,C,v,D,A,y,x,F,E;for(x=[],r=0;r=0&&!(x[A].level<=f);A--);if(x.length=A+1,"text"===i.type){p=0,h=(c=i.content).length;e:for(;p=0)m=c.charCodeAt(l.index-1);else for(A=r-1;A>=0&&("softbreak"!==e[A].type&&"hardbreak"!==e[A].type);A--)if(e[A].content){m=e[A].content.charCodeAt(e[A].content.length-1);break}if(g=32,p=48&&m<=57&&(D=v=!1),v&&D&&(v=_,D=b),v||D){if(D)for(A=x.length-1;A>=0&&(d=x[A],!(x[A].level=0;t--)"inline"===e.tokens[t].type&&i.test(e.tokens[t].content)&&c(e.tokens[t].children,e)}},function(e,t,r){"use strict";var n=r(2);function s(e,t,r){this.src=e,this.env=r,this.tokens=[],this.inlineMode=!1,this.md=t}s.prototype.Token=n,e.exports=s},function(e,t,r){"use strict";var n=r(1),s=[["table",r(36),["paragraph","reference"]],["code",r(37)],["fence",r(38),["paragraph","reference","blockquote","list"]],["blockquote",r(39),["paragraph","reference","blockquote","list"]],["hr",r(40),["paragraph","reference","blockquote","list"]],["list",r(41),["paragraph","reference","blockquote"]],["reference",r(42)],["heading",r(43),["paragraph","reference","blockquote"]],["lheading",r(44)],["html_block",r(45),["paragraph","reference","blockquote"]],["paragraph",r(47)]];function o(){this.ruler=new n;for(var e=0;e=r))&&!(e.sCount[i]=u){e.line=r;break}for(n=0;nr)return!1;if(h=t+1,e.sCount[h]=4)return!1;if((c=e.bMarks[h]+e.tShift[h])>=e.eMarks[h])return!1;if(124!==(a=e.src.charCodeAt(c++))&&45!==a&&58!==a)return!1;for(;c=4)return!1;if((f=o(u)).length&&""===f[0]&&f.shift(),f.length&&""===f[f.length-1]&&f.pop(),0===(d=f.length)||d!==g.length)return!1;if(i)return!0;for(C=e.parentType,e.parentType="table",D=e.md.block.ruler.getRules("blockquote"),(m=e.push("table_open","table",1)).map=b=[t,0],(m=e.push("thead_open","thead",1)).map=[t,t+1],(m=e.push("tr_open","tr",1)).map=[t,t+1],l=0;l=4)break;for((f=o(u)).length&&""===f[0]&&f.shift(),f.length&&""===f[f.length-1]&&f.pop(),h===t+2&&((m=e.push("tbody_open","tbody",1)).map=k=[t+2,0]),(m=e.push("tr_open","tr",1)).map=[h,h+1],l=0;l=4))break;s=++n}return e.line=s,(o=e.push("code_block","code",0)).content=e.getLines(t,s,4+e.blkIndent,!0),o.map=[t,e.line],!0}},function(e,t,r){"use strict";e.exports=function(e,t,r,n){var s,o,i,a,u,c,l,p=!1,h=e.bMarks[t]+e.tShift[t],f=e.eMarks[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(h+3>f)return!1;if(126!==(s=e.src.charCodeAt(h))&&96!==s)return!1;if(u=h,(o=(h=e.skipChars(h,s))-u)<3)return!1;if(l=e.src.slice(u,h),i=e.src.slice(h,f),96===s&&i.indexOf(String.fromCharCode(s))>=0)return!1;if(n)return!0;for(a=t;!(++a>=r)&&!((h=u=e.bMarks[a]+e.tShift[a])<(f=e.eMarks[a])&&e.sCount[a]=4||(h=e.skipChars(h,s))-u=4)return!1;if(62!==e.src.charCodeAt(F++))return!1;if(s)return!0;for(u=f=e.sCount[t]+1,32===e.src.charCodeAt(F)?(F++,u++,f++,o=!1,C=!0):9===e.src.charCodeAt(F)?(C=!0,(e.bsCount[t]+f)%4==3?(F++,u++,f++,o=!1):o=!0):C=!1,d=[e.bMarks[t]],e.bMarks[t]=F;F=E,b=[e.sCount[t]],e.sCount[t]=f-u,k=[e.tShift[t]],e.tShift[t]=F-e.bMarks[t],D=e.md.block.ruler.getRules("blockquote"),_=e.parentType,e.parentType="blockquote",h=t+1;h=(E=e.eMarks[h])));h++)if(62!==e.src.charCodeAt(F++)||y){if(l)break;for(v=!1,a=0,c=D.length;a=E,m.push(e.bsCount[h]),e.bsCount[h]=e.sCount[h]+1+(C?1:0),b.push(e.sCount[h]),e.sCount[h]=f-u,k.push(e.tShift[h]),e.tShift[h]=F-e.bMarks[h]}for(g=e.blkIndent,e.blkIndent=0,(A=e.push("blockquote_open","blockquote",1)).markup=">",A.map=p=[t,0],e.md.block.tokenize(e,t,h),(A=e.push("blockquote_close","blockquote",-1)).markup=">",e.lineMax=x,e.parentType=_,p[1]=e.line,a=0;a=4)return!1;if(42!==(o=e.src.charCodeAt(c++))&&45!==o&&95!==o)return!1;for(i=1;c=i)return-1;if((r=e.src.charCodeAt(o++))<48||r>57)return-1;for(;;){if(o>=i)return-1;if(!((r=e.src.charCodeAt(o++))>=48&&r<=57)){if(41===r||46===r)break;return-1}if(o-s>=10)return-1}return o=4)return!1;if(e.listIndent>=0&&e.sCount[t]-e.listIndent>=4&&e.sCount[t]=e.blkIndent&&(B=!0),(w=o(e,t))>=0){if(h=!0,S=e.bMarks[t]+e.tShift[t],b=Number(e.src.substr(S,w-S-1)),B&&1!==b)return!1}else{if(!((w=s(e,t))>=0))return!1;h=!1}if(B&&e.skipSpaces(w)>=e.eMarks[t])return!1;if(_=e.src.charCodeAt(w-1),n)return!0;for(g=e.tokens.length,h?(T=e.push("ordered_list_open","ol",1),1!==b&&(T.attrs=[["start",b]])):T=e.push("bullet_list_open","ul",1),T.map=m=[t,0],T.markup=String.fromCharCode(_),C=t,q=!1,z=e.md.block.ruler.getRules("list"),A=e.parentType,e.parentType="list";C=k?1:v-p)>4&&(l=1),c=p+l,(T=e.push("list_item_open","li",1)).markup=String.fromCharCode(_),T.map=f=[t,0],F=e.tight,x=e.tShift[t],y=e.sCount[t],D=e.listIndent,e.listIndent=e.blkIndent,e.blkIndent=c,e.tight=!0,e.tShift[t]=a-e.bMarks[t],e.sCount[t]=v,a>=k&&e.isEmpty(t+1)?e.line=Math.min(e.line+2,r):e.md.block.tokenize(e,t,r,!0),e.tight&&!q||(I=!1),q=e.line-t>1&&e.isEmpty(e.line-1),e.blkIndent=e.listIndent,e.listIndent=D,e.tShift[t]=x,e.sCount[t]=y,e.tight=F,(T=e.push("list_item_close","li",-1)).markup=String.fromCharCode(_),C=t=e.line,f[1]=C,a=e.bMarks[t],C>=r)break;if(e.sCount[C]=4)break;for(L=!1,u=0,d=z.length;u=4)return!1;if(91!==e.src.charCodeAt(A))return!1;for(;++A3||e.sCount[x]<0)){for(k=!1,p=0,h=C.length;p=4)return!1;if(35!==(o=e.src.charCodeAt(c))||c>=l)return!1;for(i=1,o=e.src.charCodeAt(++c);35===o&&c6||cc&&n(e.src.charCodeAt(a-1))&&(l=a),e.line=t+1,(u=e.push("heading_open","h"+String(i),1)).markup="########".slice(0,i),u.map=[t,e.line],(u=e.push("inline","",0)).content=e.src.slice(c,l).trim(),u.map=[t,e.line],u.children=[],(u=e.push("heading_close","h"+String(i),-1)).markup="########".slice(0,i)),!0)}},function(e,t,r){"use strict";e.exports=function(e,t,r){var n,s,o,i,a,u,c,l,p,h,f=t+1,d=e.md.block.ruler.getRules("paragraph");if(e.sCount[t]-e.blkIndent>=4)return!1;for(h=e.parentType,e.parentType="paragraph";f3)){if(e.sCount[f]>=e.blkIndent&&(u=e.bMarks[f]+e.tShift[f])<(c=e.eMarks[f])&&(45===(p=e.src.charCodeAt(u))||61===p)&&(u=e.skipChars(u,p),(u=e.skipSpaces(u))>=c)){l=61===p?1:2;break}if(!(e.sCount[f]<0)){for(s=!1,o=0,i=d.length;o|$))/i,/<\/(script|pre|style)>/i,!0],[/^/,!0],[/^<\?/,/\?>/,!0],[/^/,!0],[/^/,!0],[new RegExp("^|$))","i"),/^$/,!0],[new RegExp(s.source+"\\s*$"),/^$/,!1]];e.exports=function(e,t,r,n){var s,i,a,u,c=e.bMarks[t]+e.tShift[t],l=e.eMarks[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(!e.md.options.html)return!1;if(60!==e.src.charCodeAt(c))return!1;for(u=e.src.slice(c,l),s=0;s3||e.sCount[u]<0)){for(n=!1,s=0,o=c.length;s0&&this.level++,this.tokens.push(s),s},o.prototype.isEmpty=function(e){return this.bMarks[e]+this.tShift[e]>=this.eMarks[e]},o.prototype.skipEmptyLines=function(e){for(var t=this.lineMax;et;)if(!s(this.src.charCodeAt(--e)))return e+1;return e},o.prototype.skipChars=function(e,t){for(var r=this.src.length;er;)if(t!==this.src.charCodeAt(--e))return e+1;return e},o.prototype.getLines=function(e,t,r,n){var o,i,a,u,c,l,p,h=e;if(e>=t)return"";for(l=new Array(t-e),o=0;hr?new Array(i-r+1).join(" ")+this.src.slice(u,c):this.src.slice(u,c)}return l.join("")},o.prototype.Token=n,e.exports=o},function(e,t,r){"use strict";var n=r(1),s=[["text",r(50)],["newline",r(51)],["escape",r(52)],["backticks",r(53)],["strikethrough",r(7).tokenize],["emphasis",r(8).tokenize],["link",r(54)],["image",r(55)],["autolink",r(56)],["html_inline",r(57)],["entity",r(58)]],o=[["balance_pairs",r(59)],["strikethrough",r(7).postProcess],["emphasis",r(8).postProcess],["text_collapse",r(60)]];function i(){var e;for(this.ruler=new n,e=0;e=o)break}else e.pending+=e.src[e.pos++]}e.pending&&e.pushPending()},i.prototype.parse=function(e,t,r,n){var s,o,i,a=new this.State(e,t,r,n);for(this.tokenize(a),i=(o=this.ruler2.getRules("")).length,s=0;s=0&&32===e.pending.charCodeAt(r)?r>=1&&32===e.pending.charCodeAt(r-1)?(e.pending=e.pending.replace(/ +$/,""),e.push("hardbreak","br",0)):(e.pending=e.pending.slice(0,-1),e.push("softbreak","br",0)):e.push("softbreak","br",0)),o++;o?@[]^_`{|}~-".split("").forEach((function(e){s[e.charCodeAt(0)]=1})),e.exports=function(e,t){var r,o=e.pos,i=e.posMax;if(92!==e.src.charCodeAt(o))return!1;if(++o=m)return!1;if(g=c,(l=e.md.helpers.parseLinkDestination(e.src,c,e.posMax)).ok){for(h=e.md.normalizeLink(l.str),e.md.validateLink(h)?c=l.pos:h="",g=c;c=m||41!==e.src.charCodeAt(c))&&(_=!0),c++}if(_){if(void 0===e.env.references)return!1;if(c=0?i=e.src.slice(g,c++):c=a+1):c=a+1,i||(i=e.src.slice(u,a)),!(p=e.env.references[n(i)]))return e.pos=d,!1;h=p.href,f=p.title}return t||(e.pos=u,e.posMax=a,e.push("link_open","a",1).attrs=r=[["href",h]],f&&r.push(["title",f]),e.md.inline.tokenize(e),e.push("link_close","a",-1)),e.pos=c,e.posMax=m,!0}},function(e,t,r){"use strict";var n=r(0).normalizeReference,s=r(0).isSpace;e.exports=function(e,t){var r,o,i,a,u,c,l,p,h,f,d,m,g,_="",b=e.pos,k=e.posMax;if(33!==e.src.charCodeAt(e.pos))return!1;if(91!==e.src.charCodeAt(e.pos+1))return!1;if(c=e.pos+2,(u=e.md.helpers.parseLinkLabel(e,e.pos+1,!1))<0)return!1;if((l=u+1)=k)return!1;for(g=l,(h=e.md.helpers.parseLinkDestination(e.src,l,e.posMax)).ok&&(_=e.md.normalizeLink(h.str),e.md.validateLink(_)?l=h.pos:_=""),g=l;l=k||41!==e.src.charCodeAt(l))return e.pos=b,!1;l++}else{if(void 0===e.env.references)return!1;if(l=0?a=e.src.slice(g,l++):l=u+1):l=u+1,a||(a=e.src.slice(c,u)),!(p=e.env.references[n(a)]))return e.pos=b,!1;_=p.href,f=p.title}return t||(i=e.src.slice(c,u),e.md.inline.parse(i,e.md,e.env,m=[]),(d=e.push("image","img",0)).attrs=r=[["src",_],["alt",""]],d.children=m,d.content=i,f&&r.push(["title",f])),e.pos=l,e.posMax=k,!0}},function(e,t,r){"use strict";var n=/^([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/,s=/^([a-zA-Z][a-zA-Z0-9+.\-]{1,31}):([^<>\x00-\x20]*)$/;e.exports=function(e,t){var r,o,i,a,u,c,l=e.pos;if(60!==e.src.charCodeAt(l))return!1;for(u=e.pos,c=e.posMax;;){if(++l>=c)return!1;if(60===(a=e.src.charCodeAt(l)))return!1;if(62===a)break}return r=e.src.slice(u+1,l),s.test(r)?(o=e.md.normalizeLink(r),!!e.md.validateLink(o)&&(t||((i=e.push("link_open","a",1)).attrs=[["href",o]],i.markup="autolink",i.info="auto",(i=e.push("text","",0)).content=e.md.normalizeLinkText(r),(i=e.push("link_close","a",-1)).markup="autolink",i.info="auto"),e.pos+=r.length+2,!0)):!!n.test(r)&&(o=e.md.normalizeLink("mailto:"+r),!!e.md.validateLink(o)&&(t||((i=e.push("link_open","a",1)).attrs=[["href",o]],i.markup="autolink",i.info="auto",(i=e.push("text","",0)).content=e.md.normalizeLinkText(r),(i=e.push("link_close","a",-1)).markup="autolink",i.info="auto"),e.pos+=r.length+2,!0))}},function(e,t,r){"use strict";var n=r(6).HTML_TAG_RE;e.exports=function(e,t){var r,s,o,i=e.pos;return!!e.md.options.html&&(o=e.posMax,!(60!==e.src.charCodeAt(i)||i+2>=o)&&(!(33!==(r=e.src.charCodeAt(i+1))&&63!==r&&47!==r&&!function(e){var t=32|e;return t>=97&&t<=122}(r))&&(!!(s=e.src.slice(i).match(n))&&(t||(e.push("html_inline","",0).content=e.src.slice(i,i+s[0].length)),e.pos+=s[0].length,!0))))}},function(e,t,r){"use strict";var n=r(3),s=r(0).has,o=r(0).isValidEntityCode,i=r(0).fromCodePoint,a=/^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i,u=/^&([a-z][a-z0-9]{1,31});/i;e.exports=function(e,t){var r,c,l=e.pos,p=e.posMax;if(38!==e.src.charCodeAt(l))return!1;if(l+1i;n-=o.jump+1)if((o=t[n]).marker===s.marker&&o.open&&o.end<0&&(u=!1,(o.close||s.open)&&(o.length+s.length)%3==0&&(o.length%3==0&&s.length%3==0||(u=!0)),!u)){c=n>0&&!t[n-1].open?t[n-1].jump+1:0,s.jump=r-n+c,s.open=!1,o.end=r,o.jump=c,o.close=!1,a=-1;break}-1!==a&&(l[s.marker][(s.length||0)%3]=a)}}e.exports=function(e){var t,r=e.tokens_meta,s=e.tokens_meta.length;for(n(0,e.delimiters),t=0;t0&&n++,"text"===s[t].type&&t+10&&(this.level++,this._prev_delimiters.push(this.delimiters),this.delimiters=[],o={delimiters:this.delimiters}),this.pendingLevel=this.level,this.tokens.push(s),this.tokens_meta.push(o),s},a.prototype.scanDelims=function(e,t){var r,n,a,u,c,l,p,h,f,d=e,m=!0,g=!0,_=this.posMax,b=this.src.charCodeAt(e);for(r=e>0?this.src.charCodeAt(e-1):32;d<_&&this.src.charCodeAt(d)===b;)d++;return a=d-e,n=d<_?this.src.charCodeAt(d):32,p=i(r)||o(String.fromCharCode(r)),f=i(n)||o(String.fromCharCode(n)),l=s(r),(h=s(n))?m=!1:f&&(l||p||(m=!1)),l?g=!1:p&&(h||f||(g=!1)),t?(u=m,c=g):(u=m&&(!g||p),c=g&&(!m||f)),{can_open:u,can_close:c,length:a}},a.prototype.Token=n,e.exports=a},function(e,t,r){"use strict";function n(e){var t=Array.prototype.slice.call(arguments,1);return t.forEach((function(t){t&&Object.keys(t).forEach((function(r){e[r]=t[r]}))})),e}function s(e){return Object.prototype.toString.call(e)}function o(e){return"[object Function]"===s(e)}function i(e){return e.replace(/[.?*+^$[\]\\(){}|-]/g,"\\$&")}var a={fuzzyLink:!0,fuzzyEmail:!0,fuzzyIP:!1};var u={"http:":{validate:function(e,t,r){var n=e.slice(t);return r.re.http||(r.re.http=new RegExp("^\\/\\/"+r.re.src_auth+r.re.src_host_port_strict+r.re.src_path,"i")),r.re.http.test(n)?n.match(r.re.http)[0].length:0}},"https:":"http:","ftp:":"http:","//":{validate:function(e,t,r){var n=e.slice(t);return r.re.no_http||(r.re.no_http=new RegExp("^"+r.re.src_auth+"(?:localhost|(?:(?:"+r.re.src_domain+")\\.)+"+r.re.src_domain_root+")"+r.re.src_port+r.re.src_host_terminator+r.re.src_path,"i")),r.re.no_http.test(n)?t>=3&&":"===e[t-3]||t>=3&&"/"===e[t-3]?0:n.match(r.re.no_http)[0].length:0}},"mailto:":{validate:function(e,t,r){var n=e.slice(t);return r.re.mailto||(r.re.mailto=new RegExp("^"+r.re.src_email_name+"@"+r.re.src_host_strict,"i")),r.re.mailto.test(n)?n.match(r.re.mailto)[0].length:0}}},c="biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф".split("|");function l(e){var t=e.re=r(63)(e.__opts__),n=e.__tlds__.slice();function a(e){return e.replace("%TLDS%",t.src_tlds)}e.onCompile(),e.__tlds_replaced__||n.push("a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]"),n.push(t.src_xn),t.src_tlds=n.join("|"),t.email_fuzzy=RegExp(a(t.tpl_email_fuzzy),"i"),t.link_fuzzy=RegExp(a(t.tpl_link_fuzzy),"i"),t.link_no_ip_fuzzy=RegExp(a(t.tpl_link_no_ip_fuzzy),"i"),t.host_fuzzy_test=RegExp(a(t.tpl_host_fuzzy_test),"i");var u=[];function c(e,t){throw new Error('(LinkifyIt) Invalid schema "'+e+'": '+t)}e.__compiled__={},Object.keys(e.__schemas__).forEach((function(t){var r=e.__schemas__[t];if(null!==r){var n={validate:null,link:null};if(e.__compiled__[t]=n,"[object Object]"===s(r))return!function(e){return"[object RegExp]"===s(e)}(r.validate)?o(r.validate)?n.validate=r.validate:c(t,r):n.validate=function(e){return function(t,r){var n=t.slice(r);return e.test(n)?n.match(e)[0].length:0}}(r.validate),void(o(r.normalize)?n.normalize=r.normalize:r.normalize?c(t,r):n.normalize=function(e,t){t.normalize(e)});!function(e){return"[object String]"===s(e)}(r)?c(t,r):u.push(t)}})),u.forEach((function(t){e.__compiled__[e.__schemas__[t]]&&(e.__compiled__[t].validate=e.__compiled__[e.__schemas__[t]].validate,e.__compiled__[t].normalize=e.__compiled__[e.__schemas__[t]].normalize)})),e.__compiled__[""]={validate:null,normalize:function(e,t){t.normalize(e)}};var l=Object.keys(e.__compiled__).filter((function(t){return t.length>0&&e.__compiled__[t]})).map(i).join("|");e.re.schema_test=RegExp("(^|(?!_)(?:[><|]|"+t.src_ZPCc+"))("+l+")","i"),e.re.schema_search=RegExp("(^|(?!_)(?:[><|]|"+t.src_ZPCc+"))("+l+")","ig"),e.re.pretest=RegExp("("+e.re.schema_test.source+")|("+e.re.host_fuzzy_test.source+")|@","i"),function(e){e.__index__=-1,e.__text_cache__=""}(e)}function p(e,t){var r=e.__index__,n=e.__last_index__,s=e.__text_cache__.slice(r,n);this.schema=e.__schema__.toLowerCase(),this.index=r+t,this.lastIndex=n+t,this.raw=s,this.text=s,this.url=s}function h(e,t){var r=new p(e,t);return e.__compiled__[r.schema].normalize(r,e),r}function f(e,t){if(!(this instanceof f))return new f(e,t);var r;t||(r=e,Object.keys(r||{}).reduce((function(e,t){return e||a.hasOwnProperty(t)}),!1)&&(t=e,e={})),this.__opts__=n({},a,t),this.__index__=-1,this.__last_index__=-1,this.__schema__="",this.__text_cache__="",this.__schemas__=n({},u,e),this.__compiled__={},this.__tlds__=c,this.__tlds_replaced__=!1,this.re={},l(this)}f.prototype.add=function(e,t){return this.__schemas__[e]=t,l(this),this},f.prototype.set=function(e){return this.__opts__=n(this.__opts__,e),this},f.prototype.test=function(e){if(this.__text_cache__=e,this.__index__=-1,!e.length)return!1;var t,r,n,s,o,i,a,u;if(this.re.schema_test.test(e))for((a=this.re.schema_search).lastIndex=0;null!==(t=a.exec(e));)if(s=this.testSchemaAt(e,t[2],a.lastIndex)){this.__schema__=t[2],this.__index__=t.index+t[1].length,this.__last_index__=t.index+t[0].length+s;break}return this.__opts__.fuzzyLink&&this.__compiled__["http:"]&&(u=e.search(this.re.host_fuzzy_test))>=0&&(this.__index__<0||u=0&&null!==(n=e.match(this.re.email_fuzzy))&&(o=n.index+n[1].length,i=n.index+n[0].length,(this.__index__<0||othis.__last_index__)&&(this.__schema__="mailto:",this.__index__=o,this.__last_index__=i)),this.__index__>=0},f.prototype.pretest=function(e){return this.re.pretest.test(e)},f.prototype.testSchemaAt=function(e,t,r){return this.__compiled__[t.toLowerCase()]?this.__compiled__[t.toLowerCase()].validate(e,r,this):0},f.prototype.match=function(e){var t=0,r=[];this.__index__>=0&&this.__text_cache__===e&&(r.push(h(this,t)),t=this.__last_index__);for(var n=t?e.slice(t):e;this.test(n);)r.push(h(this,t)),n=n.slice(this.__last_index__),t+=this.__last_index__;return r.length?r:null},f.prototype.tlds=function(e,t){return e=Array.isArray(e)?e:[e],t?(this.__tlds__=this.__tlds__.concat(e).sort().filter((function(e,t,r){return e!==r[t-1]})).reverse(),l(this),this):(this.__tlds__=e.slice(),this.__tlds_replaced__=!0,l(this),this)},f.prototype.normalize=function(e){e.schema||(e.url="http://"+e.url),"mailto:"!==e.schema||/^mailto:/i.test(e.url)||(e.url="mailto:"+e.url)},f.prototype.onCompile=function(){},e.exports=f},function(e,t,r){"use strict";e.exports=function(e){var t={};t.src_Any=r(64).source,t.src_Cc=r(65).source,t.src_Z=r(66).source,t.src_P=r(67).source,t.src_ZPCc=[t.src_Z,t.src_P,t.src_Cc].join("|"),t.src_ZCc=[t.src_Z,t.src_Cc].join("|");return t.src_pseudo_letter="(?:(?![><|]|"+t.src_ZPCc+")"+t.src_Any+")",t.src_ip4="(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)",t.src_auth="(?:(?:(?!"+t.src_ZCc+"|[@/\\[\\]()]).)+@)?",t.src_port="(?::(?:6(?:[0-4]\\d{3}|5(?:[0-4]\\d{2}|5(?:[0-2]\\d|3[0-5])))|[1-5]?\\d{1,4}))?",t.src_host_terminator="(?=$|[><|]|"+t.src_ZPCc+")(?!-|_|:\\d|\\.-|\\.(?!$|"+t.src_ZPCc+"))",t.src_path="(?:[/?#](?:(?!"+t.src_ZCc+"|[><|]|[()[\\]{}.,\"'?!\\-]).|\\[(?:(?!"+t.src_ZCc+"|\\]).)*\\]|\\((?:(?!"+t.src_ZCc+"|[)]).)*\\)|\\{(?:(?!"+t.src_ZCc+'|[}]).)*\\}|\\"(?:(?!'+t.src_ZCc+'|["]).)+\\"|\\\'(?:(?!'+t.src_ZCc+"|[']).)+\\'|\\'(?="+t.src_pseudo_letter+"|[-]).|\\.{2,}[a-zA-Z0-9%/&]|\\.(?!"+t.src_ZCc+"|[.]).|"+(e&&e["---"]?"\\-(?!--(?:[^-]|$))(?:-*)|":"\\-+|")+"\\,(?!"+t.src_ZCc+").|\\!+(?!"+t.src_ZCc+"|[!]).|\\?(?!"+t.src_ZCc+"|[?]).)+|\\/)?",t.src_email_name='[\\-;:&=\\+\\$,\\.a-zA-Z0-9_][\\-;:&=\\+\\$,\\"\\.a-zA-Z0-9_]*',t.src_xn="xn--[a-z0-9\\-]{1,59}",t.src_domain_root="(?:"+t.src_xn+"|"+t.src_pseudo_letter+"{1,63})",t.src_domain="(?:"+t.src_xn+"|(?:"+t.src_pseudo_letter+")|(?:"+t.src_pseudo_letter+"(?:-|"+t.src_pseudo_letter+"){0,61}"+t.src_pseudo_letter+"))",t.src_host="(?:(?:(?:(?:"+t.src_domain+")\\.)*"+t.src_domain+"))",t.tpl_host_fuzzy="(?:"+t.src_ip4+"|(?:(?:(?:"+t.src_domain+")\\.)+(?:%TLDS%)))",t.tpl_host_no_ip_fuzzy="(?:(?:(?:"+t.src_domain+")\\.)+(?:%TLDS%))",t.src_host_strict=t.src_host+t.src_host_terminator,t.tpl_host_fuzzy_strict=t.tpl_host_fuzzy+t.src_host_terminator,t.src_host_port_strict=t.src_host+t.src_port+t.src_host_terminator,t.tpl_host_port_fuzzy_strict=t.tpl_host_fuzzy+t.src_port+t.src_host_terminator,t.tpl_host_port_no_ip_fuzzy_strict=t.tpl_host_no_ip_fuzzy+t.src_port+t.src_host_terminator,t.tpl_host_fuzzy_test="localhost|www\\.|\\.\\d{1,3}\\.|(?:\\.(?:%TLDS%)(?:"+t.src_ZPCc+"|>|$))",t.tpl_email_fuzzy='(^|[><|]|"|\\(|'+t.src_ZCc+")("+t.src_email_name+"@"+t.tpl_host_fuzzy_strict+")",t.tpl_link_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`||]|"+t.src_ZPCc+"))((?![$+<=>^`||])"+t.tpl_host_port_fuzzy_strict+t.src_path+")",t.tpl_link_no_ip_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`||]|"+t.src_ZPCc+"))((?![$+<=>^`||])"+t.tpl_host_port_no_ip_fuzzy_strict+t.src_path+")",t}},function(e,t){e.exports=/[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/},function(e,t){e.exports=/[\0-\x1F\x7F-\x9F]/},function(e,t){e.exports=/[ \xA0\u1680\u2000-\u200A\u202F\u205F\u3000]/},function(e,t){e.exports=/[!-#%-\*,-/:;\?@\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E44\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD807[\uDC41-\uDC45\uDC70\uDC71]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/},function(e,t,r){(function(e,n){var s;/*! https://mths.be/punycode v1.4.1 by @mathias */!function(o){t&&t.nodeType,e&&e.nodeType;var i="object"==typeof n&&n;i.global!==i&&i.window!==i&&i.self;var a,u=2147483647,c=/^xn--/,l=/[^\x20-\x7E]/,p=/[\x2E\u3002\uFF0E\uFF61]/g,h={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},f=Math.floor,d=String.fromCharCode;function m(e){throw new RangeError(h[e])}function g(e,t){for(var r=e.length,n=[];r--;)n[r]=t(e[r]);return n}function _(e,t){var r=e.split("@"),n="";return r.length>1&&(n=r[0]+"@",e=r[1]),n+g((e=e.replace(p,".")).split("."),t).join(".")}function b(e){for(var t,r,n=[],s=0,o=e.length;s=55296&&t<=56319&&s65535&&(t+=d((e-=65536)>>>10&1023|55296),e=56320|1023&e),t+=d(e)})).join("")}function C(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function v(e,t,r){var n=0;for(e=r?f(e/700):e>>1,e+=f(e/t);e>455;n+=36)e=f(e/35);return f(n+36*e/(e+38))}function D(e){var t,r,n,s,o,i,a,c,l,p,h,d=[],g=e.length,_=0,b=128,C=72;for((r=e.lastIndexOf("-"))<0&&(r=0),n=0;n=128&&m("not-basic"),d.push(e.charCodeAt(n));for(s=r>0?r+1:0;s=g&&m("invalid-input"),((c=(h=e.charCodeAt(s++))-48<10?h-22:h-65<26?h-65:h-97<26?h-97:36)>=36||c>f((u-_)/i))&&m("overflow"),_+=c*i,!(c<(l=a<=C?1:a>=C+26?26:a-C));a+=36)i>f(u/(p=36-l))&&m("overflow"),i*=p;C=v(_-o,t=d.length+1,0==o),f(_/t)>u-b&&m("overflow"),b+=f(_/t),_%=t,d.splice(_++,0,b)}return k(d)}function A(e){var t,r,n,s,o,i,a,c,l,p,h,g,_,k,D,A=[];for(g=(e=b(e)).length,t=128,r=0,o=72,i=0;i=t&&hf((u-r)/(_=n+1))&&m("overflow"),r+=(a-t)*_,t=a,i=0;iu&&m("overflow"),h==t){for(c=r,l=36;!(c<(p=l<=o?1:l>=o+26?26:l-o));l+=36)D=c-p,k=36-p,A.push(d(C(p+D%k,0))),c=f(D/k);A.push(d(C(c,0))),o=v(r,_,n==s),r=0,++n}++r,++t}return A.join("")}a={version:"1.4.1",ucs2:{decode:b,encode:k},decode:D,encode:A,toASCII:function(e){return _(e,(function(e){return l.test(e)?"xn--"+A(e):e}))},toUnicode:function(e){return _(e,(function(e){return c.test(e)?D(e.slice(4).toLowerCase()):e}))}},void 0===(s=function(){return a}.call(t,r,t,e))||(e.exports=s)}()}).call(this,r(69)(e),r(70))},function(e,t){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}},function(e,t){var r;r=function(){return this}();try{r=r||new Function("return this")()}catch(e){"object"==typeof window&&(r=window)}e.exports=r},function(e,t,r){"use strict";e.exports={options:{html:!1,xhtmlOut:!1,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"“”‘’",highlight:null,maxNesting:100},components:{core:{},block:{},inline:{}}}},function(e,t,r){"use strict";e.exports={options:{html:!1,xhtmlOut:!1,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"“”‘’",highlight:null,maxNesting:20},components:{core:{rules:["normalize","block","inline"]},block:{rules:["paragraph"]},inline:{rules:["text"],rules2:["balance_pairs","text_collapse"]}}}},function(e,t,r){"use strict";e.exports={options:{html:!0,xhtmlOut:!0,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"“”‘’",highlight:null,maxNesting:20},components:{core:{rules:["normalize","block","inline"]},block:{rules:["blockquote","code","fence","heading","hr","html_block","lheading","list","reference","paragraph"]},inline:{rules:["autolink","backticks","emphasis","entity","escape","html_inline","image","link","newline","text"],rules2:["balance_pairs","emphasis","text_collapse"]}}}}]); \ No newline at end of file diff --git a/extensions/markdown-language-features/webpack.config.js b/extensions/markdown-language-features/webpack.config.js index 865444125fe..cfbacda4045 100644 --- a/extensions/markdown-language-features/webpack.config.js +++ b/extensions/markdown-language-features/webpack.config.js @@ -6,8 +6,8 @@ const path = require('path'); module.exports = { entry: { - index: './preview-src/index.ts', - pre: './preview-src/pre.ts' + index: path.join(__dirname, 'preview-src', 'index.ts'), + pre: path.join(__dirname, 'preview-src', 'pre.ts'), }, module: { rules: [ diff --git a/extensions/markdown-language-features/webpack.notebook.js b/extensions/markdown-language-features/webpack.notebook.js index bf1e22651a8..3783b8a6c4d 100644 --- a/extensions/markdown-language-features/webpack.notebook.js +++ b/extensions/markdown-language-features/webpack.notebook.js @@ -5,8 +5,9 @@ const path = require('path'); module.exports = { + mode: 'production', entry: { - index: './notebook/index.ts' + index: path.join(__dirname, 'notebook', 'index.ts') }, module: { rules: [ diff --git a/extensions/microsoft-authentication/tsconfig.json b/extensions/microsoft-authentication/tsconfig.json index 86c288d3c6e..2c2bce4b8aa 100644 --- a/extensions/microsoft-authentication/tsconfig.json +++ b/extensions/microsoft-authentication/tsconfig.json @@ -17,5 +17,6 @@ "strict": true, "target": "es2019" }, - "exclude": ["node_modules"] + "exclude": ["node_modules"], + "include": ["src/**/*"] } diff --git a/extensions/notebook-markdown-extensions/package.json b/extensions/notebook-markdown-extensions/package.json index d5cd3bb4c0a..4cefc019369 100644 --- a/extensions/notebook-markdown-extensions/package.json +++ b/extensions/notebook-markdown-extensions/package.json @@ -31,8 +31,7 @@ "scripts": { "compile": "npm run build-notebook", "watch": "npm run build-notebook", - "build-notebook": "npx webpack-cli --config webpack.notebook.js --mode production", - "postinstall": "npm run build-notebook" + "build-notebook": "npx webpack-cli --config webpack.notebook.js --mode production" }, "devDependencies": { "@iktakahiro/markdown-it-katex": "^4.0.1", diff --git a/extensions/notebook-markdown-extensions/webpack.notebook.js b/extensions/notebook-markdown-extensions/webpack.notebook.js index 18044ea235a..de8fe9af0fc 100644 --- a/extensions/notebook-markdown-extensions/webpack.notebook.js +++ b/extensions/notebook-markdown-extensions/webpack.notebook.js @@ -6,6 +6,13 @@ const path = require('path'); const CopyPlugin = require('copy-webpack-plugin'); module.exports = { + context: path.resolve(__dirname), + mode: 'production', + performance: { + hints: false, + maxEntrypointSize: 512000, + maxAssetSize: 512000 + }, entry: { katex: './notebook/katex.ts', emoji: './notebook/emoji.ts', diff --git a/package.json b/package.json index 22a7b5200e1..36d3ba4a56f 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "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": "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", @@ -25,6 +25,7 @@ "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", "mocha": "mocha test/unit/node/all.js --delay", diff --git a/src/bootstrap-node.js b/src/bootstrap-node.js index 3956deab8d2..35ead94b8d3 100644 --- a/src/bootstrap-node.js +++ b/src/bootstrap-node.js @@ -10,7 +10,7 @@ // - Windows: call `process.chdir()` to always set application folder as cwd // - 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 +// TODO@bpasero revisit if chdir() on Windows is needed in the future still function setupCurrentWorkingDirectory() { const path = require('path'); diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index 382f52049f2..f62a89e0d9a 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -232,9 +232,12 @@ export class IconLabel extends Disposable { } tokenSource = new CancellationTokenSource(); function mouseLeaveOrDown(this: HTMLElement, e: MouseEvent): any { - if ((e.type === dom.EventType.MOUSE_DOWN) || (e).fromElement === htmlElement) { + 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); diff --git a/src/vs/base/parts/quickinput/browser/quickInput.ts b/src/vs/base/parts/quickinput/browser/quickInput.ts index bea0f810f49..63c4a28ee7e 100644 --- a/src/vs/base/parts/quickinput/browser/quickInput.ts +++ b/src/vs/base/parts/quickinput/browser/quickInput.ts @@ -1406,6 +1406,7 @@ export class QuickInputController extends Disposable { resolve(undefined); }), ]; + input.title = options.title; input.canSelectMany = !!options.canPickMany; input.placeholder = options.placeHolder; input.ignoreFocusOut = !!options.ignoreFocusLost; @@ -1499,6 +1500,8 @@ export class QuickInputController extends Disposable { resolve(undefined); }), ]; + + input.title = options.title; input.value = options.value || ''; input.valueSelection = options.valueSelection; input.prompt = options.prompt; diff --git a/src/vs/base/parts/quickinput/common/quickInput.ts b/src/vs/base/parts/quickinput/common/quickInput.ts index 33c29d9d3ed..477f416943c 100644 --- a/src/vs/base/parts/quickinput/common/quickInput.ts +++ b/src/vs/base/parts/quickinput/common/quickInput.ts @@ -59,6 +59,11 @@ export interface IQuickNavigateConfiguration { export interface IPickOptions { + /** + * an optional string to show as the title of the quick input + */ + title?: string; + /** * an optional string to show as placeholder in the input box to guide the user what she picks on */ @@ -116,6 +121,11 @@ export interface IPickOptions { export interface IInputOptions { + /** + * an optional string to show as the title of the quick input + */ + title?: string; + /** * the value to prefill in the input box */ diff --git a/src/vs/code/browser/workbench/workbench-web.html b/src/vs/code/browser/workbench/workbench-web.html new file mode 100644 index 00000000000..628d9778c54 --- /dev/null +++ b/src/vs/code/browser/workbench/workbench-web.html @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index 423a4204374..5589fd7f120 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -106,7 +106,7 @@ export class View extends ViewEventHandler { // The view context is passed on to most classes (basically to reduce param. counts in ctors) this._context = new ViewContext(configuration, themeService.getColorTheme(), model); - this._configPixelRatio = this._configPixelRatio = this._context.configuration.options.get(EditorOption.pixelRatio); + this._configPixelRatio = this._context.configuration.options.get(EditorOption.pixelRatio); // Ensure the view is the first event handler in order to update the layout this._context.addEventHandler(this); diff --git a/src/vs/editor/contrib/linesOperations/linesOperations.ts b/src/vs/editor/contrib/linesOperations/linesOperations.ts index 54fcba6ac55..64b689a5fc2 100644 --- a/src/vs/editor/contrib/linesOperations/linesOperations.ts +++ b/src/vs/editor/contrib/linesOperations/linesOperations.ts @@ -1058,7 +1058,7 @@ export class SnakeCaseAction extends AbstractCaseAction { protected _modifyText(text: string, wordSeparators: string): string { return (text .replace(/(\p{Ll})(\p{Lu})/gmu, '$1_$2') - .replace(/([^\b_])(\p{Lu})(\p{Ll})/gmu, '$1_$2$3') + .replace(/(\p{Lu}|\p{N})(\p{Lu})(\p{Ll})/gmu, '$1_$2$3') .toLocaleLowerCase() ); } diff --git a/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts b/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts index b3cbe4bdc55..0e43e416e9b 100644 --- a/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts +++ b/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts @@ -549,7 +549,10 @@ suite('Editor Contrib - Line Operations', () => { `function helloWorld() { return someGlobalObject.printHelloWorld("en", "utf-8"); } - helloWorld();`.replace(/^\s+/gm, '') + helloWorld();`.replace(/^\s+/gm, ''), + `'JavaScript'`, + 'parseHTML4String', + '_accessor: ServicesAccessor' ], {}, (editor) => { let model = editor.getModel()!; let uppercaseAction = new UpperCaseAction(); @@ -659,6 +662,21 @@ suite('Editor Contrib - Line Operations', () => { } hello_world();`.replace(/^\s+/gm, '')); assertSelection(editor, new Selection(14, 1, 17, 15)); + + editor.setSelection(new Selection(18, 1, 18, 13)); + executeAction(snakecaseAction, editor); + assert.strictEqual(model.getLineContent(18), `'java_script'`); + assertSelection(editor, new Selection(18, 1, 18, 14)); + + editor.setSelection(new Selection(19, 1, 19, 17)); + executeAction(snakecaseAction, editor); + assert.strictEqual(model.getLineContent(19), 'parse_html4_string'); + assertSelection(editor, new Selection(19, 1, 19, 19)); + + editor.setSelection(new Selection(20, 1, 20, 28)); + executeAction(snakecaseAction, editor); + assert.strictEqual(model.getLineContent(20), '_accessor: services_accessor'); + assertSelection(editor, new Selection(20, 1, 20, 29)); } ); diff --git a/src/vs/editor/contrib/quickAccess/gotoLineQuickAccess.ts b/src/vs/editor/contrib/quickAccess/gotoLineQuickAccess.ts index 2885cc4fb0d..c31fec73d8e 100644 --- a/src/vs/editor/contrib/quickAccess/gotoLineQuickAccess.ts +++ b/src/vs/editor/contrib/quickAccess/gotoLineQuickAccess.ts @@ -125,7 +125,7 @@ export abstract class AbstractGotoLineQuickAccessProvider extends AbstractEditor // Location valid: indicate this as picker label if (this.isValidLineNumber(editor, lineNumber)) { if (this.isValidColumn(editor, lineNumber, column)) { - return localize('gotoLineColumnLabel', "Go to line {0} and column {1}.", lineNumber, column); + return localize('gotoLineColumnLabel', "Go to line {0} and character {1}.", lineNumber, column); } return localize('gotoLineLabel', "Go to line {0}.", lineNumber); diff --git a/src/vs/platform/extensionManagement/node/extensionsScanner.ts b/src/vs/platform/extensionManagement/node/extensionsScanner.ts index 15833747fa0..b5d716d60ab 100644 --- a/src/vs/platform/extensionManagement/node/extensionsScanner.ts +++ b/src/vs/platform/extensionManagement/node/extensionsScanner.ts @@ -26,6 +26,8 @@ import { IStringDictionary } from 'vs/base/common/collections'; import { FileAccess } from 'vs/base/common/network'; 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'; const ERROR_SCANNING_SYS_EXTENSIONS = 'scanningSystem'; const ERROR_SCANNING_USER_EXTENSIONS = 'scanningUser'; @@ -100,7 +102,7 @@ export class ExtensionsScanner extends Disposable { async extractUserExtension(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, token: CancellationToken): Promise { const folderName = identifierWithVersion.key(); - const tempPath = path.join(this.extensionsPath, `.${folderName}`); + const tempPath = path.join(this.extensionsPath, `.${generateUuid()}`); const extensionPath = path.join(this.extensionsPath, folderName); try { @@ -117,11 +119,15 @@ export class ExtensionsScanner extends Disposable { await this.rename(identifierWithVersion, tempPath, extensionPath, Date.now() + (2 * 60 * 1000) /* Retry for 2 minutes */); this.logService.info('Renamed to', extensionPath); } catch (error) { - this.logService.info('Rename failed. Deleting from extracted location', tempPath); try { - pfs.rimraf(tempPath); + await pfs.rimraf(tempPath); } catch (e) { /* ignore */ } - throw error; + if (error.code === 'ENOTEMPTY') { + this.logService.info(`Rename failed because extension was installed by another source. So ignoring renaming.`, identifierWithVersion.id); + } else { + this.logService.info(`Rename failed because of ${getErrorMessage(error)}. Deleted from extracted location`, tempPath); + throw error; + } } let local: ILocalExtension | null = null; diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts index c218f74c847..5f1eb19f6fb 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts @@ -14,7 +14,7 @@ import { WorkspacesManagementMainService, IStoredWorkspace, getSingleFolderWorks import { WORKSPACE_EXTENSION, IRawFileWorkspaceFolder, IWorkspaceFolderCreationData, IRawUriWorkspaceFolder, rewriteWorkspaceFileForNewLocation, IWorkspaceIdentifier, IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { NullLogService } from 'vs/platform/log/common/log'; import { URI } from 'vs/base/common/uri'; -import { getRandomTestPath } from 'vs/base/test/node/testUtils'; +import { flakySuite, getRandomTestPath } from 'vs/base/test/node/testUtils'; import { isWindows } from 'vs/base/common/platform'; import { normalizeDriveLetter } from 'vs/base/common/labels'; import { extUriBiasedIgnorePathCase } from 'vs/base/common/resources'; @@ -25,7 +25,7 @@ import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; -suite('WorkspacesManagementMainService', () => { +flakySuite('WorkspacesManagementMainService', () => { class TestDialogMainService implements IDialogMainService { diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index ed9f55763cb..17e0ec366d9 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -924,6 +924,24 @@ declare module 'vscode' { //#endregion + //#region allow title property to QuickPickOptions/InputBoxOptions: https://github.com/microsoft/vscode/issues/77423 + + interface QuickPickOptions { + /** + * An optional string that represents the tile of the quick pick. + */ + title?: string; + } + + interface InputBoxOptions { + /** + * An optional string that represents the tile of the input box. + */ + title?: string; + } + + //#endregion + //#region Provide a way for custom editors to process untitled files without relying on textDocument https://github.com/microsoft/vscode/issues/115631 /** * Additional information about the opening custom document. diff --git a/src/vs/workbench/api/browser/mainThreadQuickOpen.ts b/src/vs/workbench/api/browser/mainThreadQuickOpen.ts index e1a8fdbd11a..45f9f551130 100644 --- a/src/vs/workbench/api/browser/mainThreadQuickOpen.ts +++ b/src/vs/workbench/api/browser/mainThreadQuickOpen.ts @@ -89,6 +89,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape { const inputOptions: IInputOptions = Object.create(null); if (options) { + inputOptions.title = options.title; inputOptions.password = options.password; inputOptions.placeHolder = options.placeHolder; inputOptions.valueSelection = options.valueSelection; diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index b049f8646d8..93c639e58a6 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -16,6 +16,7 @@ import { ITerminalExternalLinkProvider, ITerminalInstance, ITerminalInstanceServ 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 { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; @extHostNamedCustomer(MainContext.MainThreadTerminalService) @@ -32,6 +33,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape private readonly _toDispose = new DisposableStore(); private readonly _terminalProcessProxies = 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 @@ -58,6 +60,8 @@ 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))); @@ -350,7 +354,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } private async _onRequestAvailableProfiles(req: IAvailableProfilesRequest): Promise { - if (this._isPrimaryExtHost()) { + if (this._isPrimaryExtHost() && this._extHostKind !== ExtensionHostKind.LocalWebWorker) { req.callback(await this._proxy.$getAvailableProfiles(req.quickLaunchOnly)); } } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 5efc74965f1..02a89edbac9 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -505,6 +505,8 @@ export interface BaseTransferQuickInput { id: number; + title?: string; + type?: 'quickPick' | 'inputBox'; enabled?: boolean; @@ -559,6 +561,7 @@ export interface TransferInputBox extends BaseTransferQuickInput { } export interface IInputBoxOptions { + title?: string; value?: string; valueSelection?: [number, number]; prompt?: string; diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index a41873b3bf2..8a8b40bca9a 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -566,7 +566,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme const extensionTestsPath = originalFSPath(extensionTestsLocationURI); // Require the test runner via node require from the provided path - const testRunner: ITestRunner | INewTestRunner | undefined = await this._loadCommonJSModule(null, URI.file(extensionTestsPath), new ExtensionActivationTimesBuilder(false)); + const testRunner: ITestRunner | INewTestRunner | undefined = await this._loadCommonJSModule(null, extensionTestsLocationURI, new ExtensionActivationTimesBuilder(false)); if (!testRunner || typeof testRunner.run !== 'function') { throw new Error(nls.localize('extensionTestError', "Path {0} does not point to a valid extension test runner.", extensionTestsPath)); diff --git a/src/vs/workbench/api/common/extHostQuickOpen.ts b/src/vs/workbench/api/common/extHostQuickOpen.ts index 0d32f885bd7..41a6eaae090 100644 --- a/src/vs/workbench/api/common/extHostQuickOpen.ts +++ b/src/vs/workbench/api/common/extHostQuickOpen.ts @@ -68,11 +68,12 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx const instance = ++this._instances; const quickPickWidget = proxy.$show(instance, { - placeHolder: options && options.placeHolder, - matchOnDescription: options && options.matchOnDescription, - matchOnDetail: options && options.matchOnDetail, - ignoreFocusLost: options && options.ignoreFocusOut, - canPickMany: options && options.canPickMany + title: options?.title, + placeHolder: options?.placeHolder, + matchOnDescription: options?.matchOnDescription, + matchOnDetail: options?.matchOnDetail, + ignoreFocusLost: options?.ignoreFocusOut, + canPickMany: options?.canPickMany, }, token); const widgetClosedMarker = {}; diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts index 6ebbb92e442..fad39115832 100644 --- a/src/vs/workbench/api/worker/extHostExtensionService.ts +++ b/src/vs/workbench/api/worker/extHostExtensionService.ts @@ -11,6 +11,7 @@ import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterc import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ExtensionRuntime } from 'vs/workbench/api/common/extHostTypes'; import { timeout } from 'vs/base/common/async'; +import { MainContext, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol'; namespace TrustedFunction { @@ -68,6 +69,9 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { private _fakeModules?: WorkerRequireInterceptor; protected async _beforeAlmostReadyToRunExtensions(): Promise { + const mainThreadConsole = this._extHostContext.getProxy(MainContext.MainThreadConsole); + wrapConsoleMethods(mainThreadConsole); + // initialize API and register actors const apiFactory = this._instaService.invokeFunction(createApiFactoryAndRegisterActors); this._fakeModules = this._instaService.createInstance(WorkerRequireInterceptor, apiFactory, this._registry); @@ -167,3 +171,74 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { function ensureSuffix(path: string, suffix: string): string { return path.endsWith(suffix) ? path : path + suffix; } + +// copied from bootstrap-fork.js +function wrapConsoleMethods(service: MainThreadConsoleShape) { + wrap('info', 'log'); + wrap('log', 'log'); + wrap('warn', 'warn'); + wrap('error', 'error'); + + function wrap(method: 'error' | 'warn' | 'info' | 'log', severity: 'error' | 'warn' | 'log') { + console[method] = function () { + service.$logExtensionHostMessage({ type: '__$console', severity, arguments: safeToArray(arguments) }); + }; + } + + const MAX_LENGTH = 100000; + + function safeToArray(args: IArguments) { + const seen: any[] = []; + const argsArray = []; + + // Massage some arguments with special treatment + if (args.length) { + for (let i = 0; i < args.length; i++) { + + // Any argument of type 'undefined' needs to be specially treated because + // JSON.stringify will simply ignore those. We replace them with the string + // 'undefined' which is not 100% right, but good enough to be logged to console + if (typeof args[i] === 'undefined') { + args[i] = 'undefined'; + } + + // Any argument that is an Error will be changed to be just the error stack/message + // itself because currently cannot serialize the error over entirely. + else if (args[i] instanceof Error) { + const errorObj = args[i]; + if (errorObj.stack) { + args[i] = errorObj.stack; + } else { + args[i] = errorObj.toString(); + } + } + + argsArray.push(args[i]); + } + } + + try { + const res = JSON.stringify(argsArray, function (key, value) { + + // Objects get special treatment to prevent circles + if (value && typeof value === 'object') { + if (seen.indexOf(value) !== -1) { + return '[Circular]'; + } + + seen.push(value); + } + + return value; + }); + + if (res.length > MAX_LENGTH) { + return 'Output omitted for a large object that exceeds the limits'; + } + + return res; + } catch (error) { + return `Output omitted for an object that cannot be inspected ('${error.toString()}')`; + } + } +} diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts index a0df024be67..beb9467303d 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts @@ -5,24 +5,29 @@ import * as nls from 'vs/nls'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { URI } from 'vs/base/common/uri'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; -import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { DefaultSettingsEditorContribution } from 'vs/workbench/contrib/preferences/browser/preferencesEditor'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { Codicon } from 'vs/base/common/codicons'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; const transientWordWrapState = 'transientWordWrapState'; const isWordWrapMinifiedKey = 'isWordWrapMinified'; const isDominatedByLongLinesKey = 'isDominatedByLongLines'; +const CAN_TOGGLE_WORD_WRAP = new RawContextKey('canToggleWordWrap', false, true); +const EDITOR_WORD_WRAP = new RawContextKey('editorWordWrap', false, nls.localize('editorWordWrap', 'Whether the editor is currently using word wrapping.')); /** * State written/read by the toggle word wrap action and associated with a particular model. @@ -63,21 +68,13 @@ class ToggleWordWrapAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICodeEditor): void { - if (editor.getContribution(DefaultSettingsEditorContribution.ID)) { - // in the settings editor... - return; - } - if (!editor.hasModel()) { + if (!canToggleWordWrap(editor)) { return; } const codeEditorService = accessor.get(ICodeEditorService); const model = editor.getModel(); - if (!canToggleWordWrap(model.uri)) { - return; - } - // Read the current state const transientState = readTransientState(model, codeEditorService); @@ -137,25 +134,11 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution })); const ensureWordWrapSettings = () => { - if (this._editor.getContribution(DefaultSettingsEditorContribution.ID)) { - // in the settings editor... - return; - } - if (this._editor.isSimpleWidget) { - // in a simple widget... - return; - } - // Ensure correct word wrap settings - const newModel = this._editor.getModel(); - if (!newModel) { + if (!canToggleWordWrap(this._editor)) { return; } - if (!canToggleWordWrap(newModel.uri)) { - return; - } - - const transientState = readTransientState(newModel, this._codeEditorService); + const transientState = readTransientState(this._editor.getModel(), this._codeEditorService); // Apply the state try { @@ -175,13 +158,89 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution } } -function canToggleWordWrap(uri: URI): boolean { - if (!uri) { +function canToggleWordWrap(editor: ICodeEditor | null): editor is IActiveCodeEditor { + if (!editor) { return false; } - return (uri.scheme !== 'output'); + if (editor.getContribution(DefaultSettingsEditorContribution.ID)) { + // in the settings editor... + return false; + } + if (editor.isSimpleWidget) { + // in a simple widget... + return false; + } + // Ensure correct word wrap settings + const model = editor.getModel(); + if (!model) { + return false; + } + if (model.uri.scheme === 'output') { + // in output editor + return false; + } + return true; } +class EditorWordWrapContextKeyTracker implements IWorkbenchContribution { + + private readonly _canToggleWordWrap: IContextKey; + private readonly _editorWordWrap: IContextKey; + private _activeEditor: ICodeEditor | null; + private readonly _activeEditorListener: DisposableStore; + + constructor( + @IEditorService private readonly _editorService: IEditorService, + @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, + @IContextKeyService private readonly _contextService: IContextKeyService, + ) { + window.addEventListener('focus', () => this._update(), true); + window.addEventListener('blur', () => this._update(), true); + this._editorService.onDidActiveEditorChange(() => this._update()); + this._canToggleWordWrap = CAN_TOGGLE_WORD_WRAP.bindTo(this._contextService); + this._editorWordWrap = EDITOR_WORD_WRAP.bindTo(this._contextService); + this._activeEditor = null; + this._activeEditorListener = new DisposableStore(); + this._update(); + } + + private _update(): void { + const activeEditor = this._codeEditorService.getFocusedCodeEditor() || this._codeEditorService.getActiveCodeEditor(); + if (this._activeEditor === activeEditor) { + // no change + return; + } + this._activeEditorListener.clear(); + this._activeEditor = activeEditor; + + if (activeEditor) { + this._activeEditorListener.add(activeEditor.onDidChangeModel(() => this._updateFromCodeEditor())); + this._activeEditorListener.add(activeEditor.onDidChangeConfiguration((e) => { + if (e.hasChanged(EditorOption.wrappingInfo)) { + this._updateFromCodeEditor(); + } + })); + this._updateFromCodeEditor(); + } + } + + private _updateFromCodeEditor(): void { + if (!canToggleWordWrap(this._activeEditor)) { + return this._setValues(false, false); + } else { + const wrappingInfo = this._activeEditor.getOption(EditorOption.wrappingInfo); + this._setValues(true, wrappingInfo.wrappingColumn !== -1); + } + } + + private _setValues(canToggleWordWrap: boolean, isWordWrap: boolean): void { + this._canToggleWordWrap.set(canToggleWordWrap); + this._editorWordWrap.set(isWordWrap); + } +} + +const workbenchRegistry = Registry.as(Extensions.Workbench); +workbenchRegistry.registerWorkbenchContribution(EditorWordWrapContextKeyTracker, LifecyclePhase.Ready); registerEditorContribution(ToggleWordWrapController.ID, ToggleWordWrapController); @@ -221,7 +280,9 @@ 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'] }, "Toggle &&Word Wrap"), + toggled: EDITOR_WORD_WRAP, + precondition: CAN_TOGGLE_WORD_WRAP }, order: 1 }); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 5d544864fda..5ccfec7059d 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -2491,7 +2491,7 @@ registerThemingParticipant((theme, collector) => { 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 .cell.code { padding-top: ${MARKDOWN_CELL_TOP_MARGIN}px; }`); + 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-top: ${MARKDOWN_CELL_TOP_MARGIN}px; }`); collector.addRule(`.notebookOverlay .output { margin: 0px ${CELL_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_MARGIN * 2)}px); }`); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts index e1111a8887a..41cda48cb48 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts @@ -319,6 +319,7 @@ export class StatefulMarkdownCell extends Disposable { } this.templateData.container.classList.toggle('collapsed', false); + this.templateData.container.classList.toggle('markdown-cell-edit-mode', true); if (this.editor) { editorHeight = this.editor.getContentHeight(); @@ -401,6 +402,7 @@ export class StatefulMarkdownCell extends Disposable { DOM.hide(this.templateData.collapsedPart); DOM.show(this.markdownContainer); this.templateData.container.classList.toggle('collapsed', false); + this.templateData.container.classList.toggle('markdown-cell-edit-mode', false); this.renderedEditors.delete(this.viewCell); diff --git a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts index a41b38ef4db..8fb5da25bf3 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts @@ -30,6 +30,7 @@ import { Event } from 'vs/base/common/event'; import { IExternalUriOpenerService } from 'vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { ILogService } from 'vs/platform/log/common/log'; export const VIEWLET_ID = 'workbench.view.remote'; @@ -184,7 +185,8 @@ export class AutomaticPortForwarding extends Disposable implements IWorkbenchCon @IDebugService readonly debugService: IDebugService, @IRemoteAgentService readonly remoteAgentService: IRemoteAgentService, @ITunnelService readonly tunnelService: ITunnelService, - @IHostService readonly hostService: IHostService + @IHostService readonly hostService: IHostService, + @ILogService readonly logService: ILogService ) { super(); if (!this.environmentService.remoteAuthority) { @@ -196,15 +198,15 @@ export class AutomaticPortForwarding extends Disposable implements IWorkbenchCon Registry.as(ConfigurationExtensions.Configuration) .registerDefaultConfigurations([{ 'remote.autoForwardPortsSource': PORT_AUTO_SOURCE_SETTING_OUTPUT }]); this._register(new OutputAutomaticPortForwarding(terminalService, notificationService, openerService, externalOpenerService, - remoteExplorerService, configurationService, debugService, tunnelService, remoteAgentService, hostService, false)); + remoteExplorerService, configurationService, debugService, tunnelService, remoteAgentService, hostService, logService, false)); } else { const useProc = (this.configurationService.getValue(PORT_AUTO_SOURCE_SETTING) === PORT_AUTO_SOURCE_SETTING_PROCESS); if (useProc) { this._register(new ProcAutomaticPortForwarding(configurationService, remoteExplorerService, notificationService, - openerService, externalOpenerService, tunnelService, hostService)); + openerService, externalOpenerService, tunnelService, hostService, logService)); } this._register(new OutputAutomaticPortForwarding(terminalService, notificationService, openerService, externalOpenerService, - remoteExplorerService, configurationService, debugService, tunnelService, remoteAgentService, hostService, useProc)); + remoteExplorerService, configurationService, debugService, tunnelService, remoteAgentService, hostService, logService, useProc)); } }); } @@ -222,17 +224,22 @@ class OnAutoForwardedAction extends Disposable { private readonly openerService: IOpenerService, private readonly externalOpenerService: IExternalUriOpenerService, private readonly tunnelService: ITunnelService, - private readonly hostService: IHostService) { + private readonly hostService: IHostService, + private readonly logService: ILogService) { super(); this.lastNotifyTime = new Date(); this.lastNotifyTime.setFullYear(this.lastNotifyTime.getFullYear() - 1); } public async doAction(tunnels: RemoteTunnel[]): Promise { + this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) Starting action for ${tunnels[0]?.tunnelRemotePort}`); this.doActionTunnels = tunnels; const tunnel = await this.portNumberHeuristicDelay(); + this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) Heuristic chose ${tunnel?.tunnelRemotePort}`); if (tunnel) { - switch ((await this.remoteExplorerService.tunnelModel.getAttributes([tunnel.tunnelRemotePort]))?.get(tunnel.tunnelRemotePort)?.onAutoForward) { + const attributes = (await this.remoteExplorerService.tunnelModel.getAttributes([tunnel.tunnelRemotePort]))?.get(tunnel.tunnelRemotePort)?.onAutoForward; + this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) onAutoForward action is ${attributes}`); + switch (attributes) { case OnPortForward.OpenBrowser: { const address = makeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort); await OpenPortInBrowserAction.run(this.remoteExplorerService.tunnelModel, this.openerService, address); @@ -245,7 +252,9 @@ class OnAutoForwardedAction extends Disposable { } case OnPortForward.Silent: break; default: - if (Date.now() - this.lastNotifyTime.getTime() > OnAutoForwardedAction.NOTIFY_COOL_DOWN) { + const elapsed = new Date().getTime() - this.lastNotifyTime.getTime(); + this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) time elapsed since last notification ${elapsed} ms`); + if (elapsed > OnAutoForwardedAction.NOTIFY_COOL_DOWN) { await this.showNotification(tunnel); } } @@ -263,6 +272,7 @@ class OnAutoForwardedAction extends Disposable { private newerTunnel: RemoteTunnel | undefined; private async portNumberHeuristicDelay(): Promise { + this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) Starting heuristic delay`); if (!this.doActionTunnels || this.doActionTunnels.length === 0) { return; } @@ -270,14 +280,17 @@ class OnAutoForwardedAction extends Disposable { const firstTunnel = this.doActionTunnels.shift()!; // Heuristic. if (firstTunnel.tunnelRemotePort % 1000 === 0) { + this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) Heuristic chose tunnel because % 1000: ${firstTunnel.tunnelRemotePort}`); this.newerTunnel = firstTunnel; return firstTunnel; // 9229 is the node inspect port } else if (firstTunnel.tunnelRemotePort < 10000 && firstTunnel.tunnelRemotePort !== 9229) { + this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) Heuristic chose tunnel because < 10000: ${firstTunnel.tunnelRemotePort}`); this.newerTunnel = firstTunnel; return firstTunnel; } + this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) Waiting for "better" tunnel than ${firstTunnel.tunnelRemotePort}`); this.newerTunnel = undefined; return new Promise(resolve => { setTimeout(() => { @@ -391,10 +404,11 @@ class OutputAutomaticPortForwarding extends Disposable { readonly tunnelService: ITunnelService, private readonly remoteAgentService: IRemoteAgentService, readonly hostService: IHostService, + readonly logService: ILogService, readonly privilegedOnly: boolean ) { super(); - this.notifier = new OnAutoForwardedAction(notificationService, remoteExplorerService, openerService, externalOpenerService, tunnelService, hostService); + this.notifier = new OnAutoForwardedAction(notificationService, remoteExplorerService, openerService, externalOpenerService, tunnelService, hostService, logService); this._register(configurationService.onDidChangeConfiguration((e) => { if (e.affectsConfiguration(PORT_AUTO_FORWARD_SETTING)) { this.tryStartStopUrlFinder(); @@ -463,10 +477,11 @@ class ProcAutomaticPortForwarding extends Disposable { readonly openerService: IOpenerService, readonly externalOpenerService: IExternalUriOpenerService, readonly tunnelService: ITunnelService, - readonly hostService: IHostService + readonly hostService: IHostService, + readonly logService: ILogService ) { super(); - this.notifier = new OnAutoForwardedAction(notificationService, remoteExplorerService, openerService, externalOpenerService, tunnelService, hostService); + this.notifier = new OnAutoForwardedAction(notificationService, remoteExplorerService, openerService, externalOpenerService, tunnelService, hostService, logService); this._register(configurationService.onDidChangeConfiguration(async (e) => { if (e.affectsConfiguration(PORT_AUTO_FORWARD_SETTING)) { await this.startStopCandidateListener(); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 784a74d1990..c2ea0b5e9da 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -24,13 +24,14 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IPickOptions, IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { ILocalTerminalService } from 'vs/platform/terminal/common/terminal'; import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; import { FindInFilesCommand, IFindInFilesArgs } from 'vs/workbench/contrib/search/browser/searchActions'; import { Direction, IRemoteTerminalService, ITerminalInstance, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalQuickAccessProvider } from 'vs/workbench/contrib/terminal/browser/terminalQuickAccess'; -import { IRemoteTerminalAttachTarget, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_ACTION_CATEGORY, TERMINAL_COMMAND_ID, TERMINAL_VIEW_ID, TitleEventSource } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IRemoteTerminalAttachTarget, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, QUICK_LAUNCH_PROFILE_CHOICE, TERMINAL_ACTION_CATEGORY, TERMINAL_COMMAND_ID, TERMINAL_VIEW_ID, TitleEventSource } from 'vs/workbench/contrib/terminal/common/terminal'; import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; @@ -1440,6 +1441,7 @@ export function registerTerminalActions() { const terminalContributionService = accessor.get(ITerminalContributionService); const notificationService = accessor.get(INotificationService); const commandService = accessor.get(ICommandService); + const storageService = accessor.get(IStorageService); if (!item || !item.split) { return Promise.resolve(null); } @@ -1464,37 +1466,42 @@ export function registerTerminalActions() { // Remove 'New ' from the selected item to get the profile name const profileSelection = item.substring(4); - + const customType = terminalContributionService.terminalTypes.find(t => t.title === item); + if (customType) { + return commandService.executeCommand(customType.command); + } if (detectedProfiles) { let launchConfig = detectedProfiles?.find((profile: { profileName: string; }) => profile.profileName === profileSelection); if (launchConfig && !launchConfig.isWorkspaceProfile) { - const instance = terminalService.createTerminal({ executable: launchConfig.path, name: launchConfig.profileName, args: launchConfig.args }); + const instance = terminalService.createTerminal({ executable: launchConfig.path, args: launchConfig.args }); terminalService.setActiveInstance(instance); } else if (launchConfig && launchConfig.isWorkspaceProfile) { - notificationService.prompt(Severity.Info, `Do you allow this workspace to modify your terminal profile? ${item}`, - [{ - label: 'Allow', - run: () => { - const instance = terminalService.createTerminal({ executable: launchConfig?.path, name: launchConfig?.profileName, args: launchConfig?.args }); - terminalService.setActiveInstance(instance); - } - }, - { - label: 'Disallow', - run: () => { - const activeInstance = terminalService.getActiveInstance(); - if (activeInstance) { - terminalService.setActiveInstance(activeInstance); + if (!storageService.getBoolean(`${QUICK_LAUNCH_PROFILE_CHOICE}-${item}-${launchConfig.path}`, StorageScope.WORKSPACE, false)) { + notificationService.prompt(Severity.Info, `Do you allow this workspace to modify your terminal profile? ${item} with path ${launchConfig?.path}`, + [{ + label: 'Allow', + run: () => { + const instance = terminalService.createTerminal({ executable: launchConfig?.path, args: launchConfig?.args }); + terminalService.setActiveInstance(instance); + storageService.store(`${QUICK_LAUNCH_PROFILE_CHOICE}-${item}-${launchConfig?.path}`, true, StorageScope.WORKSPACE, StorageTarget.USER); } - } - }] - ); + }, + { + label: 'Disallow', + run: () => { + const activeInstance = terminalService.getActiveInstance(); + if (activeInstance) { + terminalService.setActiveInstance(activeInstance); + } + } + }] + ); + } else { + const instance = terminalService.createTerminal({ executable: launchConfig?.path, args: launchConfig?.args }); + terminalService.setActiveInstance(instance); + } } } else { - const customType = terminalContributionService.terminalTypes.find(t => t.title === item); - if (customType) { - return commandService.executeCommand(customType.command); - } console.warn(`Unmatched terminal item: "${item}"`); } return Promise.resolve(); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 05d556ea08a..9e63a22a34e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -151,7 +151,7 @@ export class TerminalService implements ITerminalService { if (e.affectsConfiguration('terminal.integrated.profiles.windows') || e.affectsConfiguration('terminal.integrated.profiles.osx') || e.affectsConfiguration('terminal.integrated.profiles.linux') || - e.affectsConfiguration('terminal.integrated.detectWslProfiles')) { + e.affectsConfiguration('terminal.integrated.quickLaunchWslProfiles')) { this._onProfilesConfigChanged.fire(); } }); @@ -559,16 +559,10 @@ export class TerminalService implements ITerminalService { public async initializeTerminals(): Promise { if (this._remoteTerminalsInitPromise) { await this._remoteTerminalsInitPromise; - - if (!this.terminalTabs.length) { - this.createTerminal(); - } } else if (this._localTerminalsInitPromise) { await this._localTerminalsInitPromise; - if (!this.terminalTabs.length) { - this.createTerminal(); - } - } else if (!this.terminalTabs.length) { + } + if (this.terminalTabs.length === 0 && this.isProcessSupportRegistered) { this.createTerminal(); } } diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 66f6022e5a9..d64ba7bae3a 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -102,7 +102,7 @@ export interface ITerminalConfiguration { windows: string[]; }; profiles: ITerminalProfiles; - detectWslProfiles: boolean; + quickLaunchWslProfiles: boolean; altClickMovesCursor: boolean; macOptionIsMeta: boolean; macOptionClickForcesSelection: boolean; @@ -233,8 +233,8 @@ export interface ITerminalProfile { } export const enum ProfileSource { - 'Git Bash', - 'PowerShell' + GitBash = 'Git Bash', + Pwsh = 'PowerShell' } export interface ITerminalExecutable { @@ -369,6 +369,8 @@ export enum TitleEventSource { Sequence } +export const QUICK_LAUNCH_PROFILE_CHOICE = 'workbench.action.terminal.profile.choice'; + export const enum TERMINAL_COMMAND_ID { FIND_NEXT = 'workbench.action.terminal.findNext', FIND_PREVIOUS = 'workbench.action.terminal.findPrevious', diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index 6e13c4950f5..d5618aaaf94 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -83,9 +83,9 @@ export const terminalConfiguration: IConfigurationNode = { 'terminal.integrated.profiles.windows': { markdownDescription: localize({ key: 'terminal.integrated.profiles.windows', - comment: ['{0}, {1}, {2}, and {3} are the `source`, `path`, `profileName`, and optional `args` settings keys'] + comment: ['{0}, {1}, {2}, and {3} are the `source`, `pathOrPaths`, `profileName`, and optional `args` settings keys'] }, - "The windows shell profiles to select from 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}, {2}, and optional {3}", '`source`', '`path`', '`profileName`', '`args`.'), + "The windows shell profiles to select from 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}, {2}, and optional {3}", '`source`', '`pathOrPaths`', '`profileName`', '`args`.'), type: 'object', default: { 'PowerShell': { @@ -118,49 +118,49 @@ export const terminalConfiguration: IConfigurationNode = { 'terminal.integrated.profiles.osx': { markdownDescription: localize({ key: 'terminal.integrated.profile.osx', - comment: ['{0}, {1}, and {2} are the `path`, `profileName`, and optional `args` settings keys'] + comment: ['{0}, {1}, and {2} are the `pathOrPaths`, `profileName`, and optional `args` settings keys'] }, - "The osx shell profiles to select from when creating a new terminal via the terminal dropdown. When set, these will override the default detected profiles. They are comprised of a {0}, {1}, and optional {2}", '`path`', '`profileName`', '`args`.'), + "The osx shell profiles to select from when creating a new terminal via the terminal dropdown. When set, these will override the default detected profiles. They are comprised of a {0}, {1}, and optional {2}", '`pathOrPaths`', '`profileName`', '`args`.'), type: 'object', default: { 'bash': { - path: 'bash' + pathOrPaths: 'bash' }, 'zsh': { - path: 'zsh' + pathOrPaths: 'zsh' }, 'fish': { - path: 'fish' + pathOrPaths: 'fish' }, 'tmux': { - path: 'tmux' + pathOrPaths: 'tmux' } }, }, 'terminal.integrated.profiles.linux': { markdownDescription: localize({ key: 'terminal.integrated.profile.linux', - comment: ['{0}, {1}, and {2} are the `path`, `profileName`, and optional `args` settings keys'] + comment: ['{0}, {1}, and {2} are the `pathOrPaths`, `profileName`, and optional `args` settings keys'] }, - "The linux shell profiles to select from when creating a new terminal via the terminal dropdown. When set, these will override the default detected profiles. They are comprised of a {0}, {1}, and optional {2}", '`path`', '`profileName`', '`args`.'), + "The linux shell profiles to select from when creating a new terminal via the terminal dropdown. When set, these will override the default detected profiles. They are comprised of a {0}, {1}, and optional {2}", '`pathOrPaths`', '`profileName`', '`args`.'), type: 'object', default: { 'bash': { - path: 'bash' + pathOrPaths: 'bash' }, 'zsh': { - path: 'zsh' + pathOrPaths: 'zsh' }, 'fish': { - path: 'fish' + pathOrPaths: 'fish' }, 'tmux': { - path: 'tmux' + pathOrPaths: 'tmux' } } }, - 'terminal.integrated.detectWslProfiles': { - description: localize('terminal.integrated.detectWslProfiles', 'Controls whether or not WSL distros are detected as default profiles'), + 'terminal.integrated.quickLaunchWslProfiles': { + description: localize('terminal.integrated.quickLaunchWslProfiles', 'Controls whether or not WSL distros are shown in the quick launch dropdown'), type: 'boolean', default: true }, diff --git a/src/vs/workbench/contrib/terminal/node/terminalProfiles.ts b/src/vs/workbench/contrib/terminal/node/terminalProfiles.ts index a68122140d8..eb7c7a1322a 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalProfiles.ts +++ b/src/vs/workbench/contrib/terminal/node/terminalProfiles.ts @@ -28,10 +28,10 @@ interface IPotentialTerminalProfile { } export function detectAvailableProfiles(quickLaunchOnly: boolean, logService?: ILogService, config?: ITerminalConfiguration | ITestTerminalConfig, variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder, statProvider?: IStatProvider): Promise { - return platform.isWindows ? detectAvailableWindowsProfiles(quickLaunchOnly, logService, config?.detectWslProfiles, config?.profiles?.windows, variableResolver, workspaceFolder, statProvider) : detectAvailableUnixProfiles(quickLaunchOnly, platform.isMacintosh ? config?.profiles?.osx : config?.profiles?.linux); + return platform.isWindows ? detectAvailableWindowsProfiles(quickLaunchOnly, logService, config?.quickLaunchWslProfiles, config?.profiles?.windows, variableResolver, workspaceFolder, statProvider) : detectAvailableUnixProfiles(quickLaunchOnly, platform.isMacintosh ? config?.profiles?.osx : config?.profiles?.linux); } -async function detectAvailableWindowsProfiles(quickLaunchOnly: boolean, logService?: ILogService, detectWslProfiles?: boolean, configProfiles?: any, variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder, statProvider?: IStatProvider): Promise { +async function detectAvailableWindowsProfiles(quickLaunchOnly: boolean, logService?: ILogService, quickLaunchWslProfiles?: boolean, configProfiles?: any, variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder, statProvider?: IStatProvider): 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 @@ -69,7 +69,7 @@ async function detectAvailableWindowsProfiles(quickLaunchOnly: boolean, logServi ], args: ['-l'] }, - ... await getWslProfiles(`${system32Path}\\${useWSLexe ? 'wsl.exe' : 'bash.exe'}`, detectWslProfiles, logService), + ... await getWslProfiles(`${system32Path}\\${useWSLexe ? 'wsl.exe' : 'bash.exe'}`, quickLaunchWslProfiles, logService), ... await getPowershellProfiles() ]; @@ -150,6 +150,10 @@ async function detectAvailableWindowsProfiles(quickLaunchOnly: boolean, logServi if (validProfiles.find(p => p.path.endsWith('pwsh.exe'))) { validProfiles = validProfiles.filter(p => p.profileName !== 'Windows PowerShell'); } + + if (quickLaunchWslProfiles) { + validProfiles.push(...detectedProfiles.filter(p => p.path.endsWith('wsl.exe'))); + } return validProfiles; } @@ -162,33 +166,33 @@ async function getPowershellProfiles(): Promise { return profiles; } -async function getWslProfiles(wslPath: string, detectWslProfiles?: boolean, logService?: ILogService): Promise { +async function getWslProfiles(wslPath: string, quickLaunchWslProfiles?: boolean, logService?: ILogService): Promise { let profiles: IPotentialTerminalProfile[] = []; - if (detectWslProfiles) { - const distroOutput = await new Promise(r => cp.exec('wsl.exe -l', (err, stdout) => err ? logService?.trace('problem occurred when getting wsl distros', err) : r(stdout))); + if (quickLaunchWslProfiles) { + const distroOutput = await new Promise((resolve, reject) => { + cp.exec('wsl.exe -l', (err, stdout) => { + if (err) { + return reject('Problem occurred when getting wsl distros'); + } + resolve(stdout); + }); + }); if (distroOutput) { let regex = new RegExp(/[\r?\n]/); - let distroNames = Buffer.from(distroOutput).toString('utf8').split(regex).filter(t => t.trim().length > 0 && t !== ''); + let distroNames = distroOutput.split(regex).filter(t => t.trim().length > 0 && t !== ''); // don't need the Windows Subsystem for Linux Distributions header distroNames.shift(); - for (const distroName of distroNames) { - let s = ''; - let counter = 0; - for (const c of Array.from(distroName)) { - if (counter % 2 === 1) { - // every other character is junk / a rectangle - s += c; - } - counter++; - } - if (s.endsWith('(Default)')) { - // Ubuntu (Default) -> Ubuntu bc (Default) won't work - s = s.substring(0, s.length - 10); - } + for (let distroName of distroNames) { + // HACK: For some reason wsl.exe -l returns the string in an encoding where each + // character takes up 2 bytes, it's unclear how to decode this properly so instead + // we expect ascii and just remove all NUL chars + distroName = distroName + .replace(/\u0000/g, '') + .replace(/ \(Default\)$/, ''); // docker-desktop-data is used by docker-desktop to store container images and isn't a valid profile type - if (s !== '' && s !== 'docker-desktop-data') { - let profile = { profileName: `${s} (WSL)`, paths: [wslPath], args: [`-d`, `${s}`] }; + if (distroName !== '' && distroName !== 'docker-desktop-data') { + const profile = { profileName: `${distroName} (WSL)`, paths: [wslPath], args: [`-d`, `${distroName}`] }; profiles.push(profile); } } @@ -201,23 +205,29 @@ async function getWslProfiles(wslPath: string, detectWslProfiles?: boolean, logS async function detectAvailableUnixProfiles(quickLaunchOnly?: boolean, configProfiles?: any): Promise { const contents = await fs.promises.readFile('/etc/shells', 'utf8'); const profiles = contents.split('\n').filter(e => e.trim().indexOf('#') !== 0 && e.trim().length > 0); - const detectedProfiles = profiles.map(e => { - return { - profileName: basename(e), - path: e - }; - }); + + let detectedProfiles: ITerminalProfile[] = []; + let quickLaunchProfiles: ITerminalProfile[] = []; + for (const profile of profiles) { + detectedProfiles.push({ profileName: basename(profile), path: profile }); + // choose only the first + if (!quickLaunchProfiles.find(p => p.profileName === basename(profile))) { + quickLaunchProfiles.push({ profileName: basename(profile), path: profile }); + } + } + if (!quickLaunchOnly) { return detectedProfiles; } + const validProfiles: ITerminalProfile[] = []; for (const [profileName, value] of Object.entries(configProfiles)) { if ((value as ITerminalExecutable).pathOrPaths) { const configProfile = (value as ITerminalExecutable); - const path = configProfile.pathOrPaths; - if (Array.isArray(path)) { - for (const possiblePath of path) { + const pathOrPaths = configProfile.pathOrPaths; + if (Array.isArray(pathOrPaths)) { + for (const possiblePath of pathOrPaths) { const profile = detectedProfiles.find(p => p.path.endsWith(possiblePath)); if (profile) { validProfiles.push({ profileName, path: profile.path }); @@ -225,7 +235,7 @@ async function detectAvailableUnixProfiles(quickLaunchOnly?: boolean, configProf } } } else { - const profile = detectedProfiles.find(p => p.path.endsWith(path)); + const profile = detectedProfiles.find(p => p.path.endsWith(pathOrPaths)); if (profile) { validProfiles.push({ profileName, path: profile.path }); } diff --git a/src/vs/workbench/contrib/terminal/test/node/terminalProfiles.test.ts b/src/vs/workbench/contrib/terminal/test/node/terminalProfiles.test.ts index 575f90e6ca7..32bf923414b 100644 --- a/src/vs/workbench/contrib/terminal/test/node/terminalProfiles.test.ts +++ b/src/vs/workbench/contrib/terminal/test/node/terminalProfiles.test.ts @@ -4,63 +4,67 @@ *--------------------------------------------------------------------------------------------*/ // import * as assert from 'assert'; +import assert = require('assert'); import { isWindows } from 'vs/base/common/platform'; -import { ITerminalProfiles } from 'vs/workbench/contrib/terminal/common/terminal'; -// import { detectAvailableProfiles, IStatProvider } from 'vs/workbench/contrib/terminal/node/terminalProfiles'; +import { ITerminalProfiles, ProfileSource } from 'vs/workbench/contrib/terminal/common/terminal'; +import { detectAvailableProfiles, IStatProvider } from 'vs/workbench/contrib/terminal/node/terminalProfiles'; export interface ITestTerminalConfig { profiles: ITerminalProfiles; - detectWslProfiles: boolean + quickLaunchWslProfiles: boolean } suite('Workbench - TerminalProfiles', () => { suite('detectAvailableProfiles', () => { if (isWindows) { suite('detectAvailableWindowsProfiles', async () => { - // test('should detect cmd prompt', async () => { - // const _paths = ['C:\\WINDOWS\\System32\\cmd.exe']; - // let config: ITestTerminalConfig = { - // profiles: { - // windows: { - // 'Command Prompt': { path: _paths } - // } - // }, - // detectWslProfiles: false - // }; - // const profiles = await detectAvailableProfiles(true, undefined, config, undefined, undefined, createStatProvider(_paths)); - // const expected = [{ profileName: 'Command Prompt', path: _paths[0] }]; - // assert.deepStrictEqual(expected, profiles); - // }); test('should detect Git Bash and provide login args', async () => { - // const _paths = [`C:\\Program Files\\Git\\bin\\bash.exe`]; - // let config: ITestTerminalConfig = { - // profiles: { - // windows: { - // 'Git Bash': { - // source: ProfileSource['Git Bash'] - // }, - // }, - // linux: {}, - // osx: {} - // }, - // detectWslProfiles: false - // }; - // const profiles = await detectAvailableProfiles(true, undefined, config, undefined, undefined, createStatProvider(_paths)); - // const expected = [{ profileName: 'Git Bash', path: _paths[0], args: ['--login'] }]; - // assert.deepStrictEqual(profiles, expected); + const _paths = [`C:\\Program Files\\Git\\bin\\bash.exe`]; + let config: ITestTerminalConfig = { + profiles: { + windows: { + 'Git Bash': { source: ProfileSource.GitBash } + }, + linux: {}, + osx: {} + }, + quickLaunchWslProfiles: false + }; + const profiles = await detectAvailableProfiles(true, undefined, config, undefined, undefined, createStatProvider(_paths)); + const expected = [{ profileName: 'Git Bash', path: _paths[0], args: ['--login'] }]; + assert.deepStrictEqual(profiles, expected); }); - }); + // test('should detect cmd prompt', async () => { + // const _paths = ['C:\\WINDOWS\\System32\\cmd.exe']; + // let config: ITestTerminalConfig = { + // profiles: { + // windows: { + // 'Command Prompt': { pathOrPaths: _paths } + // }, + // linux: {}, + // osx: {}, + // }, + // quickLaunchWslProfiles: false + // }; + // const profiles = await detectAvailableProfiles(true, undefined, config, undefined, undefined, createStatProvider(_paths)); + // const expected = [{ profileName: 'Command Prompt', path: _paths[0] }]; + // assert.deepStrictEqual(expected, profiles); + // }); + } + ); } + }); + + function createStatProvider(expectedPaths: string[]): IStatProvider { + const provider = { + stat(path: string) { + return expectedPaths.includes(path); + }, + lstat(path: string) { + return expectedPaths.includes(path); + } + }; + return provider; + } }); -// function createStatProvider(expectedPaths: string[]): IStatProvider { -// const provider = { -// stat(path: string) { -// return expectedPaths.includes(path); -// }, -// lstat(path: string) { -// return expectedPaths.includes(path); -// } -// }; -// return provider; -// } diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css index 698b148e147..01cdbfb4b6a 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css @@ -111,9 +111,9 @@ } .monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide.categories .category-title { - margin-bottom: 4px; + margin: 2px 0 8px; + font-size: 13px; font-weight: 500; - margin-top: 0; } .monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide.categories .category-description-container { @@ -134,7 +134,7 @@ list-style: none; margin: 0; line-height: 24px; - padding-left: 10px; + padding-left: 0; } .monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide.categories .categories-split-view li { @@ -154,12 +154,16 @@ top: 3px; } +.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide.categories .categories-split-view .start-container .codicon { + left: 1px; +} + .monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide.categories .categories-split-view .keybinding-label { padding-left: 1em; } .monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide.categories .progress-bar-outer { - height: 8px; + height: 4px; border-radius: 4px; margin-top: 4px; } @@ -188,8 +192,9 @@ font-size: 13px; box-sizing: border-box; line-height: normal; - margin-bottom: 6px; - padding: 6px; + margin-bottom: 8px; + padding: 8px 12px 12px; + left: 1px; text-align: left; display: flex; } @@ -200,15 +205,14 @@ } .monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .codicon { - margin-right: 10px; - margin-left: 10px; font-size: 20px; } .monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .codicon.hide-category-button { position: absolute; - right: -6px; - font-size: 12px; + top: 8px; + right: 8px; + font-size: 16px; padding-right: 0; } @@ -250,8 +254,8 @@ } .monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide.detail .getting-started-category .codicon { - margin-left:0; - font-size: 22pt; + margin-right: 8px; + font-size: 28px; } .monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide.detail .getting-started-detail-columns { @@ -465,3 +469,15 @@ top: -2px; left: 5px; } + +.monaco-workbench .part.editor > .content .gettingStartedContainer .getting-started-category .codicon { + top: 0; +} + +.monaco-workbench .part.editor > .content .gettingStartedContainer .codicon-close { + visibility: hidden; +} + +.monaco-workbench .part.editor > .content .gettingStartedContainer .getting-started-category:hover .codicon-close { + visibility: visible; +} diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts index c49b38f242c..c4a8e4384de 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts @@ -12,7 +12,7 @@ import { assertIsDefined } from 'vs/base/common/types'; import { $, addDisposableListener, Dimension, reset } from 'vs/base/browser/dom'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IProductService } from 'vs/platform/product/common/productService'; -import { IGettingStartedCategoryWithProgress, IGettingStartedService } from 'vs/workbench/services/gettingStarted/common/gettingStartedService'; +import { IGettingStartedCategory, IGettingStartedCategoryDescriptor, IGettingStartedCategoryWithProgress, IGettingStartedService } from 'vs/workbench/services/gettingStarted/common/gettingStartedService'; import { IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { welcomePageBackground, welcomePageProgressBackground, welcomePageProgressForeground, welcomePageTileBackground, welcomePageTileHoverBackground } from 'vs/workbench/contrib/welcome/page/browser/welcomePageColors'; import { activeContrastBorder, buttonBackground, buttonForeground, buttonHoverBackground, contrastBorder, descriptionForeground, focusBorder, foreground, textLinkActiveForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; @@ -27,7 +27,6 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Schemas } from 'vs/base/common/network'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IGettingStartedCategory, IGettingStartedCategoryDescriptor } from 'vs/workbench/services/gettingStarted/common/gettingStartedRegistry'; import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService'; import { IRecentFolder, IRecentlyOpened, IRecentWorkspace, isRecentFolder, isRecentWorkspace, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; @@ -39,6 +38,7 @@ import { splitName } from 'vs/base/common/labels'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { coalesce } from 'vs/base/common/arrays'; import { isMacintosh } from 'vs/base/common/platform'; + const SLIDE_TRANSITION_TIME_MS = 250; const configurationKey = 'workbench.startupEditor'; @@ -155,7 +155,33 @@ export class GettingStartedPage extends EditorPane { this.buildCategoriesSlide(); })); - this._register(this.gettingStartedService.onDidAddCategory(category => console.log('added new category', category, 'that isnt being rendered yet'))); + this._register(this.gettingStartedService.onDidChangeTask(task => { + const ourCategory = this.gettingStartedCategories.find(c => c.id === task.category); + if (!ourCategory || ourCategory.content.type === 'startEntry') { + console.error('Attempting to modify category that does not exist or is invlid type', task); + return; + } + const ourTask = ourCategory.content.items.find(item => item.id === task.id); + if (!ourTask) { + console.error('Attempting to modify task that cannot be found', task); + return; + } + ourTask.title = task.title; + ourTask.description = task.description; + ourTask.media.path = task.media.path; + })); + + this._register(this.gettingStartedService.onDidChangeCategory(category => { + const ourCategory = this.gettingStartedCategories.find(c => c.id === category.id); + if (!ourCategory) { + console.error('Attempting to modify category that does not exist or is invlid type', category); + return; + } + + ourCategory.title = category.title; + ourCategory.description = category.description; + })); + this._register(this.gettingStartedService.onDidProgressTask(task => { const category = this.gettingStartedCategories.find(category => category.id === task.category); if (!category) { throw Error('Could not find category with ID: ' + task.category); } @@ -709,7 +735,7 @@ export class GettingStartedPage extends EditorPane { const keybindingLabel = (task.button.command && this.getKeybindingLabel(task.button.command)); if (keybindingLabel) { - taskDescription.appendChild($('span.shortcut-message', {}, 'Pro Tip: Use keyboard shortcut ', $('span.keybinding', {}, keybindingLabel))); + taskDescription.appendChild($('span.shortcut-message', {}, 'Tip: Use keyboard shortcut ', $('span.keybinding', {}, keybindingLabel))); } return $('button.getting-started-task', @@ -852,7 +878,7 @@ registerThemingParticipant((theme, collector) => { const iconColor = theme.getColor(textLinkForeground); if (iconColor) { - collector.addRule(`.monaco-workbench .part.editor > .content .gettingStartedContainer .getting-started-category .codicon { color: ${iconColor} }`); + collector.addRule(`.monaco-workbench .part.editor > .content .gettingStartedContainer .getting-started-category .codicon:not(.codicon-close) { color: ${iconColor} }`); collector.addRule(`.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide.detail .getting-started-task .codicon.complete { color: ${iconColor} } `); collector.addRule(`.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide.detail .getting-started-task.expanded .codicon { color: ${iconColor} } `); } @@ -892,18 +918,18 @@ registerThemingParticipant((theme, collector) => { const link = theme.getColor(textLinkForeground); if (link) { - collector.addRule(`.monaco-workbench .part.editor > .content .gettingStartedContainer a { color: ${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}; }`); } const activeLink = theme.getColor(textLinkActiveForeground); if (activeLink) { - collector.addRule(`.monaco-workbench .part.editor > .content .gettingStartedContainer a:hover, + collector.addRule(`.monaco-workbench .part.editor > .content .gettingStartedContainer a:not(.codicon-close):hover, .monaco-workbench .part.editor > .content .gettingStartedContainer a:active { color: ${activeLink}; }`); } const focusColor = theme.getColor(focusBorder); if (focusColor) { - collector.addRule(`.monaco-workbench .part.editor > .content .gettingStartedContainer a:focus { outline-color: ${focusColor}; }`); + collector.addRule(`.monaco-workbench .part.editor > .content .gettingStartedContainer a:not(.codicon-close):focus { outline-color: ${focusColor}; }`); } const border = theme.getColor(contrastBorder); if (border) { diff --git a/src/vs/workbench/services/experiment/common/experimentService.ts b/src/vs/workbench/services/experiment/common/experimentService.ts index 270c3aaa872..87ce12bd485 100644 --- a/src/vs/workbench/services/experiment/common/experimentService.ts +++ b/src/vs/workbench/services/experiment/common/experimentService.ts @@ -185,6 +185,8 @@ export class ExperimentService implements ITASExperimentService { private telemetry: ExperimentServiceTelemetry | undefined; private static MEMENTO_ID = 'experiment.service.memento'; + private overrideInitDelay: Promise; + private get experimentsEnabled(): boolean { return this.configurationService.getValue('workbench.enableExperiments') === true; } @@ -199,9 +201,18 @@ export class ExperimentService implements ITASExperimentService { if (productService.tasConfig && this.experimentsEnabled && this.telemetryService.isOptedIn) { this.tasClient = this.setupTASClient(); } + + const overrideDelay = this.configurationService.getValue('tasTreatmentOverrideDelay') ?? 2000; + this.overrideInitDelay = new Promise(resolve => setTimeout(resolve, overrideDelay)); } async getTreatment(name: string): Promise { + const override = this.configurationService.getValue('tasTreatmentOverrides.' + name); + if (override !== undefined) { + await this.overrideInitDelay; + return override as T; + } + const startSetup = Date.now(); if (!this.tasClient) { diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts index 1a198ff62e6..681e77fa6c7 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts @@ -357,7 +357,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost appUriScheme: this._productService.urlProtocol, appLanguage: platform.language, extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI, - extensionTestsLocationURI: undefined, // never run extension tests in web worker extension host + extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI, globalStorageHome: this._environmentService.globalStorageHome, workspaceStorageHome: this._environmentService.workspaceStorageHome, webviewResourceRoot: this._environmentService.webviewResourceRoot, diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts index dce8ded86a2..f05902b8399 100644 --- a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts @@ -32,6 +32,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { ExtensionKindController } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Schemas } from 'vs/base/common/network'; +import { URI } from 'vs/base/common/uri'; const hasOwnProperty = Object.hasOwnProperty; const NO_OP_VOID_PROMISE = Promise.resolve(undefined); @@ -428,18 +429,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx return; } - // TODO: Use `this._registry` and `this._runningLocation` to better determine which extension host should launch the test runner - let extensionHostManager: ExtensionHostManager | null = null; - if (this._environmentService.extensionTestsLocationURI.scheme === Schemas.vscodeRemote) { - extensionHostManager = this._getExtensionHostManager(ExtensionHostKind.Remote); - } - if (!extensionHostManager) { - // When a debugger attaches to the extension host, it will surface all console.log messages from the extension host, - // but not necessarily from the window. So it would be best if any errors get printed to the console of the extension host. - // That is why here we use the local process extension host even for non-file URIs - extensionHostManager = this._getExtensionHostManager(ExtensionHostKind.LocalProcess); - } - + const extensionHostManager = this.findTestExtensionHost(this._environmentService.extensionTestsLocationURI); if (!extensionHostManager) { const msg = nls.localize('extensionTestError', "No extension host found that can launch the test runner at {0}.", this._environmentService.extensionTestsLocationURI.toString()); console.error(msg); @@ -447,6 +437,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx return; } + let exitCode: number; try { exitCode = await extensionHostManager.extensionTestsExecute(); @@ -459,6 +450,40 @@ export abstract class AbstractExtensionService extends Disposable implements IEx this._onExtensionHostExit(exitCode); } + private findTestExtensionHost(testLocation: URI): ExtensionHostManager | undefined | null { + let extensionHostKind: ExtensionHostKind | undefined; + + for (const extension of this._registry.getAllExtensionDescriptions()) { + if (isEqualOrParent(testLocation, extension.extensionLocation)) { + const runningLocation = this._runningLocation.get(ExtensionIdentifier.toKey(extension.identifier)); + if (runningLocation === ExtensionRunningLocation.LocalProcess) { + extensionHostKind = ExtensionHostKind.LocalProcess; + } else if (runningLocation === ExtensionRunningLocation.LocalWebWorker) { + extensionHostKind = ExtensionHostKind.LocalWebWorker; + } else if (runningLocation === ExtensionRunningLocation.Remote) { + extensionHostKind = ExtensionHostKind.Remote; + } + break; + } + } + if (extensionHostKind === undefined) { + // not sure if we should support that, but it was possible to have an test outside an extension + + if (testLocation.scheme === Schemas.vscodeRemote) { + extensionHostKind = ExtensionHostKind.Remote; + } else { + // When a debugger attaches to the extension host, it will surface all console.log messages from the extension host, + // but not necessarily from the window. So it would be best if any errors get printed to the console of the extension host. + // That is why here we use the local process extension host even for non-file URIs + extensionHostKind = ExtensionHostKind.LocalProcess; + } + } + if (extensionHostKind !== undefined) { + return this._getExtensionHostManager(extensionHostKind); + } + return undefined; + } + private _releaseBarrier(): void { this._installedExtensionsReady.open(); this._onDidRegisterExtensions.fire(undefined); diff --git a/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts b/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts index a3c7fcf9ce1..011bd05b6d3 100644 --- a/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts +++ b/src/vs/workbench/services/gettingStarted/common/gettingStartedContent.ts @@ -14,7 +14,7 @@ const beginnerIcon = registerIcon('getting-started-beginner', Codicon.lightbulb, const codespacesIcon = registerIcon('getting-started-codespaces', Codicon.github, localize('getting-started-codespaces-icon', "Icon used for the codespaces category of getting started")); -type GettingStartedItem = { +export type BuiltinGettingStartedItem = { id: string title: string, description: string, @@ -26,30 +26,20 @@ type GettingStartedItem = { media: { type: 'image', path: string | { hc: string, light: string, dark: string }, altText: string }, }; -type GettingStartedCategory = { +export type BuiltinGettingStartedCategory = { id: string title: string, description: string, icon: ThemeIcon, when?: string, content: - | { type: 'items', items: GettingStartedItem[] } + | { type: 'items', items: BuiltinGettingStartedItem[] } | { type: 'startEntry', command: string } }; -type GettingStartedContent = GettingStartedCategory[]; +type GettingStartedContent = BuiltinGettingStartedCategory[]; export const content: GettingStartedContent = [ - // { - // id: 'topLevelCommandPalette', - // title: localize('gettingStarted.commandPalette.title', "Command Palette"), - // description: localize('gettingStarted.commandPalette.description', "The one keybinding to show you everything VS Code can do."), - // icon: Codicon.symbolColor, - // content: { - // type: 'startEntry', - // command: 'workbench.action.showCommands', - // } - // }, { id: 'topLevelNewFile', title: localize('gettingStarted.newFile.title', "New File"), @@ -104,13 +94,13 @@ export const content: GettingStartedContent = [ } }, { - id: 'topLevelSeeExtensions', - title: localize('gettingStarted.languageSupport.title', "Install Language Support"), - description: localize('gettingStarted.languageSupport.description', "Want even more features? Install extensions to add support for languages like Python, C, or Java."), - icon: Codicon.extensions, + id: 'topLevelCommandPalette', + title: localize('gettingStarted.topLevelCommandPalette.title', "Run a Command..."), + description: localize('gettingStarted.topLevelCommandPalette.description', "Use the command palette to view and run all of vscode's commands"), + icon: Codicon.symbolColor, content: { type: 'startEntry', - command: 'workbench.extensions.action.showPopularExtensions', + command: 'workbench.action.showCommands', } }, { diff --git a/src/vs/workbench/services/gettingStarted/common/gettingStartedRegistry.ts b/src/vs/workbench/services/gettingStarted/common/gettingStartedRegistry.ts deleted file mode 100644 index c1c1c46eaee..00000000000 --- a/src/vs/workbench/services/gettingStarted/common/gettingStartedRegistry.ts +++ /dev/null @@ -1,172 +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, Event } from 'vs/base/common/event'; -import { FileAccess } from 'vs/base/common/network'; -import { URI } from 'vs/base/common/uri'; -import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { content } from 'vs/workbench/services/gettingStarted/common/gettingStartedContent'; - -export const enum GettingStartedCategory { - Beginner = 'Beginner', - Intermediate = 'Intermediate', - Advanced = 'Advanced' -} - -export interface IGettingStartedTask { - id: string, - title: string, - description: string, - category: GettingStartedCategory | string, - when: ContextKeyExpression, - order: number, - button: - | { title: string, command?: never, link: string } - | { title: string, command: string, link?: never }, - doneOn: { commandExecuted: string, eventFired?: never } | { eventFired: string, commandExecuted?: never, } - media: { type: 'image', path: { hc: URI, light: URI, dark: URI }, altText: string }, -} - -export interface IGettingStartedCategoryDescriptor { - id: GettingStartedCategory | string - title: string - description: string - icon: - | { type: 'icon', icon: ThemeIcon } - | { type: 'image', path: string } - when: ContextKeyExpression - content: - | { type: 'items' } - | { type: 'startEntry', command: string } -} - -export interface IGettingStartedCategory { - id: GettingStartedCategory | string - title: string - description: string - icon: - | { type: 'icon', icon: ThemeIcon } - | { type: 'image', path: string } - when: ContextKeyExpression - content: - | { type: 'items', items: IGettingStartedTask[] } - | { type: 'startEntry', command: string } -} - -export interface IGettingStartedRegistry { - onDidAddCategory: Event - onDidAddTask: Event - - registerTask(task: IGettingStartedTask): IGettingStartedTask; - getTask(id: string): IGettingStartedTask - - registerCategory(categoryDescriptor: IGettingStartedCategoryDescriptor): void - getCategory(id: GettingStartedCategory | string): Readonly | undefined - - getCategories(): readonly Readonly[] -} - -export class GettingStartedRegistryImpl implements IGettingStartedRegistry { - private readonly _onDidAddTask = new Emitter(); - onDidAddTask: Event = this._onDidAddTask.event; - private readonly _onDidAddCategory = new Emitter(); - onDidAddCategory: Event = this._onDidAddCategory.event; - - private readonly gettingStartedContributions = new Map(); - private readonly tasks = new Map(); - - public registerTask(task: IGettingStartedTask): IGettingStartedTask { - const category = this.gettingStartedContributions.get(task.category); - if (!category) { throw Error('Registering getting started task to category that does not exist (' + task.category + ')'); } - if (category.content.type !== 'items') { throw Error('Registering getting started task to category that is not of `items` type (' + task.category + ')'); } - if (this.tasks.has(task.id)) { throw Error('Attempting to register task with id ' + task.id + ' twice. Second is dropped.'); } - this.tasks.set(task.id, task); - category.content.items.push(task); - this._onDidAddTask.fire(task); - return task; - } - - public registerCategory(categoryDescriptor: IGettingStartedCategoryDescriptor): void { - const oldCategory = this.gettingStartedContributions.get(categoryDescriptor.id); - if (oldCategory) { - console.error(`Skipping attempt to overwrite getting started category. (${categoryDescriptor})`); - return; - } - - const category: IGettingStartedCategory = { - ...categoryDescriptor, - content: categoryDescriptor.content.type === 'items' - ? { type: 'items', items: [] } - : categoryDescriptor.content - }; - - this.gettingStartedContributions.set(categoryDescriptor.id, category); - this._onDidAddCategory.fire(category); - } - - public getCategory(id: GettingStartedCategory | string): Readonly | undefined { - return this.gettingStartedContributions.get(id); - } - - public getTask(id: string): IGettingStartedTask { - const task = this.tasks.get(id); - if (!task) { throw Error('Attempting to access task which does not exist in registry ' + id); } - return task; - } - - public getCategories(): readonly Readonly[] { - return [...this.gettingStartedContributions.values()]; - - } -} - -export const GettingStartedRegistryID = 'GettingStartedRegistry'; -const registryImpl = new GettingStartedRegistryImpl(); - -content.forEach(category => { - - registryImpl.registerCategory({ - ...category, - icon: { type: 'icon', icon: category.icon }, - when: ContextKeyExpr.deserialize(category.when) ?? ContextKeyExpr.true() - }); - - if (category.content.type === 'items') { - const convertPaths = (path: string | { hc: string, dark: string, light: string }): { hc: URI, dark: URI, light: URI } => { - const convertPath = (path: string) => path.startsWith('https://') - ? URI.parse(path, true) - : FileAccess.asBrowserUri('vs/workbench/services/gettingStarted/common/media/' + path, require); - if (typeof path === 'string') { - const converted = convertPath(path); - return { hc: converted, dark: converted, light: converted }; - } else { - return { - hc: convertPath(path.hc), - light: convertPath(path.light), - dark: convertPath(path.dark) - }; - } - }; - - category.content.items.forEach((item, index) => { - registryImpl.registerTask({ - ...item, - category: category.id, - order: index, - when: ContextKeyExpr.deserialize(item.when) ?? ContextKeyExpr.true(), - media: { - type: item.media.type, - altText: item.media.altText, - path: convertPaths(item.media.path) - } - }); - }); - } -}); - -Registry.add(GettingStartedRegistryID, registryImpl); -export const GettingStartedRegistry: IGettingStartedRegistry = Registry.as(GettingStartedRegistryID); diff --git a/src/vs/workbench/services/gettingStarted/common/gettingStartedService.ts b/src/vs/workbench/services/gettingStarted/common/gettingStartedService.ts index 277520be3bc..bd4093cb664 100644 --- a/src/vs/workbench/services/gettingStarted/common/gettingStartedService.ts +++ b/src/vs/workbench/services/gettingStarted/common/gettingStartedService.ts @@ -3,15 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, 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 { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IGettingStartedTask, GettingStartedRegistry, IGettingStartedCategory, } from 'vs/workbench/services/gettingStarted/common/gettingStartedRegistry'; 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, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, ContextKeyExpression, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { Disposable } from 'vs/base/common/lifecycle'; import { IUserDataAutoSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -21,9 +20,61 @@ import { joinPath } from 'vs/base/common/resources'; import { FileAccess } from 'vs/base/common/network'; import { DefaultIconPath } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IProductService } from 'vs/platform/product/common/productService'; +import { ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { BuiltinGettingStartedCategory, BuiltinGettingStartedItem, content } from 'vs/workbench/services/gettingStarted/common/gettingStartedContent'; +import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService'; +import { assertIsDefined } from 'vs/base/common/types'; export const IGettingStartedService = createDecorator('gettingStartedService'); +export const enum GettingStartedCategory { + Beginner = 'Beginner', + Intermediate = 'Intermediate', + Advanced = 'Advanced' +} + +export interface IGettingStartedTask { + id: string + title: string + description: string + category: GettingStartedCategory | string + when: ContextKeyExpression + order: number + button: + | { title: string, command?: never, link: string } + | { title: string, command: string, link?: never }, + doneOn: { commandExecuted: string, eventFired?: never } | { eventFired: string, commandExecuted?: never } + media: { type: 'image', path: { hc: URI, light: URI, dark: URI }, altText: string } +} + +export interface IGettingStartedCategoryDescriptor { + id: GettingStartedCategory | string + title: string + description: string + order: number + icon: + | { type: 'icon', icon: ThemeIcon } + | { type: 'image', path: string } + when: ContextKeyExpression + content: + | { type: 'items' } + | { type: 'startEntry', command: string } +} + +export interface IGettingStartedCategory { + id: GettingStartedCategory | string + title: string + description: string + order: number + icon: + | { type: 'icon', icon: ThemeIcon } + | { type: 'image', path: string } + when: ContextKeyExpression + content: + | { type: 'items', items: IGettingStartedTask[] } + | { type: 'startEntry', command: string } +} + type TaskProgress = { done?: boolean; }; export interface IGettingStartedTaskWithProgress extends IGettingStartedTask, Required { } @@ -44,6 +95,8 @@ export interface IGettingStartedService { readonly onDidAddTask: Event readonly onDidAddCategory: Event + readonly onDidChangeTask: Event + readonly onDidChangeCategory: Event readonly onDidProgressTask: Event @@ -62,10 +115,15 @@ export class GettingStartedService extends Disposable implements IGettingStarted private readonly _onDidAddCategory = new Emitter(); onDidAddCategory: Event = this._onDidAddCategory.event; + private readonly _onDidChangeCategory = new Emitter(); + onDidChangeCategory: Event = this._onDidChangeCategory.event; + + private readonly _onDidChangeTask = new Emitter(); + onDidChangeTask: Event = this._onDidChangeTask.event; + private readonly _onDidProgressTask = new Emitter(); onDidProgressTask: Event = this._onDidProgressTask.event; - private registry = GettingStartedRegistry; private memento: Memento; private taskProgress: Record; @@ -74,25 +132,27 @@ export class GettingStartedService extends Disposable implements IGettingStarted private trackedExtensions = new Set(); + private gettingStartedContributions = new Map(); + private tasks = new Map(); + + private tasExperimentService?: ITASExperimentService; + constructor( @IStorageService private readonly storageService: IStorageService, @ICommandService private readonly commandService: ICommandService, @IContextKeyService private readonly contextService: IContextKeyService, @IUserDataAutoSyncEnablementService readonly userDataAutoSyncEnablementService: IUserDataAutoSyncEnablementService, @IExtensionService private readonly extensionService: IExtensionService, - @IProductService private readonly productService: IProductService + @IProductService private readonly productService: IProductService, + @optional(ITASExperimentService) tasExperimentService: ITASExperimentService, ) { super(); + this.tasExperimentService = tasExperimentService; + this.memento = new Memento('gettingStartedService', this.storageService); this.taskProgress = this.memento.getMemento(StorageScope.GLOBAL, StorageTarget.USER); - this.registry.getCategories().forEach(category => { - if (category.content.type === 'items') { - category.content.items.forEach(task => this.registerDoneListeners(task)); - } - }); - this.extensionService.getExtensions().then(extensions => { extensions.forEach(extension => this.registerExtensionContributions(extension)); }); @@ -103,20 +163,100 @@ export class GettingStartedService extends Disposable implements IGettingStarted }); }); - this._register(this.registry.onDidAddCategory(category => - this._onDidAddCategory.fire(this.getCategoryProgress(category)) - )); - - this._register(this.registry.onDidAddTask(task => { - this.registerDoneListeners(task); - this._onDidAddTask.fire(this.getTaskProgress(task)); - })); - this._register(this.commandService.onDidExecuteCommand(command => this.progressByCommand(command.commandId))); this._register(userDataAutoSyncEnablementService.onDidChangeEnablement(() => { if (userDataAutoSyncEnablementService.isEnabled()) { this.progressByEvent('sync-enabled'); } })); + + content.forEach(async (category, index) => { + category = await this.getCategoryOverrides(category); + this.registerCategory({ + ...category, + icon: { type: 'icon', icon: category.icon }, + order: index, + when: ContextKeyExpr.deserialize(category.when) ?? ContextKeyExpr.true() + }); + + if (category.content.type === 'items') { + category.content.items.forEach(async (item, index) => { + item = await this.getTaskOverrides(item, category.id); + this.registerTask({ + ...item, + category: category.id, + order: index, + when: ContextKeyExpr.deserialize(item.when) ?? ContextKeyExpr.true(), + media: { + type: item.media.type, + altText: item.media.altText, + path: convertPaths(item.media.path) + } + }); + }); + } + }); + } + + private async getCategoryOverrides(category: BuiltinGettingStartedCategory): Promise { + return new Promise(async (resolve) => { + if (!this.tasExperimentService) { resolve(category); return; } + let resolved = false; + setTimeout(() => { resolve(category); resolved = true; }, 500); + + const [title, description] = await Promise.all([ + this.tasExperimentService.getTreatment(`gettingStarted.overrideCategory.${category.id}.title`), + this.tasExperimentService.getTreatment(`gettingStarted.overrideCategory.${category.id}.description`), + ]); + + if (resolved) { + const existing = assertIsDefined(this.gettingStartedContributions.get(category.id)); + existing.title = title ?? existing.title; + existing.description = description ?? existing.description; + console.log('hello', title, description, existing); + this._onDidChangeCategory.fire(this.getCategoryProgress(existing)); + } else { + resolve({ + ...category, + title: title ?? category.title, + description: description ?? category.description, + }); + } + }); + } + + private async getTaskOverrides(item: BuiltinGettingStartedItem, categoryId: string): Promise { + return new Promise(async (resolve) => { + if (!this.tasExperimentService) { resolve(item); return; } + let resolved = false; + setTimeout(() => { resolve(item); resolved = true; }, 500); + + const [title, description, media] = await Promise.all([ + this.tasExperimentService.getTreatment(`gettingStarted.overrideTask.${item.id}.title`), + this.tasExperimentService.getTreatment(`gettingStarted.overrideTask.${item.id}.description`), + this.tasExperimentService.getTreatment(`gettingStarted.overrideTask.${item.id}.media`), + ]); + + if (resolved) { + const existingCategory = assertIsDefined(this.gettingStartedContributions.get(categoryId)); + if (existingCategory.content.type === 'startEntry') { throw Error('Unexpected content type'); } + const existingItem = assertIsDefined(existingCategory.content.items.find(_item => _item.id === item.id)); + existingItem.title = title ?? existingItem.title; + existingItem.description = description ?? existingItem.description; + existingItem.media.path = media ? convertPaths(media) : existingItem.media.path; + this._onDidChangeTask.fire(this.getTaskProgress(existingItem)); + } else { + resolve({ + ...item, + title: title ?? item.title, + description: description ?? item.description, + media: { + altText: item.media.altText, + path: media ? media : item.media.path, + type: item.media.type, + }, + }); + } + }); } private registerExtensionContributions(extension: IExtensionDescription) { @@ -147,11 +287,12 @@ export class GettingStartedService extends Disposable implements IGettingStarted extension.contributes?.walkthroughs?.forEach(section => { const categoryID = extension.identifier.value + '#' + section.id; - this.registry.registerCategory({ + this.registerCategory({ content: { type: 'items' }, description: section.description, title: section.title, id: categoryID, + order: Math.min(), icon: { type: 'image', path: extension.icon @@ -161,9 +302,8 @@ export class GettingStartedService extends Disposable implements IGettingStarted when: ContextKeyExpr.deserialize(section.when) ?? ContextKeyExpr.true(), }); try { - section.tasks.forEach((task, index) => - this.registry.registerTask({ + this.registerTask({ button: task.button, description: task.description, media: { type: 'image', altText: task.media.altText, path: convertPaths(task.media.path) }, @@ -203,8 +343,9 @@ export class GettingStartedService extends Disposable implements IGettingStarted } getCategories(): IGettingStartedCategoryWithProgress[] { - const registeredCategories = this.registry.getCategories(); + const registeredCategories = [...this.gettingStartedContributions.values()]; const categoriesWithCompletion = registeredCategories + .sort((a, b) => a.order - b.order) .filter(category => this.contextService.contextMatchesRules(category.when)) .map(category => { if (category.content.type === 'items') { @@ -256,7 +397,7 @@ export class GettingStartedService extends Disposable implements IGettingStarted if (!oldProgress || oldProgress.done !== true) { this.taskProgress[id] = { done: true }; this.memento.saveMemento(); - const task = this.registry.getTask(id); + const task = this.getTask(id); this._onDidProgressTask.fire(this.getTaskProgress(task)); } } @@ -264,7 +405,7 @@ export class GettingStartedService extends Disposable implements IGettingStarted deprogressTask(id: string) { delete this.taskProgress[id]; this.memento.saveMemento(); - const task = this.registry.getTask(id); + const task = this.getTask(id); this._onDidProgressTask.fire(this.getTaskProgress(task)); } @@ -277,8 +418,61 @@ export class GettingStartedService extends Disposable implements IGettingStarted const listening = this.eventListeners.get(event) ?? []; listening.forEach(id => this.progressTask(id)); } + + public registerTask(task: IGettingStartedTask): IGettingStartedTask { + const category = this.gettingStartedContributions.get(task.category); + if (!category) { throw Error('Registering getting started task to category that does not exist (' + task.category + ')'); } + if (category.content.type !== 'items') { throw Error('Registering getting started task to category that is not of `items` type (' + task.category + ')'); } + if (this.tasks.has(task.id)) { throw Error('Attempting to register task with id ' + task.id + ' twice. Second is dropped.'); } + this.tasks.set(task.id, task); + const insertIndex = category.content.items.findIndex(item => item.order > task.order); + category.content.items.splice(insertIndex, 0, task); + this.registerDoneListeners(task); + this._onDidAddTask.fire(this.getTaskProgress(task)); + return task; + } + + public registerCategory(categoryDescriptor: IGettingStartedCategoryDescriptor): void { + const oldCategory = this.gettingStartedContributions.get(categoryDescriptor.id); + if (oldCategory) { + console.error(`Skipping attempt to overwrite getting started category. (${categoryDescriptor})`); + return; + } + + const category: IGettingStartedCategory = { + ...categoryDescriptor, + content: categoryDescriptor.content.type === 'items' + ? { type: 'items', items: [] } + : categoryDescriptor.content + }; + + this.gettingStartedContributions.set(categoryDescriptor.id, category); + this._onDidAddCategory.fire(this.getCategoryProgress(category)); + } + + private getTask(id: string): IGettingStartedTask { + const task = this.tasks.get(id); + if (!task) { throw Error('Attempting to access task which does not exist in registry ' + id); } + return task; + } } +const convertPaths = (path: string | { hc: string, dark: string, light: string }): { hc: URI, dark: URI, light: URI } => { + const convertPath = (path: string) => path.startsWith('https://') + ? URI.parse(path, true) + : FileAccess.asBrowserUri('vs/workbench/services/gettingStarted/common/media/' + path, require); + if (typeof path === 'string') { + const converted = convertPath(path); + return { hc: converted, dark: converted, light: converted }; + } else { + return { + hc: convertPath(path.hc), + light: convertPath(path.light), + dark: convertPath(path.dark) + }; + } +}; + registerAction2(class extends Action2 { constructor() { super({ diff --git a/src/vs/workbench/services/workingCopy/common/fileWorkingCopy.ts b/src/vs/workbench/services/workingCopy/common/fileWorkingCopy.ts index f7cd5e63546..5175a42914e 100644 --- a/src/vs/workbench/services/workingCopy/common/fileWorkingCopy.ts +++ b/src/vs/workbench/services/workingCopy/common/fileWorkingCopy.ts @@ -66,8 +66,6 @@ export interface IFileWorkingCopyModel { * Snapshots the model's current content for writing. This must include * any changes that were made to the model that are in memory. * - * TODO@bpasero could this method return sync and not promise? - * * @param token support for cancellation */ snapshot(token: CancellationToken): Promise; @@ -89,7 +87,7 @@ export interface IFileWorkingCopyModel { * case of undo-redo. * * TODO@bpasero should find a better name here maybe together - * with the pushStackElement concept since this is around + * with the `pushStackElement` concept since this is around * undo/redo? */ getAlternativeVersionId(): number; @@ -102,7 +100,9 @@ export interface IFileWorkingCopyModel { * save is triggered so that the user can always undo back * to the state before saving. * - * TODO@bpasero rename to beforeSave()? + * TODO@bpasero should find a better name here maybe together + * with the `getAlternativeVersionId` concept since this is around + * undo/redo? */ pushStackElement(): void; } diff --git a/test/unit/README.md b/test/unit/README.md index 35289710f4f..47a309adbad 100644 --- a/test/unit/README.md +++ b/test/unit/README.md @@ -8,6 +8,7 @@ All unit tests are run inside a electron-browser environment which access to DOM - use the `--debug` to see an electron window with dev tools which allows for debugging - to run only a subset of tests use the `--run` or `--glob` options +- use `yarn watch` to automatically compile changes For instance, `./scripts/test.sh --debug --glob **/extHost*.test.js` runs all tests from `extHost`-files and enables you to debug them. @@ -24,7 +25,7 @@ Unit tests from layers `common` and `browser` are run inside `chromium`, `webkit ## Run (with node) - yarn run mocha --run src/vs/editor/test/browser/controller/cursor.test.ts + yarn run mocha --ui tdd --run src/vs/editor/test/browser/controller/cursor.test.ts ## Coverage