diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index ce9afa3eae9..ca28c413a71 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -44,6 +44,8 @@ const tasks = compilations.map(function (tsconfigFile) { const root = path.join('extensions', relativeDirname); const srcBase = path.join(root, 'src'); const src = path.join(srcBase, '**'); + const srcOpts = { cwd: path.dirname(__dirname), base: srcBase }; + const out = path.join(root, 'out'); const baseUrl = getBaseUrl(out); @@ -65,7 +67,7 @@ const tasks = compilations.map(function (tsconfigFile) { const compilation = tsb.create(absolutePath, overrideOptions, false, err => reporter(err.toString())); - return function () { + const pipeline = function () { const input = es.through(); const tsFilter = filter(['**/*.ts', '!**/lib/lib*.d.ts', '!**/node_modules/**'], { restore: true }); const output = input @@ -95,15 +97,19 @@ const tasks = compilations.map(function (tsconfigFile) { return es.duplex(input, output); }; - } - const srcOpts = { cwd: path.dirname(__dirname), base: srcBase }; + // add src-stream for project files + pipeline.tsProjectSrc = () => { + return compilation.src(srcOpts); + }; + return pipeline; + } const cleanTask = task.define(`clean-extension-${name}`, util.rimraf(out)); const compileTask = task.define(`compile-extension:${name}`, task.series(cleanTask, () => { const pipeline = createPipeline(false, true); - const input = gulp.src(src, srcOpts); + const input = pipeline.tsProjectSrc(); return input .pipe(pipeline()) @@ -112,8 +118,8 @@ const tasks = compilations.map(function (tsconfigFile) { const watchTask = task.define(`watch-extension:${name}`, task.series(cleanTask, () => { const pipeline = createPipeline(false); - const input = gulp.src(src, srcOpts); - const watchInput = watcher(src, srcOpts); + const input = pipeline.tsProjectSrc(); + const watchInput = watcher(src, { ...srcOpts, ...{ readDelay: 200 } }); return watchInput .pipe(util.incremental(pipeline, input)) @@ -122,7 +128,7 @@ const tasks = compilations.map(function (tsconfigFile) { const compileBuildTask = task.define(`compile-build-extension-${name}`, task.series(cleanTask, () => { const pipeline = createPipeline(true, true); - const input = gulp.src(src, srcOpts); + const input = pipeline.tsProjectSrc(); return input .pipe(pipeline()) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 3e97ef2fe3b..baa2b749486 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -93,6 +93,7 @@ const optimizeVSCodeTask = task.define('optimize-vscode', task.series( resources: vscodeResources, loaderConfig: common.loaderConfig(nodeModules), out: 'out-vscode', + inlineAmdImages: true, bundleInfo: undefined }) )); diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index 54a270695bd..52660b0df12 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -42,6 +42,7 @@ function prepareDebPackage(arch) { .pipe(replace('@@NAME_LONG@@', product.nameLong)) .pipe(replace('@@NAME_SHORT@@', product.nameShort)) .pipe(replace('@@NAME@@', product.applicationName)) + .pipe(replace('@@EXEC@@', `/usr/share/${product.applicationName}/${product.applicationName}`)) .pipe(replace('@@ICON@@', product.linuxIconName)) .pipe(replace('@@URLPROTOCOL@@', product.urlProtocol)); @@ -134,6 +135,7 @@ function prepareRpmPackage(arch) { .pipe(replace('@@NAME_LONG@@', product.nameLong)) .pipe(replace('@@NAME_SHORT@@', product.nameShort)) .pipe(replace('@@NAME@@', product.applicationName)) + .pipe(replace('@@EXEC@@', `/usr/share/${product.applicationName}/${product.applicationName}`)) .pipe(replace('@@ICON@@', product.linuxIconName)) .pipe(replace('@@URLPROTOCOL@@', product.urlProtocol)); @@ -203,21 +205,25 @@ function prepareSnapPackage(arch) { const destination = getSnapBuildPath(arch); return function () { + // A desktop file that is placed in snap/gui will be placed into meta/gui verbatim. const desktop = gulp.src('resources/linux/code.desktop', { base: '.' }) - .pipe(rename(`usr/share/applications/${product.applicationName}.desktop`)); + .pipe(rename(`snap/gui/${product.applicationName}.desktop`)); + // A desktop file that is placed in snap/gui will be placed into meta/gui verbatim. const desktopUrlHandler = gulp.src('resources/linux/code-url-handler.desktop', { base: '.' }) - .pipe(rename(`usr/share/applications/${product.applicationName}-url-handler.desktop`)); + .pipe(rename(`snap/gui/${product.applicationName}-url-handler.desktop`)); const desktops = es.merge(desktop, desktopUrlHandler) .pipe(replace('@@NAME_LONG@@', product.nameLong)) .pipe(replace('@@NAME_SHORT@@', product.nameShort)) .pipe(replace('@@NAME@@', product.applicationName)) - .pipe(replace('@@ICON@@', `/usr/share/pixmaps/${product.linuxIconName}.png`)) + .pipe(replace('@@EXEC@@', product.applicationName)) + .pipe(replace('@@ICON@@', `\${SNAP}/meta/gui/${product.linuxIconName}.png`)) .pipe(replace('@@URLPROTOCOL@@', product.urlProtocol)); + // An icon that is placed in snap/gui will be placed into meta/gui verbatim. const icon = gulp.src('resources/linux/code.png', { base: '.' }) - .pipe(rename(`usr/share/pixmaps/${product.linuxIconName}.png`)); + .pipe(rename(`snap/gui/${product.linuxIconName}.png`)); const code = gulp.src(binaryDir + '/**/*', { base: binaryDir }) .pipe(rename(function (p) { p.dirname = `usr/share/${product.applicationName}/${p.dirname}`; })); @@ -238,7 +244,8 @@ function prepareSnapPackage(arch) { function buildSnapPackage(arch) { const snapBuildPath = getSnapBuildPath(arch); - return shell.task(`cd ${snapBuildPath} && snapcraft build`); + // Default target for snapcraft runs: pull, build, stage and prime, and finally assembles the snap. + return shell.task(`cd ${snapBuildPath} && snapcraft`); } const BUILD_TARGETS = [ diff --git a/build/gulpfile.vscode.web.js b/build/gulpfile.vscode.web.js index 8f2e9c9f5a2..846ceb219fd 100644 --- a/build/gulpfile.vscode.web.js +++ b/build/gulpfile.vscode.web.js @@ -34,7 +34,8 @@ const nodeModules = Object.keys(product.dependencies || {}) const vscodeWebResources = [ // Workbench - 'out-build/vs/{base,platform,editor,workbench}/**/*.{svg,png,html}', + 'out-build/vs/{base,platform,editor,workbench}/**/*.{svg,png}', + 'out-build/vs/code/browser/workbench/*.html', 'out-build/vs/base/browser/ui/octiconLabel/octicons/**', 'out-build/vs/**/markdown.css', diff --git a/build/lib/compilation.js b/build/lib/compilation.js index 6e2ff276d7c..170e086b35b 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -36,8 +36,8 @@ function getTypeScriptCompilerOptions(src) { function createCompile(src, build, emitError) { const projectPath = path.join(__dirname, '../../', src, 'tsconfig.json'); const overrideOptions = Object.assign(Object.assign({}, getTypeScriptCompilerOptions(src)), { inlineSources: Boolean(build) }); - const ts = tsb.create(projectPath, overrideOptions, false, err => reporter(err)); - return function (token) { + const compilation = tsb.create(projectPath, overrideOptions, false, err => reporter(err)); + function pipeline(token) { const utf8Filter = util.filter(data => /(\/|\\)test(\/|\\).*utf8/.test(data.path)); const tsFilter = util.filter(data => /\.ts$/.test(data.path)); const noDeclarationsFilter = util.filter(data => !(/\.d\.ts$/.test(data.path))); @@ -48,7 +48,7 @@ function createCompile(src, build, emitError) { .pipe(utf8Filter.restore) .pipe(tsFilter) .pipe(util.loadSourcemaps()) - .pipe(ts(token)) + .pipe(compilation(token)) .pipe(noDeclarationsFilter) .pipe(build ? nls() : es.through()) .pipe(noDeclarationsFilter.restore) @@ -60,7 +60,11 @@ function createCompile(src, build, emitError) { .pipe(tsFilter.restore) .pipe(reporter.end(!!emitError)); return es.duplex(input, output); + } + pipeline.tsProjectSrc = () => { + return compilation.src({ base: src }); }; + return pipeline; } function compileTask(src, out, build) { return function () { @@ -81,7 +85,7 @@ function watchTask(out, build) { return function () { const compile = createCompile('src', build); const src = gulp.src('src/**', { base: 'src' }); - const watchSrc = watch('src/**', { base: 'src' }); + const watchSrc = watch('src/**', { base: 'src', readDelay: 200 }); let generator = new MonacoGenerator(true); generator.execute(); return watchSrc diff --git a/build/lib/compilation.ts b/build/lib/compilation.ts index 08c1774a90e..6f37821c775 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -39,13 +39,13 @@ function getTypeScriptCompilerOptions(src: string): ts.CompilerOptions { return options; } -function createCompile(src: string, build: boolean, emitError?: boolean): (token?: util.ICancellationToken) => NodeJS.ReadWriteStream { +function createCompile(src: string, build: boolean, emitError?: boolean) { const projectPath = path.join(__dirname, '../../', src, 'tsconfig.json'); const overrideOptions = { ...getTypeScriptCompilerOptions(src), inlineSources: Boolean(build) }; - const ts = tsb.create(projectPath, overrideOptions, false, err => reporter(err)); + const compilation = tsb.create(projectPath, overrideOptions, false, err => reporter(err)); - return function (token?: util.ICancellationToken) { + function pipeline(token?: util.ICancellationToken) { const utf8Filter = util.filter(data => /(\/|\\)test(\/|\\).*utf8/.test(data.path)); const tsFilter = util.filter(data => /\.ts$/.test(data.path)); @@ -58,7 +58,7 @@ function createCompile(src: string, build: boolean, emitError?: boolean): (token .pipe(utf8Filter.restore) .pipe(tsFilter) .pipe(util.loadSourcemaps()) - .pipe(ts(token)) + .pipe(compilation(token)) .pipe(noDeclarationsFilter) .pipe(build ? nls() : es.through()) .pipe(noDeclarationsFilter.restore) @@ -71,16 +71,18 @@ function createCompile(src: string, build: boolean, emitError?: boolean): (token .pipe(reporter.end(!!emitError)); return es.duplex(input, output); + } + pipeline.tsProjectSrc = () => { + return compilation.src({ base: src }); }; + return pipeline; } export function compileTask(src: string, out: string, build: boolean): () => NodeJS.ReadWriteStream { return function () { const compile = createCompile(src, build, true); - const srcPipe = gulp.src(`${src}/**`, { base: `${src}` }); - let generator = new MonacoGenerator(false); if (src === 'src') { generator.execute(); @@ -99,7 +101,7 @@ export function watchTask(out: string, build: boolean): () => NodeJS.ReadWriteSt const compile = createCompile('src', build); const src = gulp.src('src/**', { base: 'src' }); - const watchSrc = watch('src/**', { base: 'src' }); + const watchSrc = watch('src/**', { base: 'src', readDelay: 200 }); let generator = new MonacoGenerator(true); generator.execute(); diff --git a/build/lib/optimize.js b/build/lib/optimize.js index ae2e42ec65e..45f11698463 100644 --- a/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -5,6 +5,7 @@ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); const es = require("event-stream"); +const fs = require("fs"); const gulp = require("gulp"); const concat = require("gulp-concat"); const minifyCSS = require("gulp-cssnano"); @@ -132,6 +133,14 @@ function optimizeTask(opts) { if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); } + if (opts.inlineAmdImages) { + try { + result = inlineAmdImages(src, result); + } + catch (err) { + return bundlesStream.emit('error', JSON.stringify(err)); + } + } toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream); // Remove css inlined resources const filteredResources = resources.slice(); @@ -167,6 +176,39 @@ function optimizeTask(opts) { }; } exports.optimizeTask = optimizeTask; +function inlineAmdImages(src, result) { + for (const outputFile of result.files) { + for (const sourceFile of outputFile.sources) { + if (sourceFile.path && /\.js$/.test(sourceFile.path)) { + sourceFile.contents = sourceFile.contents.replace(/\([^.]+\.registerAndGetAmdImageURL\(([^)]+)\)\)/g, (_, m0) => { + let imagePath = m0; + // remove `` or '' + if ((imagePath.charAt(0) === '`' && imagePath.charAt(imagePath.length - 1) === '`') + || (imagePath.charAt(0) === '\'' && imagePath.charAt(imagePath.length - 1) === '\'')) { + imagePath = imagePath.substr(1, imagePath.length - 2); + } + if (!/\.(png|svg)$/.test(imagePath)) { + console.log(`original: ${_}`); + return _; + } + const repoLocation = path.join(src, imagePath); + const absoluteLocation = path.join(REPO_ROOT_PATH, repoLocation); + if (!fs.existsSync(absoluteLocation)) { + const message = `Invalid amd image url in file ${sourceFile.path}: ${imagePath}`; + console.log(message); + throw new Error(message); + } + const fileContents = fs.readFileSync(absoluteLocation); + const mime = /\.svg$/.test(imagePath) ? 'image/svg+xml' : 'image/png'; + // Mark the file as inlined so we don't ship it by itself + result.cssInlinedResources.push(repoLocation); + return `("data:${mime};base64,${fileContents.toString('base64')}")`; + }); + } + } + } + return result; +} /** * Wrap around uglify and allow the preserveComments function * to have a file "context" to include our copyright only once per file. @@ -202,9 +244,6 @@ function uglifyWithCopyrights() { const output = input .pipe(flatmap((stream, f) => { return stream.pipe(minify({ - compress: { - hoist_funs: true // required due to https://github.com/microsoft/vscode/issues/80202 - }, output: { comments: preserveComments(f), max_line_len: 1024 diff --git a/build/lib/optimize.ts b/build/lib/optimize.ts index 9380d5880a3..46189514c30 100644 --- a/build/lib/optimize.ts +++ b/build/lib/optimize.ts @@ -6,6 +6,7 @@ 'use strict'; import * as es from 'event-stream'; +import * as fs from 'fs'; import * as gulp from 'gulp'; import * as concat from 'gulp-concat'; import * as minifyCSS from 'gulp-cssnano'; @@ -159,6 +160,10 @@ export interface IOptimizeTaskOpts { * (emit bundleInfo.json file) */ bundleInfo: boolean; + /** + * replace calls to `registerAndGetAmdImageURL` with data uris + */ + inlineAmdImages: boolean; /** * (out folder name) */ @@ -192,6 +197,14 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr bundle.bundle(entryPoints, loaderConfig, function (err, result) { if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); } + if (opts.inlineAmdImages) { + try { + result = inlineAmdImages(src, result); + } catch (err) { + return bundlesStream.emit('error', JSON.stringify(err)); + } + } + toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream); // Remove css inlined resources @@ -236,6 +249,42 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr }; } +function inlineAmdImages(src: string, result: bundle.IBundleResult): bundle.IBundleResult { + for (const outputFile of result.files) { + for (const sourceFile of outputFile.sources) { + if (sourceFile.path && /\.js$/.test(sourceFile.path)) { + sourceFile.contents = sourceFile.contents.replace(/\([^.]+\.registerAndGetAmdImageURL\(([^)]+)\)\)/g, (_, m0) => { + let imagePath = m0; + // remove `` or '' + if ((imagePath.charAt(0) === '`' && imagePath.charAt(imagePath.length - 1) === '`') + || (imagePath.charAt(0) === '\'' && imagePath.charAt(imagePath.length - 1) === '\'')) { + imagePath = imagePath.substr(1, imagePath.length - 2); + } + if (!/\.(png|svg)$/.test(imagePath)) { + console.log(`original: ${_}`); + return _; + } + const repoLocation = path.join(src, imagePath); + const absoluteLocation = path.join(REPO_ROOT_PATH, repoLocation); + if (!fs.existsSync(absoluteLocation)) { + const message = `Invalid amd image url in file ${sourceFile.path}: ${imagePath}`; + console.log(message); + throw new Error(message); + } + const fileContents = fs.readFileSync(absoluteLocation); + const mime = /\.svg$/.test(imagePath) ? 'image/svg+xml' : 'image/png'; + + // Mark the file as inlined so we don't ship it by itself + result.cssInlinedResources.push(repoLocation); + + return `("data:${mime};base64,${fileContents.toString('base64')}")`; + }); + } + } + } + return result; +} + declare class FileWithCopyright extends VinylFile { public __hasOurCopyright: boolean; } @@ -278,9 +327,6 @@ function uglifyWithCopyrights(): NodeJS.ReadWriteStream { const output = input .pipe(flatmap((stream, f) => { return stream.pipe(minify({ - compress: { - hoist_funs: true // required due to https://github.com/microsoft/vscode/issues/80202 - }, output: { comments: preserveComments(f), max_line_len: 1024 diff --git a/build/lib/tslint/noUnexternalizedStringsRule.js b/build/lib/tslint/noUnexternalizedStringsRule.js index 18a90c0f9c1..a1183ce68e7 100644 --- a/build/lib/tslint/noUnexternalizedStringsRule.js +++ b/build/lib/tslint/noUnexternalizedStringsRule.js @@ -11,6 +11,9 @@ const Lint = require("tslint"); */ class Rule extends Lint.Rules.AbstractRule { apply(sourceFile) { + if (/\.d.ts$/.test(sourceFile.fileName)) { + return []; + } return this.applyWithWalker(new NoUnexternalizedStringsRuleWalker(sourceFile, this.getOptions())); } } diff --git a/build/lib/tslint/noUnexternalizedStringsRule.ts b/build/lib/tslint/noUnexternalizedStringsRule.ts index e8c0e98ec15..d896e4fabe2 100644 --- a/build/lib/tslint/noUnexternalizedStringsRule.ts +++ b/build/lib/tslint/noUnexternalizedStringsRule.ts @@ -11,6 +11,9 @@ import * as Lint from 'tslint'; */ export class Rule extends Lint.Rules.AbstractRule { public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + if (/\.d.ts$/.test(sourceFile.fileName)) { + return []; + } return this.applyWithWalker(new NoUnexternalizedStringsRuleWalker(sourceFile, this.getOptions())); } } diff --git a/build/lib/typings/gulp-tsb.d.ts b/build/lib/typings/gulp-tsb.d.ts index 916dd21cd1c..df9bb34d3fb 100644 --- a/build/lib/typings/gulp-tsb.d.ts +++ b/build/lib/typings/gulp-tsb.d.ts @@ -8,7 +8,10 @@ declare module "gulp-tsb" { export interface IncrementalCompiler { (token?: ICancellationToken): NodeJS.ReadWriteStream; - src(): NodeJS.ReadStream; + src(opts?: { + cwd?: string; + base?: string; + }): NodeJS.ReadStream; } export function create(projectPath: string, existingOptions: any, verbose?: boolean, onError?: (message: any) => void): IncrementalCompiler; diff --git a/build/lib/util.js b/build/lib/util.js index be2670261d7..6acb7ab574f 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -121,7 +121,7 @@ function loadSourcemaps() { return; } if (!f.contents) { - cb(new Error('empty file')); + cb(undefined, f); return; } const contents = f.contents.toString('utf8'); diff --git a/build/lib/util.ts b/build/lib/util.ts index 578271e6648..6a82295ae26 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -165,7 +165,7 @@ export function loadSourcemaps(): NodeJS.ReadWriteStream { } if (!f.contents) { - cb(new Error('empty file')); + cb(undefined, f); return; } diff --git a/build/lib/watch/index.js b/build/lib/watch/index.js index 0a4af2a798f..a9ab5972977 100644 --- a/build/lib/watch/index.js +++ b/build/lib/watch/index.js @@ -5,17 +5,6 @@ const es = require('event-stream'); -/** Ugly hack for gulp-tsb */ -function handleDeletions() { - return es.mapSync(f => { - if (/\.ts$/.test(f.relative) && !f.contents) { - f.contents = Buffer.from(''); - f.stat = { mtime: new Date() }; - } - - return f; - }); -} let watch = undefined; @@ -24,6 +13,5 @@ if (!watch) { } module.exports = function () { - return watch.apply(null, arguments) - .pipe(handleDeletions()); + return watch.apply(null, arguments); }; diff --git a/build/monaco/api.js b/build/monaco/api.js index 5cd0be82039..93fea1558b9 100644 --- a/build/monaco/api.js +++ b/build/monaco/api.js @@ -148,8 +148,9 @@ function getMassagedTopLevelDeclarationText(sourceFile, declaration, importName, } }); } - result = result.replace(/export default/g, 'export'); - result = result.replace(/export declare/g, 'export'); + result = result.replace(/export default /g, 'export '); + result = result.replace(/export declare /g, 'export '); + result = result.replace(/declare /g, ''); if (declaration.kind === ts.SyntaxKind.EnumDeclaration) { result = result.replace(/const enum/, 'enum'); enums.push(result); diff --git a/build/monaco/api.ts b/build/monaco/api.ts index ef9c9a584dc..1cd4e49b733 100644 --- a/build/monaco/api.ts +++ b/build/monaco/api.ts @@ -178,8 +178,9 @@ function getMassagedTopLevelDeclarationText(sourceFile: ts.SourceFile, declarati } }); } - result = result.replace(/export default/g, 'export'); - result = result.replace(/export declare/g, 'export'); + result = result.replace(/export default /g, 'export '); + result = result.replace(/export declare /g, 'export '); + result = result.replace(/declare /g, ''); if (declaration.kind === ts.SyntaxKind.EnumDeclaration) { result = result.replace(/const enum/, 'enum'); diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index afba093b25c..4a80dae41aa 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -62,6 +62,7 @@ export interface ICommandHandler { #includeAll(vs/editor/common/editorCommon;editorOptions.=>): IScrollEvent #includeAll(vs/editor/common/model/textModelEvents): #includeAll(vs/editor/common/controller/cursorEvents): +#include(vs/platform/accessibility/common/accessibility): AccessibilitySupport #includeAll(vs/editor/common/config/editorOptions): #includeAll(vs/editor/browser/editorBrowser;editorCommon.=>;editorOptions.=>): #include(vs/editor/common/config/fontInfo): FontInfo, BareFontInfo diff --git a/build/package.json b/build/package.json index a48af3c1d8f..bf3ec5ce3f9 100644 --- a/build/package.json +++ b/build/package.json @@ -40,7 +40,7 @@ "mime": "^1.3.4", "minimist": "^1.2.0", "request": "^2.85.0", - "terser": "^4.2.1", + "terser": "4.3.1", "tslint": "^5.9.1", "typescript": "3.6.2", "vsce": "1.48.0", diff --git a/build/yarn.lock b/build/yarn.lock index 223ecd968ef..937eb1daa43 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -2169,7 +2169,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -terser@*, terser@^4.2.1: +terser@*: version "4.2.1" resolved "https://registry.yarnpkg.com/terser/-/terser-4.2.1.tgz#1052cfe17576c66e7bc70fcc7119f22b155bdac1" integrity sha512-cGbc5utAcX4a9+2GGVX4DsenG6v0x3glnDi5hx8816X1McEAwPlPgRtXPJzSBsbpILxZ8MQMT0KvArLuE0HP5A== @@ -2178,6 +2178,15 @@ terser@*, terser@^4.2.1: source-map "~0.6.1" source-map-support "~0.5.12" +terser@4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.3.1.tgz#09820bcb3398299c4b48d9a86aefc65127d0ed65" + integrity sha512-pnzH6dnFEsR2aa2SJaKb1uSCl3QmIsJ8dEkj0Fky+2AwMMcC9doMqLOQIH6wVTEKaVfKVvLSk5qxPBEZT9mywg== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + through2@2.X, through2@^2.0.0, through2@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" @@ -2424,9 +2433,9 @@ vsce@1.48.0: yazl "^2.2.2" vscode-ripgrep@^1.5.6: - version "1.5.6" - resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.6.tgz#93bf5c99ca5f8248950a305e224f6ca153c30af4" - integrity sha512-WRIM9XpUj6dsfdAmuI3ANbmT1ysPUVsYy/2uCLDHJa9kbiB4T7uGvFnnc0Rgx2qQnyRAwL7PeWaFgUljPPxf2g== + version "1.5.7" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.7.tgz#acb6b548af488a4bca5d0f1bb5faf761343289ce" + integrity sha512-/Vsz/+k8kTvui0q3O74pif9FK0nKopgFTiGNVvxicZANxtSA8J8gUE9GQ/4dpi7D/2yI/YVORszwVskFbz46hQ== vscode-telemetry-extractor@^1.5.4: version "1.5.4" diff --git a/extensions/git/src/statusbar.ts b/extensions/git/src/statusbar.ts index fb89aca7264..7f858933702 100644 --- a/extensions/git/src/statusbar.ts +++ b/extensions/git/src/statusbar.ts @@ -71,6 +71,7 @@ class SyncStatusBar { const onEnablementChange = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.enableStatusBarSync')); onEnablementChange(this.updateEnablement, this, this.disposables); + this.updateEnablement(); this._onDidChange.fire(); } diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index ca358e22b9b..ec693b876f7 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -10,7 +10,7 @@ "main": "./out/htmlServerMain", "dependencies": { "vscode-css-languageservice": "^4.0.3-next.6", - "vscode-html-languageservice": "^3.0.4-next.2", + "vscode-html-languageservice": "^3.0.4-next.3", "vscode-languageserver": "^5.3.0-next.8", "vscode-languageserver-types": "3.15.0-next.2", "vscode-nls": "^4.1.1", diff --git a/extensions/html-language-features/server/src/test/formatting.test.ts b/extensions/html-language-features/server/src/test/formatting.test.ts index 8c59c75e017..31c80215399 100644 --- a/extensions/html-language-features/server/src/test/formatting.test.ts +++ b/extensions/html-language-features/server/src/test/formatting.test.ts @@ -46,8 +46,8 @@ suite('HTML Embedded Formatting', () => { } function assertFormatWithFixture(fixtureName: string, expectedPath: string, options?: any, formatOptions?: FormattingOptions): void { - let input = fs.readFileSync(path.join(__dirname, 'fixtures', 'inputs', fixtureName)).toString().replace(/\r\n/mg, '\n'); - let expected = fs.readFileSync(path.join(__dirname, 'fixtures', 'expected', expectedPath)).toString().replace(/\r\n/mg, '\n'); + let input = fs.readFileSync(path.join(__dirname, '..', '..', 'src', 'test', 'fixtures', 'inputs', fixtureName)).toString().replace(/\r\n/mg, '\n'); + let expected = fs.readFileSync(path.join(__dirname, '..', '..', 'src', 'test', 'fixtures', 'expected', expectedPath)).toString().replace(/\r\n/mg, '\n'); assertFormat(input, expected, options, formatOptions, expectedPath); } @@ -208,4 +208,4 @@ preserve_newlines: true unformatted: Array(1)["wbr"] wrap_attributes: "auto" wrap_attributes_indent_size: undefined -wrap_line_length: 120*/ \ No newline at end of file +wrap_line_length: 120*/ diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index 4ac895b439c..c2b7f141cc6 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -238,10 +238,10 @@ vscode-css-languageservice@^4.0.3-next.6: vscode-nls "^4.1.1" vscode-uri "^2.0.3" -vscode-html-languageservice@^3.0.4-next.2: - version "3.0.4-next.2" - resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.4-next.2.tgz#afdbe2781daa0a72613afac77068593925bd2e07" - integrity sha512-tlyiflBm/k/PoTwGzg4LL0cwq6wS7mnKxDVYSlY2Iw21dONWINaS0MynYCn6Zs4PzIpgueCSMuTBQTey4d+BBQ== +vscode-html-languageservice@^3.0.4-next.3: + version "3.0.4-next.3" + resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.4-next.3.tgz#7a0fc33aae846165b157acbb8b133cc3fcf2ca0d" + integrity sha512-PGIcKFxqsvVMv51QWreuQx9LhN43Vzhgl8RYI8CcWThjl+J8uUKImjwAWq9zndOiiRUPF2Zk7zME/dMIis1hOw== dependencies: vscode-languageserver-types "^3.15.0-next.2" vscode-nls "^4.1.1" diff --git a/extensions/markdown-language-features/media/index.js b/extensions/markdown-language-features/media/index.js index 9a0fd91b45a..d46e19c8c97 100644 --- a/extensions/markdown-language-features/media/index.js +++ b/extensions/markdown-language-features/media/index.js @@ -1005,4 +1005,4 @@ exports.getSettings = getSettings; /***/ }) /******/ }); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2xvZGFzaC50aHJvdHRsZS9pbmRleC5qcyIsIndlYnBhY2s6Ly8vKHdlYnBhY2spL2J1aWxkaW4vZ2xvYmFsLmpzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2FjdGl2ZUxpbmVNYXJrZXIudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvZXZlbnRzLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2luZGV4LnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL21lc3NhZ2luZy50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9zY3JvbGwtc3luYy50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9zZXR0aW5ncy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQSx5REFBaUQsY0FBYztBQUMvRDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBMkIsMEJBQTBCLEVBQUU7QUFDdkQseUNBQWlDLGVBQWU7QUFDaEQ7QUFDQTtBQUNBOztBQUVBO0FBQ0EsOERBQXNELCtEQUErRDs7QUFFckg7QUFDQTs7O0FBR0E7QUFDQTs7Ozs7Ozs7Ozs7O0FDbkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFNBQVM7QUFDcEIsV0FBVyxPQUFPO0FBQ2xCLFdBQVcsT0FBTyxZQUFZO0FBQzlCLFdBQVcsUUFBUTtBQUNuQjtBQUNBLFdBQVcsT0FBTztBQUNsQjtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLDhDQUE4QyxrQkFBa0I7QUFDaEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFNBQVM7QUFDcEIsV0FBVyxPQUFPO0FBQ2xCLFdBQVcsT0FBTyxZQUFZO0FBQzlCLFdBQVcsUUFBUTtBQUNuQjtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtREFBbUQsb0JBQW9CO0FBQ3ZFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLEVBQUU7QUFDYixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsRUFBRTtBQUNiLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLEVBQUU7QUFDYixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxFQUFFO0FBQ2IsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOzs7Ozs7Ozs7Ozs7O0FDdGJBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsNENBQTRDOztBQUU1Qzs7Ozs7Ozs7Ozs7Ozs7O0FDbkJBOzs7Z0dBR2dHO0FBQ2hHLCtGQUF5RDtBQUV6RCxNQUFhLGdCQUFnQjtJQUc1Qiw4QkFBOEIsQ0FBQyxJQUFZO1FBQzFDLE1BQU0sRUFBRSxRQUFRLEVBQUUsR0FBRyxzQ0FBd0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwRCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsSUFBSSxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDNUMsQ0FBQztJQUVELE9BQU8sQ0FBQyxNQUErQjtRQUN0QyxJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3pDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNoQyxJQUFJLENBQUMsUUFBUSxHQUFHLE1BQU0sQ0FBQztJQUN4QixDQUFDO0lBRUQsb0JBQW9CLENBQUMsT0FBZ0M7UUFDcEQsSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUNiLE9BQU87U0FDUDtRQUNELE9BQU8sQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsdUJBQXVCLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDNUUsQ0FBQztJQUVELGtCQUFrQixDQUFDLE9BQWdDO1FBQ2xELElBQUksQ0FBQyxPQUFPLEVBQUU7WUFDYixPQUFPO1NBQ1A7UUFDRCxPQUFPLENBQUMsU0FBUyxJQUFJLG1CQUFtQixDQUFDO0lBQzFDLENBQUM7Q0FDRDtBQTNCRCw0Q0EyQkM7Ozs7Ozs7Ozs7Ozs7O0FDakNEOzs7Z0dBR2dHOztBQUVoRyxTQUFnQixrQkFBa0IsQ0FBQyxDQUFhO0lBQy9DLElBQUksUUFBUSxDQUFDLFVBQVUsS0FBSyxTQUFTLElBQUksUUFBUSxDQUFDLFVBQW9CLEtBQUssZUFBZSxFQUFFO1FBQzNGLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxrQkFBa0IsRUFBRSxDQUFDLENBQUMsQ0FBQztLQUNqRDtTQUFNO1FBQ04sQ0FBQyxFQUFFLENBQUM7S0FDSjtBQUNGLENBQUM7QUFORCxnREFNQzs7Ozs7Ozs7Ozs7Ozs7QUNYRDs7O2dHQUdnRzs7QUFFaEcsOEdBQXNEO0FBQ3RELGdGQUE4QztBQUM5Qyx5RkFBb0Q7QUFDcEQsK0ZBQXNIO0FBQ3RILHNGQUFrRDtBQUNsRCx1R0FBNkM7QUFJN0MsSUFBSSxjQUFjLEdBQUcsSUFBSSxDQUFDO0FBQzFCLE1BQU0sTUFBTSxHQUFHLElBQUksbUNBQWdCLEVBQUUsQ0FBQztBQUN0QyxNQUFNLFFBQVEsR0FBRyxzQkFBVyxFQUFFLENBQUM7QUFFL0IsTUFBTSxNQUFNLEdBQUcsZ0JBQWdCLEVBQUUsQ0FBQztBQUVsQyxvQkFBb0I7QUFDcEIsSUFBSSxLQUFLLEdBQUcsa0JBQU8sQ0FBc0MsWUFBWSxDQUFDLENBQUM7QUFDdkUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUV2QixNQUFNLFNBQVMsR0FBRyxpQ0FBcUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUVoRCxNQUFNLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUN2QyxNQUFNLENBQUMsbUJBQW1CLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBRWhELE1BQU0sQ0FBQyxNQUFNLEdBQUcsR0FBRyxFQUFFO0lBQ3BCLGdCQUFnQixFQUFFLENBQUM7QUFDcEIsQ0FBQyxDQUFDO0FBRUYsMkJBQWtCLENBQUMsR0FBRyxFQUFFO0lBQ3ZCLElBQUksUUFBUSxDQUFDLHVCQUF1QixFQUFFO1FBQ3JDLFVBQVUsQ0FBQyxHQUFHLEVBQUU7WUFDZix5Q0FBeUM7WUFDekMsSUFBSSxLQUFLLENBQUMsUUFBUSxFQUFFO2dCQUNuQixNQUFNLE9BQU8sR0FBRyx1Q0FBeUIsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQzFELElBQUksT0FBTyxFQUFFO29CQUNaLGNBQWMsR0FBRyxJQUFJLENBQUM7b0JBQ3RCLHNDQUF3QixDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztpQkFDdkM7YUFDRDtpQkFBTTtnQkFDTixNQUFNLFdBQVcsR0FBRyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7Z0JBQ25DLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUU7b0JBQ3hCLGNBQWMsR0FBRyxJQUFJLENBQUM7b0JBQ3RCLHNDQUF3QixDQUFDLFdBQVcsQ0FBQyxDQUFDO2lCQUN0QzthQUNEO1FBQ0YsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0tBQ047QUFDRixDQUFDLENBQUMsQ0FBQztBQUVILE1BQU0sWUFBWSxHQUFHLENBQUMsR0FBRyxFQUFFO0lBQzFCLE1BQU0sUUFBUSxHQUFHLFFBQVEsQ0FBQyxDQUFDLElBQVksRUFBRSxFQUFFO1FBQzFDLGNBQWMsR0FBRyxJQUFJLENBQUM7UUFDdEIsc0NBQXdCLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDaEMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBRVAsT0FBTyxDQUFDLElBQVksRUFBRSxRQUFhLEVBQUUsRUFBRTtRQUN0QyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQ2pCLFFBQVEsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1lBQ3JCLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUNmO0lBQ0YsQ0FBQyxDQUFDO0FBQ0gsQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUVMLElBQUksZ0JBQWdCLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRTtJQUNwQyxNQUFNLFNBQVMsR0FBb0QsRUFBRSxDQUFDO0lBQ3RFLElBQUksTUFBTSxHQUFHLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNsRCxJQUFJLE1BQU0sRUFBRTtRQUNYLElBQUksQ0FBQyxDQUFDO1FBQ04sS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ25DLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUV0QixJQUFJLEdBQUcsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUFFO2dCQUN0QyxHQUFHLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQzthQUNoQztZQUVELFNBQVMsQ0FBQyxJQUFJLENBQUM7Z0JBQ2QsRUFBRSxFQUFFLEdBQUcsQ0FBQyxFQUFFO2dCQUNWLE1BQU0sRUFBRSxHQUFHLENBQUMsTUFBTTtnQkFDbEIsS0FBSyxFQUFFLEdBQUcsQ0FBQyxLQUFLO2FBQ2hCLENBQUMsQ0FBQztTQUNIO1FBRUQsU0FBUyxDQUFDLFdBQVcsQ0FBQyxpQkFBaUIsRUFBRSxTQUFTLENBQUMsQ0FBQztLQUNwRDtBQUNGLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztBQUVQLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsR0FBRyxFQUFFO0lBQ3RDLGNBQWMsR0FBRyxJQUFJLENBQUM7SUFDdEIsZ0JBQWdCLEVBQUUsQ0FBQztBQUNwQixDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFFVCxNQUFNLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxFQUFFO0lBQzFDLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEtBQUssUUFBUSxDQUFDLE1BQU0sRUFBRTtRQUMxQyxPQUFPO0tBQ1A7SUFFRCxRQUFRLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFO1FBQ3hCLEtBQUssZ0NBQWdDO1lBQ3BDLE1BQU0sQ0FBQyw4QkFBOEIsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3ZELE1BQU07UUFFUCxLQUFLLFlBQVk7WUFDaEIsWUFBWSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQ3hDLE1BQU07S0FDUDtBQUNGLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztBQUVWLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLEVBQUU7SUFDN0MsSUFBSSxDQUFDLFFBQVEsQ0FBQywyQkFBMkIsRUFBRTtRQUMxQyxPQUFPO0tBQ1A7SUFFRCx5QkFBeUI7SUFDekIsS0FBSyxJQUFJLElBQUksR0FBRyxLQUFLLENBQUMsTUFBcUIsRUFBRSxJQUFJLEVBQUUsSUFBSSxHQUFHLElBQUksQ0FBQyxVQUF5QixFQUFFO1FBQ3pGLElBQUksSUFBSSxDQUFDLE9BQU8sS0FBSyxHQUFHLEVBQUU7WUFDekIsT0FBTztTQUNQO0tBQ0Q7SUFFRCxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO0lBQzNCLE1BQU0sSUFBSSxHQUFHLDhDQUFnQyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3RELElBQUksT0FBTyxJQUFJLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFO1FBQzdDLFNBQVMsQ0FBQyxXQUFXLENBQUMsVUFBVSxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0tBQzlEO0FBQ0YsQ0FBQyxDQUFDLENBQUM7QUFFSCxRQUFRLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxFQUFFO0lBQzFDLElBQUksQ0FBQyxLQUFLLEVBQUU7UUFDWCxPQUFPO0tBQ1A7SUFFRCxJQUFJLElBQUksR0FBUSxLQUFLLENBQUMsTUFBTSxDQUFDO0lBQzdCLE9BQU8sSUFBSSxFQUFFO1FBQ1osSUFBSSxJQUFJLENBQUMsT0FBTyxJQUFJLElBQUksQ0FBQyxPQUFPLEtBQUssR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUU7WUFDdEQsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRTtnQkFDOUMsTUFBTTthQUNOO1lBQ0QsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFO2dCQUN0SSxNQUFNLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLGdDQUFnQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxJQUFJLFlBQVksQ0FBQyxRQUFRLENBQUMsbUJBQW1CLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQ2xLLFNBQVMsQ0FBQyxXQUFXLENBQUMsV0FBVyxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7Z0JBQ3ZELEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDdkIsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO2dCQUN4QixNQUFNO2FBQ047WUFDRCxNQUFNO1NBQ047UUFDRCxJQUFJLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQztLQUN2QjtBQUNGLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztBQUVULElBQUksUUFBUSxDQUFDLHVCQUF1QixFQUFFO0lBQ3JDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLEdBQUcsRUFBRTtRQUMvQyxJQUFJLGNBQWMsRUFBRTtZQUNuQixjQUFjLEdBQUcsS0FBSyxDQUFDO1NBQ3ZCO2FBQU07WUFDTixNQUFNLElBQUksR0FBRyw4Q0FBZ0MsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDOUQsSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUU7Z0JBQzdDLFNBQVMsQ0FBQyxXQUFXLENBQUMsWUFBWSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDOUMsS0FBSyxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7Z0JBQ2xCLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7YUFDdkI7U0FDRDtJQUNGLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0NBQ1I7QUFFRCxTQUFTLFlBQVksQ0FBQyxJQUFZO0lBQ2pDLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQywwQkFBMEIsRUFBRSxNQUFNLENBQUMsQ0FBQztBQUN6RCxDQUFDOzs7Ozs7Ozs7Ozs7OztBQzVLRDs7O2dHQUdnRzs7QUFFaEcsc0ZBQXlDO0FBUzVCLDZCQUFxQixHQUFHLENBQUMsTUFBVyxFQUFFLEVBQUU7SUFDcEQsT0FBTyxJQUFJO1FBQ1YsV0FBVyxDQUFDLElBQVksRUFBRSxJQUFZO1lBQ3JDLE1BQU0sQ0FBQyxXQUFXLENBQUM7Z0JBQ2xCLElBQUk7Z0JBQ0osTUFBTSxFQUFFLHNCQUFXLEVBQUUsQ0FBQyxNQUFNO2dCQUM1QixJQUFJO2FBQ0osQ0FBQyxDQUFDO1FBQ0osQ0FBQztLQUNELENBQUM7QUFDSCxDQUFDLENBQUM7Ozs7Ozs7Ozs7Ozs7O0FDeEJGOzs7Z0dBR2dHOztBQUVoRyxzRkFBeUM7QUFHekMsU0FBUyxLQUFLLENBQUMsR0FBVyxFQUFFLEdBQVcsRUFBRSxLQUFhO0lBQ3JELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztBQUM1QyxDQUFDO0FBRUQsU0FBUyxTQUFTLENBQUMsSUFBWTtJQUM5QixPQUFPLEtBQUssQ0FBQyxDQUFDLEVBQUUsc0JBQVcsRUFBRSxDQUFDLFNBQVMsR0FBRyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFDcEQsQ0FBQztBQVFELE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxHQUFHLEVBQUU7SUFDakMsSUFBSSxRQUEyQixDQUFDO0lBQ2hDLE9BQU8sR0FBRyxFQUFFO1FBQ1gsSUFBSSxDQUFDLFFBQVEsRUFBRTtZQUNkLFFBQVEsR0FBRyxDQUFDLEVBQUUsT0FBTyxFQUFFLFFBQVEsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDakQsS0FBSyxNQUFNLE9BQU8sSUFBSSxRQUFRLENBQUMsc0JBQXNCLENBQUMsV0FBVyxDQUFDLEVBQUU7Z0JBQ25FLE1BQU0sSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUUsQ0FBQztnQkFDakQsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRTtvQkFDakIsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSxPQUFzQixFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7aUJBQ3pEO2FBQ0Q7U0FDRDtRQUNELE9BQU8sUUFBUSxDQUFDO0lBQ2pCLENBQUMsQ0FBQztBQUNILENBQUMsQ0FBQyxFQUFFLENBQUM7QUFFTDs7Ozs7R0FLRztBQUNILFNBQWdCLHdCQUF3QixDQUFDLFVBQWtCO0lBQzFELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDMUMsTUFBTSxLQUFLLEdBQUcsbUJBQW1CLEVBQUUsQ0FBQztJQUNwQyxJQUFJLFFBQVEsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDO0lBQ2hDLEtBQUssTUFBTSxLQUFLLElBQUksS0FBSyxFQUFFO1FBQzFCLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxVQUFVLEVBQUU7WUFDOUIsT0FBTyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxDQUFDO1NBQzVDO2FBQU0sSUFBSSxLQUFLLENBQUMsSUFBSSxHQUFHLFVBQVUsRUFBRTtZQUNuQyxPQUFPLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsQ0FBQztTQUNqQztRQUNELFFBQVEsR0FBRyxLQUFLLENBQUM7S0FDakI7SUFDRCxPQUFPLEVBQUUsUUFBUSxFQUFFLENBQUM7QUFDckIsQ0FBQztBQWJELDREQWFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQiwyQkFBMkIsQ0FBQyxNQUFjO0lBQ3pELE1BQU0sS0FBSyxHQUFHLG1CQUFtQixFQUFFLENBQUM7SUFDcEMsTUFBTSxRQUFRLEdBQUcsTUFBTSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUM7SUFDekMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDWixJQUFJLEVBQUUsR0FBRyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztJQUMxQixPQUFPLEVBQUUsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFO1FBQ25CLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDdEMsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1FBQzFELElBQUksTUFBTSxDQUFDLEdBQUcsR0FBRyxNQUFNLENBQUMsTUFBTSxJQUFJLFFBQVEsRUFBRTtZQUMzQyxFQUFFLEdBQUcsR0FBRyxDQUFDO1NBQ1Q7YUFDSTtZQUNKLEVBQUUsR0FBRyxHQUFHLENBQUM7U0FDVDtLQUNEO0lBQ0QsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzVCLE1BQU0sUUFBUSxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMscUJBQXFCLEVBQUUsQ0FBQztJQUMzRCxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksUUFBUSxDQUFDLEdBQUcsR0FBRyxRQUFRLEVBQUU7UUFDdkMsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzVCLE9BQU8sRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsQ0FBQztLQUNoRDtJQUNELE9BQU8sRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLENBQUM7QUFDaEMsQ0FBQztBQXRCRCxrRUFzQkM7QUFFRDs7R0FFRztBQUNILFNBQWdCLHdCQUF3QixDQUFDLElBQVk7SUFDcEQsSUFBSSxDQUFDLHNCQUFXLEVBQUUsQ0FBQyx1QkFBdUIsRUFBRTtRQUMzQyxPQUFPO0tBQ1A7SUFFRCxJQUFJLElBQUksSUFBSSxDQUFDLEVBQUU7UUFDZCxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDakMsT0FBTztLQUNQO0lBRUQsTUFBTSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsR0FBRyx3QkFBd0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMxRCxJQUFJLENBQUMsUUFBUSxFQUFFO1FBQ2QsT0FBTztLQUNQO0lBQ0QsSUFBSSxRQUFRLEdBQUcsQ0FBQyxDQUFDO0lBQ2pCLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMscUJBQXFCLEVBQUUsQ0FBQztJQUN0RCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQzdCLElBQUksSUFBSSxJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUSxDQUFDLElBQUksRUFBRTtRQUN4Qyw4REFBOEQ7UUFDOUQsTUFBTSxlQUFlLEdBQUcsQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDN0UsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsRUFBRSxDQUFDLEdBQUcsR0FBRyxXQUFXLENBQUM7UUFDN0UsUUFBUSxHQUFHLFdBQVcsR0FBRyxlQUFlLEdBQUcsYUFBYSxDQUFDO0tBQ3pEO1NBQU07UUFDTixNQUFNLGlCQUFpQixHQUFHLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2xELFFBQVEsR0FBRyxXQUFXLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLGlCQUFpQixDQUFDLENBQUM7S0FDM0Q7SUFDRCxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLE9BQU8sR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDO0FBQ3ZFLENBQUM7QUEzQkQsNERBMkJDO0FBRUQsU0FBZ0IsZ0NBQWdDLENBQUMsTUFBYztJQUM5RCxNQUFNLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxHQUFHLDJCQUEyQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQy9ELElBQUksUUFBUSxFQUFFO1FBQ2IsTUFBTSxjQUFjLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1FBQ2hFLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDLE9BQU8sR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDMUUsSUFBSSxJQUFJLEVBQUU7WUFDVCxNQUFNLHVCQUF1QixHQUFHLGtCQUFrQixHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsRUFBRSxDQUFDLEdBQUcsR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDckgsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLElBQUksR0FBRyx1QkFBdUIsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ25GLE9BQU8sU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ3ZCO2FBQ0k7WUFDSixNQUFNLHFCQUFxQixHQUFHLGtCQUFrQixHQUFHLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQzNFLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxJQUFJLEdBQUcscUJBQXFCLENBQUM7WUFDbkQsT0FBTyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDdkI7S0FDRDtJQUNELE9BQU8sSUFBSSxDQUFDO0FBQ2IsQ0FBQztBQWpCRCw0RUFpQkM7QUFFRDs7R0FFRztBQUNILFNBQWdCLHlCQUF5QixDQUFDLFFBQWdCO0lBQ3pELE9BQU8sbUJBQW1CLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtRQUM3QyxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxLQUFLLFFBQVEsQ0FBQztJQUN4QyxDQUFDLENBQUMsQ0FBQztBQUNKLENBQUM7QUFKRCw4REFJQzs7Ozs7Ozs7Ozs7Ozs7QUNoSkQ7OztnR0FHZ0c7O0FBYWhHLElBQUksY0FBYyxHQUFnQyxTQUFTLENBQUM7QUFFNUQsU0FBZ0IsT0FBTyxDQUFTLEdBQVc7SUFDMUMsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDLGNBQWMsQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO0lBQ3hFLElBQUksT0FBTyxFQUFFO1FBQ1osTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN2QyxJQUFJLElBQUksRUFBRTtZQUNULE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUN4QjtLQUNEO0lBRUQsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsR0FBRyxFQUFFLENBQUMsQ0FBQztBQUNuRCxDQUFDO0FBVkQsMEJBVUM7QUFFRCxTQUFnQixXQUFXO0lBQzFCLElBQUksY0FBYyxFQUFFO1FBQ25CLE9BQU8sY0FBYyxDQUFDO0tBQ3RCO0lBRUQsY0FBYyxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUMxQyxJQUFJLGNBQWMsRUFBRTtRQUNuQixPQUFPLGNBQWMsQ0FBQztLQUN0QjtJQUVELE1BQU0sSUFBSSxLQUFLLENBQUMseUJBQXlCLENBQUMsQ0FBQztBQUM1QyxDQUFDO0FBWEQsa0NBV0MiLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VzQ29udGVudCI6WyIgXHQvLyBUaGUgbW9kdWxlIGNhY2hlXG4gXHR2YXIgaW5zdGFsbGVkTW9kdWxlcyA9IHt9O1xuXG4gXHQvLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuIFx0ZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXG4gXHRcdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxuIFx0XHRpZihpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSkge1xuIFx0XHRcdHJldHVybiBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXS5leHBvcnRzO1xuIFx0XHR9XG4gXHRcdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG4gXHRcdHZhciBtb2R1bGUgPSBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSA9IHtcbiBcdFx0XHRpOiBtb2R1bGVJZCxcbiBcdFx0XHRsOiBmYWxzZSxcbiBcdFx0XHRleHBvcnRzOiB7fVxuIFx0XHR9O1xuXG4gXHRcdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuIFx0XHRtb2R1bGVzW21vZHVsZUlkXS5jYWxsKG1vZHVsZS5leHBvcnRzLCBtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuIFx0XHQvLyBGbGFnIHRoZSBtb2R1bGUgYXMgbG9hZGVkXG4gXHRcdG1vZHVsZS5sID0gdHJ1ZTtcblxuIFx0XHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuIFx0XHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG4gXHR9XG5cblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGVzIG9iamVjdCAoX193ZWJwYWNrX21vZHVsZXNfXylcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubSA9IG1vZHVsZXM7XG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlIGNhY2hlXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmMgPSBpbnN0YWxsZWRNb2R1bGVzO1xuXG4gXHQvLyBkZWZpbmUgZ2V0dGVyIGZ1bmN0aW9uIGZvciBoYXJtb255IGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uZCA9IGZ1bmN0aW9uKGV4cG9ydHMsIG5hbWUsIGdldHRlcikge1xuIFx0XHRpZighX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIG5hbWUpKSB7XG4gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIG5hbWUsIHtcbiBcdFx0XHRcdGNvbmZpZ3VyYWJsZTogZmFsc2UsXG4gXHRcdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuIFx0XHRcdFx0Z2V0OiBnZXR0ZXJcbiBcdFx0XHR9KTtcbiBcdFx0fVxuIFx0fTtcblxuIFx0Ly8gZGVmaW5lIF9fZXNNb2R1bGUgb24gZXhwb3J0c1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5yID0gZnVuY3Rpb24oZXhwb3J0cykge1xuIFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgJ19fZXNNb2R1bGUnLCB7IHZhbHVlOiB0cnVlIH0pO1xuIFx0fTtcblxuIFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubiA9IGZ1bmN0aW9uKG1vZHVsZSkge1xuIFx0XHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cbiBcdFx0XHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuIFx0XHRcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18uZChnZXR0ZXIsICdhJywgZ2V0dGVyKTtcbiBcdFx0cmV0dXJuIGdldHRlcjtcbiBcdH07XG5cbiBcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkgeyByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpOyB9O1xuXG4gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCJcIjtcblxuXG4gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbiBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IFwiLi9wcmV2aWV3LXNyYy9pbmRleC50c1wiKTtcbiIsIi8qKlxuICogbG9kYXNoIChDdXN0b20gQnVpbGQpIDxodHRwczovL2xvZGFzaC5jb20vPlxuICogQnVpbGQ6IGBsb2Rhc2ggbW9kdWxhcml6ZSBleHBvcnRzPVwibnBtXCIgLW8gLi9gXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9ycyA8aHR0cHM6Ly9qcXVlcnkub3JnLz5cbiAqIFJlbGVhc2VkIHVuZGVyIE1JVCBsaWNlbnNlIDxodHRwczovL2xvZGFzaC5jb20vbGljZW5zZT5cbiAqIEJhc2VkIG9uIFVuZGVyc2NvcmUuanMgMS44LjMgPGh0dHA6Ly91bmRlcnNjb3JlanMub3JnL0xJQ0VOU0U+XG4gKiBDb3B5cmlnaHQgSmVyZW15IEFzaGtlbmFzLCBEb2N1bWVudENsb3VkIGFuZCBJbnZlc3RpZ2F0aXZlIFJlcG9ydGVycyAmIEVkaXRvcnNcbiAqL1xuXG4vKiogVXNlZCBhcyB0aGUgYFR5cGVFcnJvcmAgbWVzc2FnZSBmb3IgXCJGdW5jdGlvbnNcIiBtZXRob2RzLiAqL1xudmFyIEZVTkNfRVJST1JfVEVYVCA9ICdFeHBlY3RlZCBhIGZ1bmN0aW9uJztcblxuLyoqIFVzZWQgYXMgcmVmZXJlbmNlcyBmb3IgdmFyaW91cyBgTnVtYmVyYCBjb25zdGFudHMuICovXG52YXIgTkFOID0gMCAvIDA7XG5cbi8qKiBgT2JqZWN0I3RvU3RyaW5nYCByZXN1bHQgcmVmZXJlbmNlcy4gKi9cbnZhciBzeW1ib2xUYWcgPSAnW29iamVjdCBTeW1ib2xdJztcblxuLyoqIFVzZWQgdG8gbWF0Y2ggbGVhZGluZyBhbmQgdHJhaWxpbmcgd2hpdGVzcGFjZS4gKi9cbnZhciByZVRyaW0gPSAvXlxccyt8XFxzKyQvZztcblxuLyoqIFVzZWQgdG8gZGV0ZWN0IGJhZCBzaWduZWQgaGV4YWRlY2ltYWwgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzQmFkSGV4ID0gL15bLStdMHhbMC05YS1mXSskL2k7XG5cbi8qKiBVc2VkIHRvIGRldGVjdCBiaW5hcnkgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzQmluYXJ5ID0gL14wYlswMV0rJC9pO1xuXG4vKiogVXNlZCB0byBkZXRlY3Qgb2N0YWwgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzT2N0YWwgPSAvXjBvWzAtN10rJC9pO1xuXG4vKiogQnVpbHQtaW4gbWV0aG9kIHJlZmVyZW5jZXMgd2l0aG91dCBhIGRlcGVuZGVuY3kgb24gYHJvb3RgLiAqL1xudmFyIGZyZWVQYXJzZUludCA9IHBhcnNlSW50O1xuXG4vKiogRGV0ZWN0IGZyZWUgdmFyaWFibGUgYGdsb2JhbGAgZnJvbSBOb2RlLmpzLiAqL1xudmFyIGZyZWVHbG9iYWwgPSB0eXBlb2YgZ2xvYmFsID09ICdvYmplY3QnICYmIGdsb2JhbCAmJiBnbG9iYWwuT2JqZWN0ID09PSBPYmplY3QgJiYgZ2xvYmFsO1xuXG4vKiogRGV0ZWN0IGZyZWUgdmFyaWFibGUgYHNlbGZgLiAqL1xudmFyIGZyZWVTZWxmID0gdHlwZW9mIHNlbGYgPT0gJ29iamVjdCcgJiYgc2VsZiAmJiBzZWxmLk9iamVjdCA9PT0gT2JqZWN0ICYmIHNlbGY7XG5cbi8qKiBVc2VkIGFzIGEgcmVmZXJlbmNlIHRvIHRoZSBnbG9iYWwgb2JqZWN0LiAqL1xudmFyIHJvb3QgPSBmcmVlR2xvYmFsIHx8IGZyZWVTZWxmIHx8IEZ1bmN0aW9uKCdyZXR1cm4gdGhpcycpKCk7XG5cbi8qKiBVc2VkIGZvciBidWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcy4gKi9cbnZhciBvYmplY3RQcm90byA9IE9iamVjdC5wcm90b3R5cGU7XG5cbi8qKlxuICogVXNlZCB0byByZXNvbHZlIHRoZVxuICogW2B0b1N0cmluZ1RhZ2BdKGh0dHA6Ly9lY21hLWludGVybmF0aW9uYWwub3JnL2VjbWEtMjYyLzcuMC8jc2VjLW9iamVjdC5wcm90b3R5cGUudG9zdHJpbmcpXG4gKiBvZiB2YWx1ZXMuXG4gKi9cbnZhciBvYmplY3RUb1N0cmluZyA9IG9iamVjdFByb3RvLnRvU3RyaW5nO1xuXG4vKiBCdWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcyBmb3IgdGhvc2Ugd2l0aCB0aGUgc2FtZSBuYW1lIGFzIG90aGVyIGBsb2Rhc2hgIG1ldGhvZHMuICovXG52YXIgbmF0aXZlTWF4ID0gTWF0aC5tYXgsXG4gICAgbmF0aXZlTWluID0gTWF0aC5taW47XG5cbi8qKlxuICogR2V0cyB0aGUgdGltZXN0YW1wIG9mIHRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRoYXQgaGF2ZSBlbGFwc2VkIHNpbmNlXG4gKiB0aGUgVW5peCBlcG9jaCAoMSBKYW51YXJ5IDE5NzAgMDA6MDA6MDAgVVRDKS5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDIuNC4wXG4gKiBAY2F0ZWdvcnkgRGF0ZVxuICogQHJldHVybnMge251bWJlcn0gUmV0dXJucyB0aGUgdGltZXN0YW1wLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmRlZmVyKGZ1bmN0aW9uKHN0YW1wKSB7XG4gKiAgIGNvbnNvbGUubG9nKF8ubm93KCkgLSBzdGFtcCk7XG4gKiB9LCBfLm5vdygpKTtcbiAqIC8vID0+IExvZ3MgdGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgaXQgdG9vayBmb3IgdGhlIGRlZmVycmVkIGludm9jYXRpb24uXG4gKi9cbnZhciBub3cgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIHJvb3QuRGF0ZS5ub3coKTtcbn07XG5cbi8qKlxuICogQ3JlYXRlcyBhIGRlYm91bmNlZCBmdW5jdGlvbiB0aGF0IGRlbGF5cyBpbnZva2luZyBgZnVuY2AgdW50aWwgYWZ0ZXIgYHdhaXRgXG4gKiBtaWxsaXNlY29uZHMgaGF2ZSBlbGFwc2VkIHNpbmNlIHRoZSBsYXN0IHRpbWUgdGhlIGRlYm91bmNlZCBmdW5jdGlvbiB3YXNcbiAqIGludm9rZWQuIFRoZSBkZWJvdW5jZWQgZnVuY3Rpb24gY29tZXMgd2l0aCBhIGBjYW5jZWxgIG1ldGhvZCB0byBjYW5jZWxcbiAqIGRlbGF5ZWQgYGZ1bmNgIGludm9jYXRpb25zIGFuZCBhIGBmbHVzaGAgbWV0aG9kIHRvIGltbWVkaWF0ZWx5IGludm9rZSB0aGVtLlxuICogUHJvdmlkZSBgb3B0aW9uc2AgdG8gaW5kaWNhdGUgd2hldGhlciBgZnVuY2Agc2hvdWxkIGJlIGludm9rZWQgb24gdGhlXG4gKiBsZWFkaW5nIGFuZC9vciB0cmFpbGluZyBlZGdlIG9mIHRoZSBgd2FpdGAgdGltZW91dC4gVGhlIGBmdW5jYCBpcyBpbnZva2VkXG4gKiB3aXRoIHRoZSBsYXN0IGFyZ3VtZW50cyBwcm92aWRlZCB0byB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uLiBTdWJzZXF1ZW50XG4gKiBjYWxscyB0byB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uIHJldHVybiB0aGUgcmVzdWx0IG9mIHRoZSBsYXN0IGBmdW5jYFxuICogaW52b2NhdGlvbi5cbiAqXG4gKiAqKk5vdGU6KiogSWYgYGxlYWRpbmdgIGFuZCBgdHJhaWxpbmdgIG9wdGlvbnMgYXJlIGB0cnVlYCwgYGZ1bmNgIGlzXG4gKiBpbnZva2VkIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0IG9ubHkgaWYgdGhlIGRlYm91bmNlZCBmdW5jdGlvblxuICogaXMgaW52b2tlZCBtb3JlIHRoYW4gb25jZSBkdXJpbmcgdGhlIGB3YWl0YCB0aW1lb3V0LlxuICpcbiAqIElmIGB3YWl0YCBpcyBgMGAgYW5kIGBsZWFkaW5nYCBpcyBgZmFsc2VgLCBgZnVuY2AgaW52b2NhdGlvbiBpcyBkZWZlcnJlZFxuICogdW50aWwgdG8gdGhlIG5leHQgdGljaywgc2ltaWxhciB0byBgc2V0VGltZW91dGAgd2l0aCBhIHRpbWVvdXQgb2YgYDBgLlxuICpcbiAqIFNlZSBbRGF2aWQgQ29yYmFjaG8ncyBhcnRpY2xlXShodHRwczovL2Nzcy10cmlja3MuY29tL2RlYm91bmNpbmctdGhyb3R0bGluZy1leHBsYWluZWQtZXhhbXBsZXMvKVxuICogZm9yIGRldGFpbHMgb3ZlciB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBgXy5kZWJvdW5jZWAgYW5kIGBfLnRocm90dGxlYC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDAuMS4wXG4gKiBAY2F0ZWdvcnkgRnVuY3Rpb25cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGRlYm91bmNlLlxuICogQHBhcmFtIHtudW1iZXJ9IFt3YWl0PTBdIFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIGRlbGF5LlxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zPXt9XSBUaGUgb3B0aW9ucyBvYmplY3QuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxlYWRpbmc9ZmFsc2VdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgbGVhZGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLm1heFdhaXRdXG4gKiAgVGhlIG1heGltdW0gdGltZSBgZnVuY2AgaXMgYWxsb3dlZCB0byBiZSBkZWxheWVkIGJlZm9yZSBpdCdzIGludm9rZWQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnRyYWlsaW5nPXRydWVdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgdHJhaWxpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGRlYm91bmNlZCBmdW5jdGlvbi5cbiAqIEBleGFtcGxlXG4gKlxuICogLy8gQXZvaWQgY29zdGx5IGNhbGN1bGF0aW9ucyB3aGlsZSB0aGUgd2luZG93IHNpemUgaXMgaW4gZmx1eC5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdyZXNpemUnLCBfLmRlYm91bmNlKGNhbGN1bGF0ZUxheW91dCwgMTUwKSk7XG4gKlxuICogLy8gSW52b2tlIGBzZW5kTWFpbGAgd2hlbiBjbGlja2VkLCBkZWJvdW5jaW5nIHN1YnNlcXVlbnQgY2FsbHMuXG4gKiBqUXVlcnkoZWxlbWVudCkub24oJ2NsaWNrJywgXy5kZWJvdW5jZShzZW5kTWFpbCwgMzAwLCB7XG4gKiAgICdsZWFkaW5nJzogdHJ1ZSxcbiAqICAgJ3RyYWlsaW5nJzogZmFsc2VcbiAqIH0pKTtcbiAqXG4gKiAvLyBFbnN1cmUgYGJhdGNoTG9nYCBpcyBpbnZva2VkIG9uY2UgYWZ0ZXIgMSBzZWNvbmQgb2YgZGVib3VuY2VkIGNhbGxzLlxuICogdmFyIGRlYm91bmNlZCA9IF8uZGVib3VuY2UoYmF0Y2hMb2csIDI1MCwgeyAnbWF4V2FpdCc6IDEwMDAgfSk7XG4gKiB2YXIgc291cmNlID0gbmV3IEV2ZW50U291cmNlKCcvc3RyZWFtJyk7XG4gKiBqUXVlcnkoc291cmNlKS5vbignbWVzc2FnZScsIGRlYm91bmNlZCk7XG4gKlxuICogLy8gQ2FuY2VsIHRoZSB0cmFpbGluZyBkZWJvdW5jZWQgaW52b2NhdGlvbi5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdwb3BzdGF0ZScsIGRlYm91bmNlZC5jYW5jZWwpO1xuICovXG5mdW5jdGlvbiBkZWJvdW5jZShmdW5jLCB3YWl0LCBvcHRpb25zKSB7XG4gIHZhciBsYXN0QXJncyxcbiAgICAgIGxhc3RUaGlzLFxuICAgICAgbWF4V2FpdCxcbiAgICAgIHJlc3VsdCxcbiAgICAgIHRpbWVySWQsXG4gICAgICBsYXN0Q2FsbFRpbWUsXG4gICAgICBsYXN0SW52b2tlVGltZSA9IDAsXG4gICAgICBsZWFkaW5nID0gZmFsc2UsXG4gICAgICBtYXhpbmcgPSBmYWxzZSxcbiAgICAgIHRyYWlsaW5nID0gdHJ1ZTtcblxuICBpZiAodHlwZW9mIGZ1bmMgIT0gJ2Z1bmN0aW9uJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoRlVOQ19FUlJPUl9URVhUKTtcbiAgfVxuICB3YWl0ID0gdG9OdW1iZXIod2FpdCkgfHwgMDtcbiAgaWYgKGlzT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgbGVhZGluZyA9ICEhb3B0aW9ucy5sZWFkaW5nO1xuICAgIG1heGluZyA9ICdtYXhXYWl0JyBpbiBvcHRpb25zO1xuICAgIG1heFdhaXQgPSBtYXhpbmcgPyBuYXRpdmVNYXgodG9OdW1iZXIob3B0aW9ucy5tYXhXYWl0KSB8fCAwLCB3YWl0KSA6IG1heFdhaXQ7XG4gICAgdHJhaWxpbmcgPSAndHJhaWxpbmcnIGluIG9wdGlvbnMgPyAhIW9wdGlvbnMudHJhaWxpbmcgOiB0cmFpbGluZztcbiAgfVxuXG4gIGZ1bmN0aW9uIGludm9rZUZ1bmModGltZSkge1xuICAgIHZhciBhcmdzID0gbGFzdEFyZ3MsXG4gICAgICAgIHRoaXNBcmcgPSBsYXN0VGhpcztcblxuICAgIGxhc3RBcmdzID0gbGFzdFRoaXMgPSB1bmRlZmluZWQ7XG4gICAgbGFzdEludm9rZVRpbWUgPSB0aW1lO1xuICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkodGhpc0FyZywgYXJncyk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGxlYWRpbmdFZGdlKHRpbWUpIHtcbiAgICAvLyBSZXNldCBhbnkgYG1heFdhaXRgIHRpbWVyLlxuICAgIGxhc3RJbnZva2VUaW1lID0gdGltZTtcbiAgICAvLyBTdGFydCB0aGUgdGltZXIgZm9yIHRoZSB0cmFpbGluZyBlZGdlLlxuICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgd2FpdCk7XG4gICAgLy8gSW52b2tlIHRoZSBsZWFkaW5nIGVkZ2UuXG4gICAgcmV0dXJuIGxlYWRpbmcgPyBpbnZva2VGdW5jKHRpbWUpIDogcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gcmVtYWluaW5nV2FpdCh0aW1lKSB7XG4gICAgdmFyIHRpbWVTaW5jZUxhc3RDYWxsID0gdGltZSAtIGxhc3RDYWxsVGltZSxcbiAgICAgICAgdGltZVNpbmNlTGFzdEludm9rZSA9IHRpbWUgLSBsYXN0SW52b2tlVGltZSxcbiAgICAgICAgcmVzdWx0ID0gd2FpdCAtIHRpbWVTaW5jZUxhc3RDYWxsO1xuXG4gICAgcmV0dXJuIG1heGluZyA/IG5hdGl2ZU1pbihyZXN1bHQsIG1heFdhaXQgLSB0aW1lU2luY2VMYXN0SW52b2tlKSA6IHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIHNob3VsZEludm9rZSh0aW1lKSB7XG4gICAgdmFyIHRpbWVTaW5jZUxhc3RDYWxsID0gdGltZSAtIGxhc3RDYWxsVGltZSxcbiAgICAgICAgdGltZVNpbmNlTGFzdEludm9rZSA9IHRpbWUgLSBsYXN0SW52b2tlVGltZTtcblxuICAgIC8vIEVpdGhlciB0aGlzIGlzIHRoZSBmaXJzdCBjYWxsLCBhY3Rpdml0eSBoYXMgc3RvcHBlZCBhbmQgd2UncmUgYXQgdGhlXG4gICAgLy8gdHJhaWxpbmcgZWRnZSwgdGhlIHN5c3RlbSB0aW1lIGhhcyBnb25lIGJhY2t3YXJkcyBhbmQgd2UncmUgdHJlYXRpbmdcbiAgICAvLyBpdCBhcyB0aGUgdHJhaWxpbmcgZWRnZSwgb3Igd2UndmUgaGl0IHRoZSBgbWF4V2FpdGAgbGltaXQuXG4gICAgcmV0dXJuIChsYXN0Q2FsbFRpbWUgPT09IHVuZGVmaW5lZCB8fCAodGltZVNpbmNlTGFzdENhbGwgPj0gd2FpdCkgfHxcbiAgICAgICh0aW1lU2luY2VMYXN0Q2FsbCA8IDApIHx8IChtYXhpbmcgJiYgdGltZVNpbmNlTGFzdEludm9rZSA+PSBtYXhXYWl0KSk7XG4gIH1cblxuICBmdW5jdGlvbiB0aW1lckV4cGlyZWQoKSB7XG4gICAgdmFyIHRpbWUgPSBub3coKTtcbiAgICBpZiAoc2hvdWxkSW52b2tlKHRpbWUpKSB7XG4gICAgICByZXR1cm4gdHJhaWxpbmdFZGdlKHRpbWUpO1xuICAgIH1cbiAgICAvLyBSZXN0YXJ0IHRoZSB0aW1lci5cbiAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHJlbWFpbmluZ1dhaXQodGltZSkpO1xuICB9XG5cbiAgZnVuY3Rpb24gdHJhaWxpbmdFZGdlKHRpbWUpIHtcbiAgICB0aW1lcklkID0gdW5kZWZpbmVkO1xuXG4gICAgLy8gT25seSBpbnZva2UgaWYgd2UgaGF2ZSBgbGFzdEFyZ3NgIHdoaWNoIG1lYW5zIGBmdW5jYCBoYXMgYmVlblxuICAgIC8vIGRlYm91bmNlZCBhdCBsZWFzdCBvbmNlLlxuICAgIGlmICh0cmFpbGluZyAmJiBsYXN0QXJncykge1xuICAgICAgcmV0dXJuIGludm9rZUZ1bmModGltZSk7XG4gICAgfVxuICAgIGxhc3RBcmdzID0gbGFzdFRoaXMgPSB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGNhbmNlbCgpIHtcbiAgICBpZiAodGltZXJJZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjbGVhclRpbWVvdXQodGltZXJJZCk7XG4gICAgfVxuICAgIGxhc3RJbnZva2VUaW1lID0gMDtcbiAgICBsYXN0QXJncyA9IGxhc3RDYWxsVGltZSA9IGxhc3RUaGlzID0gdGltZXJJZCA9IHVuZGVmaW5lZDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGZsdXNoKCkge1xuICAgIHJldHVybiB0aW1lcklkID09PSB1bmRlZmluZWQgPyByZXN1bHQgOiB0cmFpbGluZ0VkZ2Uobm93KCkpO1xuICB9XG5cbiAgZnVuY3Rpb24gZGVib3VuY2VkKCkge1xuICAgIHZhciB0aW1lID0gbm93KCksXG4gICAgICAgIGlzSW52b2tpbmcgPSBzaG91bGRJbnZva2UodGltZSk7XG5cbiAgICBsYXN0QXJncyA9IGFyZ3VtZW50cztcbiAgICBsYXN0VGhpcyA9IHRoaXM7XG4gICAgbGFzdENhbGxUaW1lID0gdGltZTtcblxuICAgIGlmIChpc0ludm9raW5nKSB7XG4gICAgICBpZiAodGltZXJJZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBsZWFkaW5nRWRnZShsYXN0Q2FsbFRpbWUpO1xuICAgICAgfVxuICAgICAgaWYgKG1heGluZykge1xuICAgICAgICAvLyBIYW5kbGUgaW52b2NhdGlvbnMgaW4gYSB0aWdodCBsb29wLlxuICAgICAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHdhaXQpO1xuICAgICAgICByZXR1cm4gaW52b2tlRnVuYyhsYXN0Q2FsbFRpbWUpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAodGltZXJJZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHdhaXQpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG4gIGRlYm91bmNlZC5jYW5jZWwgPSBjYW5jZWw7XG4gIGRlYm91bmNlZC5mbHVzaCA9IGZsdXNoO1xuICByZXR1cm4gZGVib3VuY2VkO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSB0aHJvdHRsZWQgZnVuY3Rpb24gdGhhdCBvbmx5IGludm9rZXMgYGZ1bmNgIGF0IG1vc3Qgb25jZSBwZXJcbiAqIGV2ZXJ5IGB3YWl0YCBtaWxsaXNlY29uZHMuIFRoZSB0aHJvdHRsZWQgZnVuY3Rpb24gY29tZXMgd2l0aCBhIGBjYW5jZWxgXG4gKiBtZXRob2QgdG8gY2FuY2VsIGRlbGF5ZWQgYGZ1bmNgIGludm9jYXRpb25zIGFuZCBhIGBmbHVzaGAgbWV0aG9kIHRvXG4gKiBpbW1lZGlhdGVseSBpbnZva2UgdGhlbS4gUHJvdmlkZSBgb3B0aW9uc2AgdG8gaW5kaWNhdGUgd2hldGhlciBgZnVuY2BcbiAqIHNob3VsZCBiZSBpbnZva2VkIG9uIHRoZSBsZWFkaW5nIGFuZC9vciB0cmFpbGluZyBlZGdlIG9mIHRoZSBgd2FpdGBcbiAqIHRpbWVvdXQuIFRoZSBgZnVuY2AgaXMgaW52b2tlZCB3aXRoIHRoZSBsYXN0IGFyZ3VtZW50cyBwcm92aWRlZCB0byB0aGVcbiAqIHRocm90dGxlZCBmdW5jdGlvbi4gU3Vic2VxdWVudCBjYWxscyB0byB0aGUgdGhyb3R0bGVkIGZ1bmN0aW9uIHJldHVybiB0aGVcbiAqIHJlc3VsdCBvZiB0aGUgbGFzdCBgZnVuY2AgaW52b2NhdGlvbi5cbiAqXG4gKiAqKk5vdGU6KiogSWYgYGxlYWRpbmdgIGFuZCBgdHJhaWxpbmdgIG9wdGlvbnMgYXJlIGB0cnVlYCwgYGZ1bmNgIGlzXG4gKiBpbnZva2VkIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0IG9ubHkgaWYgdGhlIHRocm90dGxlZCBmdW5jdGlvblxuICogaXMgaW52b2tlZCBtb3JlIHRoYW4gb25jZSBkdXJpbmcgdGhlIGB3YWl0YCB0aW1lb3V0LlxuICpcbiAqIElmIGB3YWl0YCBpcyBgMGAgYW5kIGBsZWFkaW5nYCBpcyBgZmFsc2VgLCBgZnVuY2AgaW52b2NhdGlvbiBpcyBkZWZlcnJlZFxuICogdW50aWwgdG8gdGhlIG5leHQgdGljaywgc2ltaWxhciB0byBgc2V0VGltZW91dGAgd2l0aCBhIHRpbWVvdXQgb2YgYDBgLlxuICpcbiAqIFNlZSBbRGF2aWQgQ29yYmFjaG8ncyBhcnRpY2xlXShodHRwczovL2Nzcy10cmlja3MuY29tL2RlYm91bmNpbmctdGhyb3R0bGluZy1leHBsYWluZWQtZXhhbXBsZXMvKVxuICogZm9yIGRldGFpbHMgb3ZlciB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBgXy50aHJvdHRsZWAgYW5kIGBfLmRlYm91bmNlYC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDAuMS4wXG4gKiBAY2F0ZWdvcnkgRnVuY3Rpb25cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIHRocm90dGxlLlxuICogQHBhcmFtIHtudW1iZXJ9IFt3YWl0PTBdIFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHRocm90dGxlIGludm9jYXRpb25zIHRvLlxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zPXt9XSBUaGUgb3B0aW9ucyBvYmplY3QuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxlYWRpbmc9dHJ1ZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSBsZWFkaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnRyYWlsaW5nPXRydWVdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgdHJhaWxpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IHRocm90dGxlZCBmdW5jdGlvbi5cbiAqIEBleGFtcGxlXG4gKlxuICogLy8gQXZvaWQgZXhjZXNzaXZlbHkgdXBkYXRpbmcgdGhlIHBvc2l0aW9uIHdoaWxlIHNjcm9sbGluZy5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdzY3JvbGwnLCBfLnRocm90dGxlKHVwZGF0ZVBvc2l0aW9uLCAxMDApKTtcbiAqXG4gKiAvLyBJbnZva2UgYHJlbmV3VG9rZW5gIHdoZW4gdGhlIGNsaWNrIGV2ZW50IGlzIGZpcmVkLCBidXQgbm90IG1vcmUgdGhhbiBvbmNlIGV2ZXJ5IDUgbWludXRlcy5cbiAqIHZhciB0aHJvdHRsZWQgPSBfLnRocm90dGxlKHJlbmV3VG9rZW4sIDMwMDAwMCwgeyAndHJhaWxpbmcnOiBmYWxzZSB9KTtcbiAqIGpRdWVyeShlbGVtZW50KS5vbignY2xpY2snLCB0aHJvdHRsZWQpO1xuICpcbiAqIC8vIENhbmNlbCB0aGUgdHJhaWxpbmcgdGhyb3R0bGVkIGludm9jYXRpb24uXG4gKiBqUXVlcnkod2luZG93KS5vbigncG9wc3RhdGUnLCB0aHJvdHRsZWQuY2FuY2VsKTtcbiAqL1xuZnVuY3Rpb24gdGhyb3R0bGUoZnVuYywgd2FpdCwgb3B0aW9ucykge1xuICB2YXIgbGVhZGluZyA9IHRydWUsXG4gICAgICB0cmFpbGluZyA9IHRydWU7XG5cbiAgaWYgKHR5cGVvZiBmdW5jICE9ICdmdW5jdGlvbicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKEZVTkNfRVJST1JfVEVYVCk7XG4gIH1cbiAgaWYgKGlzT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgbGVhZGluZyA9ICdsZWFkaW5nJyBpbiBvcHRpb25zID8gISFvcHRpb25zLmxlYWRpbmcgOiBsZWFkaW5nO1xuICAgIHRyYWlsaW5nID0gJ3RyYWlsaW5nJyBpbiBvcHRpb25zID8gISFvcHRpb25zLnRyYWlsaW5nIDogdHJhaWxpbmc7XG4gIH1cbiAgcmV0dXJuIGRlYm91bmNlKGZ1bmMsIHdhaXQsIHtcbiAgICAnbGVhZGluZyc6IGxlYWRpbmcsXG4gICAgJ21heFdhaXQnOiB3YWl0LFxuICAgICd0cmFpbGluZyc6IHRyYWlsaW5nXG4gIH0pO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIHRoZVxuICogW2xhbmd1YWdlIHR5cGVdKGh0dHA6Ly93d3cuZWNtYS1pbnRlcm5hdGlvbmFsLm9yZy9lY21hLTI2Mi83LjAvI3NlYy1lY21hc2NyaXB0LWxhbmd1YWdlLXR5cGVzKVxuICogb2YgYE9iamVjdGAuIChlLmcuIGFycmF5cywgZnVuY3Rpb25zLCBvYmplY3RzLCByZWdleGVzLCBgbmV3IE51bWJlcigwKWAsIGFuZCBgbmV3IFN0cmluZygnJylgKVxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMC4xLjBcbiAqIEBjYXRlZ29yeSBMYW5nXG4gKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiBgdmFsdWVgIGlzIGFuIG9iamVjdCwgZWxzZSBgZmFsc2VgLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmlzT2JqZWN0KHt9KTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0KFsxLCAyLCAzXSk7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc09iamVjdChfLm5vb3ApO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNPYmplY3QobnVsbCk7XG4gKiAvLyA9PiBmYWxzZVxuICovXG5mdW5jdGlvbiBpc09iamVjdCh2YWx1ZSkge1xuICB2YXIgdHlwZSA9IHR5cGVvZiB2YWx1ZTtcbiAgcmV0dXJuICEhdmFsdWUgJiYgKHR5cGUgPT0gJ29iamVjdCcgfHwgdHlwZSA9PSAnZnVuY3Rpb24nKTtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBvYmplY3QtbGlrZS4gQSB2YWx1ZSBpcyBvYmplY3QtbGlrZSBpZiBpdCdzIG5vdCBgbnVsbGBcbiAqIGFuZCBoYXMgYSBgdHlwZW9mYCByZXN1bHQgb2YgXCJvYmplY3RcIi5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDQuMC4wXG4gKiBAY2F0ZWdvcnkgTGFuZ1xuICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYHZhbHVlYCBpcyBvYmplY3QtbGlrZSwgZWxzZSBgZmFsc2VgLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZSh7fSk7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc09iamVjdExpa2UoWzEsIDIsIDNdKTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZShfLm5vb3ApO1xuICogLy8gPT4gZmFsc2VcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZShudWxsKTtcbiAqIC8vID0+IGZhbHNlXG4gKi9cbmZ1bmN0aW9uIGlzT2JqZWN0TGlrZSh2YWx1ZSkge1xuICByZXR1cm4gISF2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT0gJ29iamVjdCc7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgY2xhc3NpZmllZCBhcyBhIGBTeW1ib2xgIHByaW1pdGl2ZSBvciBvYmplY3QuXG4gKlxuICogQHN0YXRpY1xuICogQG1lbWJlck9mIF9cbiAqIEBzaW5jZSA0LjAuMFxuICogQGNhdGVnb3J5IExhbmdcbiAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGB2YWx1ZWAgaXMgYSBzeW1ib2wsIGVsc2UgYGZhbHNlYC5cbiAqIEBleGFtcGxlXG4gKlxuICogXy5pc1N5bWJvbChTeW1ib2wuaXRlcmF0b3IpO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNTeW1ib2woJ2FiYycpO1xuICogLy8gPT4gZmFsc2VcbiAqL1xuZnVuY3Rpb24gaXNTeW1ib2wodmFsdWUpIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PSAnc3ltYm9sJyB8fFxuICAgIChpc09iamVjdExpa2UodmFsdWUpICYmIG9iamVjdFRvU3RyaW5nLmNhbGwodmFsdWUpID09IHN5bWJvbFRhZyk7XG59XG5cbi8qKlxuICogQ29udmVydHMgYHZhbHVlYCB0byBhIG51bWJlci5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDQuMC4wXG4gKiBAY2F0ZWdvcnkgTGFuZ1xuICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gcHJvY2Vzcy5cbiAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIG51bWJlci5cbiAqIEBleGFtcGxlXG4gKlxuICogXy50b051bWJlcigzLjIpO1xuICogLy8gPT4gMy4yXG4gKlxuICogXy50b051bWJlcihOdW1iZXIuTUlOX1ZBTFVFKTtcbiAqIC8vID0+IDVlLTMyNFxuICpcbiAqIF8udG9OdW1iZXIoSW5maW5pdHkpO1xuICogLy8gPT4gSW5maW5pdHlcbiAqXG4gKiBfLnRvTnVtYmVyKCczLjInKTtcbiAqIC8vID0+IDMuMlxuICovXG5mdW5jdGlvbiB0b051bWJlcih2YWx1ZSkge1xuICBpZiAodHlwZW9mIHZhbHVlID09ICdudW1iZXInKSB7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9XG4gIGlmIChpc1N5bWJvbCh2YWx1ZSkpIHtcbiAgICByZXR1cm4gTkFOO1xuICB9XG4gIGlmIChpc09iamVjdCh2YWx1ZSkpIHtcbiAgICB2YXIgb3RoZXIgPSB0eXBlb2YgdmFsdWUudmFsdWVPZiA9PSAnZnVuY3Rpb24nID8gdmFsdWUudmFsdWVPZigpIDogdmFsdWU7XG4gICAgdmFsdWUgPSBpc09iamVjdChvdGhlcikgPyAob3RoZXIgKyAnJykgOiBvdGhlcjtcbiAgfVxuICBpZiAodHlwZW9mIHZhbHVlICE9ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIHZhbHVlID09PSAwID8gdmFsdWUgOiArdmFsdWU7XG4gIH1cbiAgdmFsdWUgPSB2YWx1ZS5yZXBsYWNlKHJlVHJpbSwgJycpO1xuICB2YXIgaXNCaW5hcnkgPSByZUlzQmluYXJ5LnRlc3QodmFsdWUpO1xuICByZXR1cm4gKGlzQmluYXJ5IHx8IHJlSXNPY3RhbC50ZXN0KHZhbHVlKSlcbiAgICA/IGZyZWVQYXJzZUludCh2YWx1ZS5zbGljZSgyKSwgaXNCaW5hcnkgPyAyIDogOClcbiAgICA6IChyZUlzQmFkSGV4LnRlc3QodmFsdWUpID8gTkFOIDogK3ZhbHVlKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB0aHJvdHRsZTtcbiIsInZhciBnO1xyXG5cclxuLy8gVGhpcyB3b3JrcyBpbiBub24tc3RyaWN0IG1vZGVcclxuZyA9IChmdW5jdGlvbigpIHtcclxuXHRyZXR1cm4gdGhpcztcclxufSkoKTtcclxuXHJcbnRyeSB7XHJcblx0Ly8gVGhpcyB3b3JrcyBpZiBldmFsIGlzIGFsbG93ZWQgKHNlZSBDU1ApXHJcblx0ZyA9IGcgfHwgRnVuY3Rpb24oXCJyZXR1cm4gdGhpc1wiKSgpIHx8ICgxLCBldmFsKShcInRoaXNcIik7XHJcbn0gY2F0Y2ggKGUpIHtcclxuXHQvLyBUaGlzIHdvcmtzIGlmIHRoZSB3aW5kb3cgcmVmZXJlbmNlIGlzIGF2YWlsYWJsZVxyXG5cdGlmICh0eXBlb2Ygd2luZG93ID09PSBcIm9iamVjdFwiKSBnID0gd2luZG93O1xyXG59XHJcblxyXG4vLyBnIGNhbiBzdGlsbCBiZSB1bmRlZmluZWQsIGJ1dCBub3RoaW5nIHRvIGRvIGFib3V0IGl0Li4uXHJcbi8vIFdlIHJldHVybiB1bmRlZmluZWQsIGluc3RlYWQgb2Ygbm90aGluZyBoZXJlLCBzbyBpdCdzXHJcbi8vIGVhc2llciB0byBoYW5kbGUgdGhpcyBjYXNlLiBpZighZ2xvYmFsKSB7IC4uLn1cclxuXHJcbm1vZHVsZS5leHBvcnRzID0gZztcclxuIiwiLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5pbXBvcnQgeyBnZXRFbGVtZW50c0ZvclNvdXJjZUxpbmUgfSBmcm9tICcuL3Njcm9sbC1zeW5jJztcblxuZXhwb3J0IGNsYXNzIEFjdGl2ZUxpbmVNYXJrZXIge1xuXHRwcml2YXRlIF9jdXJyZW50OiBhbnk7XG5cblx0b25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGxpbmU6IG51bWJlcikge1xuXHRcdGNvbnN0IHsgcHJldmlvdXMgfSA9IGdldEVsZW1lbnRzRm9yU291cmNlTGluZShsaW5lKTtcblx0XHR0aGlzLl91cGRhdGUocHJldmlvdXMgJiYgcHJldmlvdXMuZWxlbWVudCk7XG5cdH1cblxuXHRfdXBkYXRlKGJlZm9yZTogSFRNTEVsZW1lbnQgfCB1bmRlZmluZWQpIHtcblx0XHR0aGlzLl91bm1hcmtBY3RpdmVFbGVtZW50KHRoaXMuX2N1cnJlbnQpO1xuXHRcdHRoaXMuX21hcmtBY3RpdmVFbGVtZW50KGJlZm9yZSk7XG5cdFx0dGhpcy5fY3VycmVudCA9IGJlZm9yZTtcblx0fVxuXG5cdF91bm1hcmtBY3RpdmVFbGVtZW50KGVsZW1lbnQ6IEhUTUxFbGVtZW50IHwgdW5kZWZpbmVkKSB7XG5cdFx0aWYgKCFlbGVtZW50KSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGVsZW1lbnQuY2xhc3NOYW1lID0gZWxlbWVudC5jbGFzc05hbWUucmVwbGFjZSgvXFxiY29kZS1hY3RpdmUtbGluZVxcYi9nLCAnJyk7XG5cdH1cblxuXHRfbWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudDogSFRNTEVsZW1lbnQgfCB1bmRlZmluZWQpIHtcblx0XHRpZiAoIWVsZW1lbnQpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0ZWxlbWVudC5jbGFzc05hbWUgKz0gJyBjb2RlLWFjdGl2ZS1saW5lJztcblx0fVxufSIsIi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG5leHBvcnQgZnVuY3Rpb24gb25jZURvY3VtZW50TG9hZGVkKGY6ICgpID0+IHZvaWQpIHtcblx0aWYgKGRvY3VtZW50LnJlYWR5U3RhdGUgPT09ICdsb2FkaW5nJyB8fCBkb2N1bWVudC5yZWFkeVN0YXRlIGFzIHN0cmluZyA9PT0gJ3VuaW5pdGlhbGl6ZWQnKSB7XG5cdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignRE9NQ29udGVudExvYWRlZCcsIGYpO1xuXHR9IGVsc2Uge1xuXHRcdGYoKTtcblx0fVxufSIsIi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG5pbXBvcnQgeyBBY3RpdmVMaW5lTWFya2VyIH0gZnJvbSAnLi9hY3RpdmVMaW5lTWFya2VyJztcbmltcG9ydCB7IG9uY2VEb2N1bWVudExvYWRlZCB9IGZyb20gJy4vZXZlbnRzJztcbmltcG9ydCB7IGNyZWF0ZVBvc3RlckZvclZzQ29kZSB9IGZyb20gJy4vbWVzc2FnaW5nJztcbmltcG9ydCB7IGdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0LCBzY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUsIGdldExpbmVFbGVtZW50Rm9yRnJhZ21lbnQgfSBmcm9tICcuL3Njcm9sbC1zeW5jJztcbmltcG9ydCB7IGdldFNldHRpbmdzLCBnZXREYXRhIH0gZnJvbSAnLi9zZXR0aW5ncyc7XG5pbXBvcnQgdGhyb3R0bGUgPSByZXF1aXJlKCdsb2Rhc2gudGhyb3R0bGUnKTtcblxuZGVjbGFyZSB2YXIgYWNxdWlyZVZzQ29kZUFwaTogYW55O1xuXG5sZXQgc2Nyb2xsRGlzYWJsZWQgPSB0cnVlO1xuY29uc3QgbWFya2VyID0gbmV3IEFjdGl2ZUxpbmVNYXJrZXIoKTtcbmNvbnN0IHNldHRpbmdzID0gZ2V0U2V0dGluZ3MoKTtcblxuY29uc3QgdnNjb2RlID0gYWNxdWlyZVZzQ29kZUFwaSgpO1xuXG4vLyBTZXQgVlMgQ29kZSBzdGF0ZVxubGV0IHN0YXRlID0gZ2V0RGF0YTx7IGxpbmU6IG51bWJlciwgIGZyYWdtZW50OiBzdHJpbmcgfT4oJ2RhdGEtc3RhdGUnKTtcbnZzY29kZS5zZXRTdGF0ZShzdGF0ZSk7XG5cbmNvbnN0IG1lc3NhZ2luZyA9IGNyZWF0ZVBvc3RlckZvclZzQ29kZSh2c2NvZGUpO1xuXG53aW5kb3cuY3NwQWxlcnRlci5zZXRQb3N0ZXIobWVzc2FnaW5nKTtcbndpbmRvdy5zdHlsZUxvYWRpbmdNb25pdG9yLnNldFBvc3RlcihtZXNzYWdpbmcpO1xuXG53aW5kb3cub25sb2FkID0gKCkgPT4ge1xuXHR1cGRhdGVJbWFnZVNpemVzKCk7XG59O1xuXG5vbmNlRG9jdW1lbnRMb2FkZWQoKCkgPT4ge1xuXHRpZiAoc2V0dGluZ3Muc2Nyb2xsUHJldmlld1dpdGhFZGl0b3IpIHtcblx0XHRzZXRUaW1lb3V0KCgpID0+IHtcblx0XHRcdC8vIFRyeSB0byBzY3JvbGwgdG8gZnJhZ21lbnQgaWYgYXZhaWxhYmxlXG5cdFx0XHRpZiAoc3RhdGUuZnJhZ21lbnQpIHtcblx0XHRcdFx0Y29uc3QgZWxlbWVudCA9IGdldExpbmVFbGVtZW50Rm9yRnJhZ21lbnQoc3RhdGUuZnJhZ21lbnQpO1xuXHRcdFx0XHRpZiAoZWxlbWVudCkge1xuXHRcdFx0XHRcdHNjcm9sbERpc2FibGVkID0gdHJ1ZTtcblx0XHRcdFx0XHRzY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUoZWxlbWVudC5saW5lKTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y29uc3QgaW5pdGlhbExpbmUgPSArc2V0dGluZ3MubGluZTtcblx0XHRcdFx0aWYgKCFpc05hTihpbml0aWFsTGluZSkpIHtcblx0XHRcdFx0XHRzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG5cdFx0XHRcdFx0c2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGluaXRpYWxMaW5lKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0sIDApO1xuXHR9XG59KTtcblxuY29uc3Qgb25VcGRhdGVWaWV3ID0gKCgpID0+IHtcblx0Y29uc3QgZG9TY3JvbGwgPSB0aHJvdHRsZSgobGluZTogbnVtYmVyKSA9PiB7XG5cdFx0c2Nyb2xsRGlzYWJsZWQgPSB0cnVlO1xuXHRcdHNjcm9sbFRvUmV2ZWFsU291cmNlTGluZShsaW5lKTtcblx0fSwgNTApO1xuXG5cdHJldHVybiAobGluZTogbnVtYmVyLCBzZXR0aW5nczogYW55KSA9PiB7XG5cdFx0aWYgKCFpc05hTihsaW5lKSkge1xuXHRcdFx0c2V0dGluZ3MubGluZSA9IGxpbmU7XG5cdFx0XHRkb1Njcm9sbChsaW5lKTtcblx0XHR9XG5cdH07XG59KSgpO1xuXG5sZXQgdXBkYXRlSW1hZ2VTaXplcyA9IHRocm90dGxlKCgpID0+IHtcblx0Y29uc3QgaW1hZ2VJbmZvOiB7IGlkOiBzdHJpbmcsIGhlaWdodDogbnVtYmVyLCB3aWR0aDogbnVtYmVyIH1bXSA9IFtdO1xuXHRsZXQgaW1hZ2VzID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2ltZycpO1xuXHRpZiAoaW1hZ2VzKSB7XG5cdFx0bGV0IGk7XG5cdFx0Zm9yIChpID0gMDsgaSA8IGltYWdlcy5sZW5ndGg7IGkrKykge1xuXHRcdFx0Y29uc3QgaW1nID0gaW1hZ2VzW2ldO1xuXG5cdFx0XHRpZiAoaW1nLmNsYXNzTGlzdC5jb250YWlucygnbG9hZGluZycpKSB7XG5cdFx0XHRcdGltZy5jbGFzc0xpc3QucmVtb3ZlKCdsb2FkaW5nJyk7XG5cdFx0XHR9XG5cblx0XHRcdGltYWdlSW5mby5wdXNoKHtcblx0XHRcdFx0aWQ6IGltZy5pZCxcblx0XHRcdFx0aGVpZ2h0OiBpbWcuaGVpZ2h0LFxuXHRcdFx0XHR3aWR0aDogaW1nLndpZHRoXG5cdFx0XHR9KTtcblx0XHR9XG5cblx0XHRtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ2NhY2hlSW1hZ2VTaXplcycsIGltYWdlSW5mbyk7XG5cdH1cbn0sIDUwKTtcblxud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsICgpID0+IHtcblx0c2Nyb2xsRGlzYWJsZWQgPSB0cnVlO1xuXHR1cGRhdGVJbWFnZVNpemVzKCk7XG59LCB0cnVlKTtcblxud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCBldmVudCA9PiB7XG5cdGlmIChldmVudC5kYXRhLnNvdXJjZSAhPT0gc2V0dGluZ3Muc291cmNlKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0c3dpdGNoIChldmVudC5kYXRhLnR5cGUpIHtcblx0XHRjYXNlICdvbkRpZENoYW5nZVRleHRFZGl0b3JTZWxlY3Rpb24nOlxuXHRcdFx0bWFya2VyLm9uRGlkQ2hhbmdlVGV4dEVkaXRvclNlbGVjdGlvbihldmVudC5kYXRhLmxpbmUpO1xuXHRcdFx0YnJlYWs7XG5cblx0XHRjYXNlICd1cGRhdGVWaWV3Jzpcblx0XHRcdG9uVXBkYXRlVmlldyhldmVudC5kYXRhLmxpbmUsIHNldHRpbmdzKTtcblx0XHRcdGJyZWFrO1xuXHR9XG59LCBmYWxzZSk7XG5cbmRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2RibGNsaWNrJywgZXZlbnQgPT4ge1xuXHRpZiAoIXNldHRpbmdzLmRvdWJsZUNsaWNrVG9Td2l0Y2hUb0VkaXRvcikge1xuXHRcdHJldHVybjtcblx0fVxuXG5cdC8vIElnbm9yZSBjbGlja3Mgb24gbGlua3Ncblx0Zm9yIChsZXQgbm9kZSA9IGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudDsgbm9kZTsgbm9kZSA9IG5vZGUucGFyZW50Tm9kZSBhcyBIVE1MRWxlbWVudCkge1xuXHRcdGlmIChub2RlLnRhZ05hbWUgPT09ICdBJykge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0fVxuXG5cdGNvbnN0IG9mZnNldCA9IGV2ZW50LnBhZ2VZO1xuXHRjb25zdCBsaW5lID0gZ2V0RWRpdG9yTGluZU51bWJlckZvclBhZ2VPZmZzZXQob2Zmc2V0KTtcblx0aWYgKHR5cGVvZiBsaW5lID09PSAnbnVtYmVyJyAmJiAhaXNOYU4obGluZSkpIHtcblx0XHRtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ2RpZENsaWNrJywgeyBsaW5lOiBNYXRoLmZsb29yKGxpbmUpIH0pO1xuXHR9XG59KTtcblxuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBldmVudCA9PiB7XG5cdGlmICghZXZlbnQpIHtcblx0XHRyZXR1cm47XG5cdH1cblxuXHRsZXQgbm9kZTogYW55ID0gZXZlbnQudGFyZ2V0O1xuXHR3aGlsZSAobm9kZSkge1xuXHRcdGlmIChub2RlLnRhZ05hbWUgJiYgbm9kZS50YWdOYW1lID09PSAnQScgJiYgbm9kZS5ocmVmKSB7XG5cdFx0XHRpZiAobm9kZS5nZXRBdHRyaWJ1dGUoJ2hyZWYnKS5zdGFydHNXaXRoKCcjJykpIHtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0XHRpZiAobm9kZS5ocmVmLnN0YXJ0c1dpdGgoJ2ZpbGU6Ly8nKSB8fCBub2RlLmhyZWYuc3RhcnRzV2l0aCgndnNjb2RlLXJlc291cmNlOicpIHx8IG5vZGUuaHJlZi5zdGFydHNXaXRoKHNldHRpbmdzLndlYnZpZXdSZXNvdXJjZVJvb3QpKSB7XG5cdFx0XHRcdGNvbnN0IFtwYXRoLCBmcmFnbWVudF0gPSBub2RlLmhyZWYucmVwbGFjZSgvXihmaWxlOlxcL1xcL3x2c2NvZGUtcmVzb3VyY2U6KS9pLCAnJykucmVwbGFjZShuZXcgUmVnRXhwKGBeJHtlc2NhcGVSZWdFeHAoc2V0dGluZ3Mud2Vidmlld1Jlc291cmNlUm9vdCl9YCkpLnNwbGl0KCcjJyk7XG5cdFx0XHRcdG1lc3NhZ2luZy5wb3N0TWVzc2FnZSgnY2xpY2tMaW5rJywgeyBwYXRoLCBmcmFnbWVudCB9KTtcblx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0ZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdFx0YnJlYWs7XG5cdFx0fVxuXHRcdG5vZGUgPSBub2RlLnBhcmVudE5vZGU7XG5cdH1cbn0sIHRydWUpO1xuXG5pZiAoc2V0dGluZ3Muc2Nyb2xsRWRpdG9yV2l0aFByZXZpZXcpIHtcblx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIHRocm90dGxlKCgpID0+IHtcblx0XHRpZiAoc2Nyb2xsRGlzYWJsZWQpIHtcblx0XHRcdHNjcm9sbERpc2FibGVkID0gZmFsc2U7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGNvbnN0IGxpbmUgPSBnZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldCh3aW5kb3cuc2Nyb2xsWSk7XG5cdFx0XHRpZiAodHlwZW9mIGxpbmUgPT09ICdudW1iZXInICYmICFpc05hTihsaW5lKSkge1xuXHRcdFx0XHRtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ3JldmVhbExpbmUnLCB7IGxpbmUgfSk7XG5cdFx0XHRcdHN0YXRlLmxpbmUgPSBsaW5lO1xuXHRcdFx0XHR2c2NvZGUuc2V0U3RhdGUoc3RhdGUpO1xuXHRcdFx0fVxuXHRcdH1cblx0fSwgNTApKTtcbn1cblxuZnVuY3Rpb24gZXNjYXBlUmVnRXhwKHRleHQ6IHN0cmluZykge1xuXHRyZXR1cm4gdGV4dC5yZXBsYWNlKC9bLVtcXF17fSgpKis/LixcXFxcXiR8I1xcc10vZywgJ1xcXFwkJicpO1xufVxuIiwiLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbmltcG9ydCB7IGdldFNldHRpbmdzIH0gZnJvbSAnLi9zZXR0aW5ncyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWVzc2FnZVBvc3RlciB7XG5cdC8qKlxuXHQgKiBQb3N0IGEgbWVzc2FnZSB0byB0aGUgbWFya2Rvd24gZXh0ZW5zaW9uXG5cdCAqL1xuXHRwb3N0TWVzc2FnZSh0eXBlOiBzdHJpbmcsIGJvZHk6IG9iamVjdCk6IHZvaWQ7XG59XG5cbmV4cG9ydCBjb25zdCBjcmVhdGVQb3N0ZXJGb3JWc0NvZGUgPSAodnNjb2RlOiBhbnkpID0+IHtcblx0cmV0dXJuIG5ldyBjbGFzcyBpbXBsZW1lbnRzIE1lc3NhZ2VQb3N0ZXIge1xuXHRcdHBvc3RNZXNzYWdlKHR5cGU6IHN0cmluZywgYm9keTogb2JqZWN0KTogdm9pZCB7XG5cdFx0XHR2c2NvZGUucG9zdE1lc3NhZ2Uoe1xuXHRcdFx0XHR0eXBlLFxuXHRcdFx0XHRzb3VyY2U6IGdldFNldHRpbmdzKCkuc291cmNlLFxuXHRcdFx0XHRib2R5XG5cdFx0XHR9KTtcblx0XHR9XG5cdH07XG59O1xuXG4iLCIvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuaW1wb3J0IHsgZ2V0U2V0dGluZ3MgfSBmcm9tICcuL3NldHRpbmdzJztcblxuXG5mdW5jdGlvbiBjbGFtcChtaW46IG51bWJlciwgbWF4OiBudW1iZXIsIHZhbHVlOiBudW1iZXIpIHtcblx0cmV0dXJuIE1hdGgubWluKG1heCwgTWF0aC5tYXgobWluLCB2YWx1ZSkpO1xufVxuXG5mdW5jdGlvbiBjbGFtcExpbmUobGluZTogbnVtYmVyKSB7XG5cdHJldHVybiBjbGFtcCgwLCBnZXRTZXR0aW5ncygpLmxpbmVDb3VudCAtIDEsIGxpbmUpO1xufVxuXG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29kZUxpbmVFbGVtZW50IHtcblx0ZWxlbWVudDogSFRNTEVsZW1lbnQ7XG5cdGxpbmU6IG51bWJlcjtcbn1cblxuY29uc3QgZ2V0Q29kZUxpbmVFbGVtZW50cyA9ICgoKSA9PiB7XG5cdGxldCBlbGVtZW50czogQ29kZUxpbmVFbGVtZW50W107XG5cdHJldHVybiAoKSA9PiB7XG5cdFx0aWYgKCFlbGVtZW50cykge1xuXHRcdFx0ZWxlbWVudHMgPSBbeyBlbGVtZW50OiBkb2N1bWVudC5ib2R5LCBsaW5lOiAwIH1dO1xuXHRcdFx0Zm9yIChjb25zdCBlbGVtZW50IG9mIGRvY3VtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoJ2NvZGUtbGluZScpKSB7XG5cdFx0XHRcdGNvbnN0IGxpbmUgPSArZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtbGluZScpITtcblx0XHRcdFx0aWYgKCFpc05hTihsaW5lKSkge1xuXHRcdFx0XHRcdGVsZW1lbnRzLnB1c2goeyBlbGVtZW50OiBlbGVtZW50IGFzIEhUTUxFbGVtZW50LCBsaW5lIH0pO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiBlbGVtZW50cztcblx0fTtcbn0pKCk7XG5cbi8qKlxuICogRmluZCB0aGUgaHRtbCBlbGVtZW50cyB0aGF0IG1hcCB0byBhIHNwZWNpZmljIHRhcmdldCBsaW5lIGluIHRoZSBlZGl0b3IuXG4gKlxuICogSWYgYW4gZXhhY3QgbWF0Y2gsIHJldHVybnMgYSBzaW5nbGUgZWxlbWVudC4gSWYgdGhlIGxpbmUgaXMgYmV0d2VlbiBlbGVtZW50cyxcbiAqIHJldHVybnMgdGhlIGVsZW1lbnQgcHJpb3IgdG8gYW5kIHRoZSBlbGVtZW50IGFmdGVyIHRoZSBnaXZlbiBsaW5lLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0RWxlbWVudHNGb3JTb3VyY2VMaW5lKHRhcmdldExpbmU6IG51bWJlcik6IHsgcHJldmlvdXM6IENvZGVMaW5lRWxlbWVudDsgbmV4dD86IENvZGVMaW5lRWxlbWVudDsgfSB7XG5cdGNvbnN0IGxpbmVOdW1iZXIgPSBNYXRoLmZsb29yKHRhcmdldExpbmUpO1xuXHRjb25zdCBsaW5lcyA9IGdldENvZGVMaW5lRWxlbWVudHMoKTtcblx0bGV0IHByZXZpb3VzID0gbGluZXNbMF0gfHwgbnVsbDtcblx0Zm9yIChjb25zdCBlbnRyeSBvZiBsaW5lcykge1xuXHRcdGlmIChlbnRyeS5saW5lID09PSBsaW5lTnVtYmVyKSB7XG5cdFx0XHRyZXR1cm4geyBwcmV2aW91czogZW50cnksIG5leHQ6IHVuZGVmaW5lZCB9O1xuXHRcdH0gZWxzZSBpZiAoZW50cnkubGluZSA+IGxpbmVOdW1iZXIpIHtcblx0XHRcdHJldHVybiB7IHByZXZpb3VzLCBuZXh0OiBlbnRyeSB9O1xuXHRcdH1cblx0XHRwcmV2aW91cyA9IGVudHJ5O1xuXHR9XG5cdHJldHVybiB7IHByZXZpb3VzIH07XG59XG5cbi8qKlxuICogRmluZCB0aGUgaHRtbCBlbGVtZW50cyB0aGF0IGFyZSBhdCBhIHNwZWNpZmljIHBpeGVsIG9mZnNldCBvbiB0aGUgcGFnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExpbmVFbGVtZW50c0F0UGFnZU9mZnNldChvZmZzZXQ6IG51bWJlcik6IHsgcHJldmlvdXM6IENvZGVMaW5lRWxlbWVudDsgbmV4dD86IENvZGVMaW5lRWxlbWVudDsgfSB7XG5cdGNvbnN0IGxpbmVzID0gZ2V0Q29kZUxpbmVFbGVtZW50cygpO1xuXHRjb25zdCBwb3NpdGlvbiA9IG9mZnNldCAtIHdpbmRvdy5zY3JvbGxZO1xuXHRsZXQgbG8gPSAtMTtcblx0bGV0IGhpID0gbGluZXMubGVuZ3RoIC0gMTtcblx0d2hpbGUgKGxvICsgMSA8IGhpKSB7XG5cdFx0Y29uc3QgbWlkID0gTWF0aC5mbG9vcigobG8gKyBoaSkgLyAyKTtcblx0XHRjb25zdCBib3VuZHMgPSBsaW5lc1ttaWRdLmVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cdFx0aWYgKGJvdW5kcy50b3AgKyBib3VuZHMuaGVpZ2h0ID49IHBvc2l0aW9uKSB7XG5cdFx0XHRoaSA9IG1pZDtcblx0XHR9XG5cdFx0ZWxzZSB7XG5cdFx0XHRsbyA9IG1pZDtcblx0XHR9XG5cdH1cblx0Y29uc3QgaGlFbGVtZW50ID0gbGluZXNbaGldO1xuXHRjb25zdCBoaUJvdW5kcyA9IGhpRWxlbWVudC5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXHRpZiAoaGkgPj0gMSAmJiBoaUJvdW5kcy50b3AgPiBwb3NpdGlvbikge1xuXHRcdGNvbnN0IGxvRWxlbWVudCA9IGxpbmVzW2xvXTtcblx0XHRyZXR1cm4geyBwcmV2aW91czogbG9FbGVtZW50LCBuZXh0OiBoaUVsZW1lbnQgfTtcblx0fVxuXHRyZXR1cm4geyBwcmV2aW91czogaGlFbGVtZW50IH07XG59XG5cbi8qKlxuICogQXR0ZW1wdCB0byByZXZlYWwgdGhlIGVsZW1lbnQgZm9yIGEgc291cmNlIGxpbmUgaW4gdGhlIGVkaXRvci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNjcm9sbFRvUmV2ZWFsU291cmNlTGluZShsaW5lOiBudW1iZXIpIHtcblx0aWYgKCFnZXRTZXR0aW5ncygpLnNjcm9sbFByZXZpZXdXaXRoRWRpdG9yKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0aWYgKGxpbmUgPD0gMCkge1xuXHRcdHdpbmRvdy5zY3JvbGwod2luZG93LnNjcm9sbFgsIDApO1xuXHRcdHJldHVybjtcblx0fVxuXG5cdGNvbnN0IHsgcHJldmlvdXMsIG5leHQgfSA9IGdldEVsZW1lbnRzRm9yU291cmNlTGluZShsaW5lKTtcblx0aWYgKCFwcmV2aW91cykge1xuXHRcdHJldHVybjtcblx0fVxuXHRsZXQgc2Nyb2xsVG8gPSAwO1xuXHRjb25zdCByZWN0ID0gcHJldmlvdXMuZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcblx0Y29uc3QgcHJldmlvdXNUb3AgPSByZWN0LnRvcDtcblx0aWYgKG5leHQgJiYgbmV4dC5saW5lICE9PSBwcmV2aW91cy5saW5lKSB7XG5cdFx0Ly8gQmV0d2VlbiB0d28gZWxlbWVudHMuIEdvIHRvIHBlcmNlbnRhZ2Ugb2Zmc2V0IGJldHdlZW4gdGhlbS5cblx0XHRjb25zdCBiZXR3ZWVuUHJvZ3Jlc3MgPSAobGluZSAtIHByZXZpb3VzLmxpbmUpIC8gKG5leHQubGluZSAtIHByZXZpb3VzLmxpbmUpO1xuXHRcdGNvbnN0IGVsZW1lbnRPZmZzZXQgPSBuZXh0LmVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkudG9wIC0gcHJldmlvdXNUb3A7XG5cdFx0c2Nyb2xsVG8gPSBwcmV2aW91c1RvcCArIGJldHdlZW5Qcm9ncmVzcyAqIGVsZW1lbnRPZmZzZXQ7XG5cdH0gZWxzZSB7XG5cdFx0Y29uc3QgcHJvZ3Jlc3NJbkVsZW1lbnQgPSBsaW5lIC0gTWF0aC5mbG9vcihsaW5lKTtcblx0XHRzY3JvbGxUbyA9IHByZXZpb3VzVG9wICsgKHJlY3QuaGVpZ2h0ICogcHJvZ3Jlc3NJbkVsZW1lbnQpO1xuXHR9XG5cdHdpbmRvdy5zY3JvbGwod2luZG93LnNjcm9sbFgsIE1hdGgubWF4KDEsIHdpbmRvdy5zY3JvbGxZICsgc2Nyb2xsVG8pKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0KG9mZnNldDogbnVtYmVyKSB7XG5cdGNvbnN0IHsgcHJldmlvdXMsIG5leHQgfSA9IGdldExpbmVFbGVtZW50c0F0UGFnZU9mZnNldChvZmZzZXQpO1xuXHRpZiAocHJldmlvdXMpIHtcblx0XHRjb25zdCBwcmV2aW91c0JvdW5kcyA9IHByZXZpb3VzLmVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cdFx0Y29uc3Qgb2Zmc2V0RnJvbVByZXZpb3VzID0gKG9mZnNldCAtIHdpbmRvdy5zY3JvbGxZIC0gcHJldmlvdXNCb3VuZHMudG9wKTtcblx0XHRpZiAobmV4dCkge1xuXHRcdFx0Y29uc3QgcHJvZ3Jlc3NCZXR3ZWVuRWxlbWVudHMgPSBvZmZzZXRGcm9tUHJldmlvdXMgLyAobmV4dC5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCAtIHByZXZpb3VzQm91bmRzLnRvcCk7XG5cdFx0XHRjb25zdCBsaW5lID0gcHJldmlvdXMubGluZSArIHByb2dyZXNzQmV0d2VlbkVsZW1lbnRzICogKG5leHQubGluZSAtIHByZXZpb3VzLmxpbmUpO1xuXHRcdFx0cmV0dXJuIGNsYW1wTGluZShsaW5lKTtcblx0XHR9XG5cdFx0ZWxzZSB7XG5cdFx0XHRjb25zdCBwcm9ncmVzc1dpdGhpbkVsZW1lbnQgPSBvZmZzZXRGcm9tUHJldmlvdXMgLyAocHJldmlvdXNCb3VuZHMuaGVpZ2h0KTtcblx0XHRcdGNvbnN0IGxpbmUgPSBwcmV2aW91cy5saW5lICsgcHJvZ3Jlc3NXaXRoaW5FbGVtZW50O1xuXHRcdFx0cmV0dXJuIGNsYW1wTGluZShsaW5lKTtcblx0XHR9XG5cdH1cblx0cmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogVHJ5IHRvIGZpbmQgdGhlIGh0bWwgZWxlbWVudCBieSB1c2luZyBhIGZyYWdtZW50IGlkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRMaW5lRWxlbWVudEZvckZyYWdtZW50KGZyYWdtZW50OiBzdHJpbmcpOiBDb2RlTGluZUVsZW1lbnQgfCB1bmRlZmluZWQge1xuXHRyZXR1cm4gZ2V0Q29kZUxpbmVFbGVtZW50cygpLmZpbmQoKGVsZW1lbnQpID0+IHtcblx0XHRyZXR1cm4gZWxlbWVudC5lbGVtZW50LmlkID09PSBmcmFnbWVudDtcblx0fSk7XG59XG4iLCIvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuZXhwb3J0IGludGVyZmFjZSBQcmV2aWV3U2V0dGluZ3Mge1xuXHRyZWFkb25seSBzb3VyY2U6IHN0cmluZztcblx0cmVhZG9ubHkgbGluZTogbnVtYmVyO1xuXHRyZWFkb25seSBsaW5lQ291bnQ6IG51bWJlcjtcblx0cmVhZG9ubHkgc2Nyb2xsUHJldmlld1dpdGhFZGl0b3I/OiBib29sZWFuO1xuXHRyZWFkb25seSBzY3JvbGxFZGl0b3JXaXRoUHJldmlldzogYm9vbGVhbjtcblx0cmVhZG9ubHkgZGlzYWJsZVNlY3VyaXR5V2FybmluZ3M6IGJvb2xlYW47XG5cdHJlYWRvbmx5IGRvdWJsZUNsaWNrVG9Td2l0Y2hUb0VkaXRvcjogYm9vbGVhbjtcblx0cmVhZG9ubHkgd2Vidmlld1Jlc291cmNlUm9vdDogc3RyaW5nO1xufVxuXG5sZXQgY2FjaGVkU2V0dGluZ3M6IFByZXZpZXdTZXR0aW5ncyB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcblxuZXhwb3J0IGZ1bmN0aW9uIGdldERhdGE8VCA9IHt9PihrZXk6IHN0cmluZyk6IFQge1xuXHRjb25zdCBlbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3ZzY29kZS1tYXJrZG93bi1wcmV2aWV3LWRhdGEnKTtcblx0aWYgKGVsZW1lbnQpIHtcblx0XHRjb25zdCBkYXRhID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoa2V5KTtcblx0XHRpZiAoZGF0YSkge1xuXHRcdFx0cmV0dXJuIEpTT04ucGFyc2UoZGF0YSk7XG5cdFx0fVxuXHR9XG5cblx0dGhyb3cgbmV3IEVycm9yKGBDb3VsZCBub3QgbG9hZCBkYXRhIGZvciAke2tleX1gKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFNldHRpbmdzKCk6IFByZXZpZXdTZXR0aW5ncyB7XG5cdGlmIChjYWNoZWRTZXR0aW5ncykge1xuXHRcdHJldHVybiBjYWNoZWRTZXR0aW5ncztcblx0fVxuXG5cdGNhY2hlZFNldHRpbmdzID0gZ2V0RGF0YSgnZGF0YS1zZXR0aW5ncycpO1xuXHRpZiAoY2FjaGVkU2V0dGluZ3MpIHtcblx0XHRyZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG5cdH1cblxuXHR0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBsb2FkIHNldHRpbmdzJyk7XG59XG4iXSwic291cmNlUm9vdCI6IiJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2xvZGFzaC50aHJvdHRsZS9pbmRleC5qcyIsIndlYnBhY2s6Ly8vKHdlYnBhY2spL2J1aWxkaW4vZ2xvYmFsLmpzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2FjdGl2ZUxpbmVNYXJrZXIudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvZXZlbnRzLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2luZGV4LnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL21lc3NhZ2luZy50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9zY3JvbGwtc3luYy50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9zZXR0aW5ncy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQSx5REFBaUQsY0FBYztBQUMvRDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBMkIsMEJBQTBCLEVBQUU7QUFDdkQseUNBQWlDLGVBQWU7QUFDaEQ7QUFDQTtBQUNBOztBQUVBO0FBQ0EsOERBQXNELCtEQUErRDs7QUFFckg7QUFDQTs7O0FBR0E7QUFDQTs7Ozs7Ozs7Ozs7O0FDbkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFNBQVM7QUFDcEIsV0FBVyxPQUFPO0FBQ2xCLFdBQVcsT0FBTyxZQUFZO0FBQzlCLFdBQVcsUUFBUTtBQUNuQjtBQUNBLFdBQVcsT0FBTztBQUNsQjtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLDhDQUE4QyxrQkFBa0I7QUFDaEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFNBQVM7QUFDcEIsV0FBVyxPQUFPO0FBQ2xCLFdBQVcsT0FBTyxZQUFZO0FBQzlCLFdBQVcsUUFBUTtBQUNuQjtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtREFBbUQsb0JBQW9CO0FBQ3ZFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLEVBQUU7QUFDYixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsRUFBRTtBQUNiLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLEVBQUU7QUFDYixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxFQUFFO0FBQ2IsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOzs7Ozs7Ozs7Ozs7O0FDdGJBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsNENBQTRDOztBQUU1Qzs7Ozs7Ozs7Ozs7OztBQ25CQTtBQUNBLDhDQUE4QyxjQUFjO0FBQzVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZSxXQUFXO0FBQzFCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQzlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDLGNBQWM7QUFDNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7O0FDZEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhDQUE4QyxjQUFjO0FBQzVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLG1CQUFtQjtBQUN0QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUMsTUFBTTtBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQyx5QkFBeUI7QUFDcEU7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdIQUF3SCwyQ0FBMkM7QUFDbkssb0RBQW9ELGlCQUFpQjtBQUNyRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxREFBcUQsT0FBTztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsZ0NBQWdDO0FBQ2hDOzs7Ozs7Ozs7Ozs7O0FDckpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDLGNBQWM7QUFDNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlCQUF5QixrQ0FBa0M7QUFDM0Q7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLHlCQUF5QjtBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQjtBQUNwQjtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLGlCQUFpQjtBQUM1QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOzs7Ozs7Ozs7Ozs7O0FDdklBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQ0FBK0MsSUFBSTtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJpbmRleC5qcyIsInNvdXJjZXNDb250ZW50IjpbIiBcdC8vIFRoZSBtb2R1bGUgY2FjaGVcbiBcdHZhciBpbnN0YWxsZWRNb2R1bGVzID0ge307XG5cbiBcdC8vIFRoZSByZXF1aXJlIGZ1bmN0aW9uXG4gXHRmdW5jdGlvbiBfX3dlYnBhY2tfcmVxdWlyZV9fKG1vZHVsZUlkKSB7XG5cbiBcdFx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG4gXHRcdGlmKGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdKSB7XG4gXHRcdFx0cmV0dXJuIGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdLmV4cG9ydHM7XG4gXHRcdH1cbiBcdFx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcbiBcdFx0dmFyIG1vZHVsZSA9IGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdID0ge1xuIFx0XHRcdGk6IG1vZHVsZUlkLFxuIFx0XHRcdGw6IGZhbHNlLFxuIFx0XHRcdGV4cG9ydHM6IHt9XG4gXHRcdH07XG5cbiBcdFx0Ly8gRXhlY3V0ZSB0aGUgbW9kdWxlIGZ1bmN0aW9uXG4gXHRcdG1vZHVsZXNbbW9kdWxlSWRdLmNhbGwobW9kdWxlLmV4cG9ydHMsIG1vZHVsZSwgbW9kdWxlLmV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pO1xuXG4gXHRcdC8vIEZsYWcgdGhlIG1vZHVsZSBhcyBsb2FkZWRcbiBcdFx0bW9kdWxlLmwgPSB0cnVlO1xuXG4gXHRcdC8vIFJldHVybiB0aGUgZXhwb3J0cyBvZiB0aGUgbW9kdWxlXG4gXHRcdHJldHVybiBtb2R1bGUuZXhwb3J0cztcbiBcdH1cblxuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZXMgb2JqZWN0IChfX3dlYnBhY2tfbW9kdWxlc19fKVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5tID0gbW9kdWxlcztcblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGUgY2FjaGVcbiBcdF9fd2VicGFja19yZXF1aXJlX18uYyA9IGluc3RhbGxlZE1vZHVsZXM7XG5cbiBcdC8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb24gZm9yIGhhcm1vbnkgZXhwb3J0c1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kID0gZnVuY3Rpb24oZXhwb3J0cywgbmFtZSwgZ2V0dGVyKSB7XG4gXHRcdGlmKCFfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZXhwb3J0cywgbmFtZSkpIHtcbiBcdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgbmFtZSwge1xuIFx0XHRcdFx0Y29uZmlndXJhYmxlOiBmYWxzZSxcbiBcdFx0XHRcdGVudW1lcmFibGU6IHRydWUsXG4gXHRcdFx0XHRnZXQ6IGdldHRlclxuIFx0XHRcdH0pO1xuIFx0XHR9XG4gXHR9O1xuXG4gXHQvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIgPSBmdW5jdGlvbihleHBvcnRzKSB7XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG4gXHR9O1xuXG4gXHQvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5uID0gZnVuY3Rpb24obW9kdWxlKSB7XG4gXHRcdHZhciBnZXR0ZXIgPSBtb2R1bGUgJiYgbW9kdWxlLl9fZXNNb2R1bGUgP1xuIFx0XHRcdGZ1bmN0aW9uIGdldERlZmF1bHQoKSB7IHJldHVybiBtb2R1bGVbJ2RlZmF1bHQnXTsgfSA6XG4gXHRcdFx0ZnVuY3Rpb24gZ2V0TW9kdWxlRXhwb3J0cygpIHsgcmV0dXJuIG1vZHVsZTsgfTtcbiBcdFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgJ2EnLCBnZXR0ZXIpO1xuIFx0XHRyZXR1cm4gZ2V0dGVyO1xuIFx0fTtcblxuIFx0Ly8gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm8gPSBmdW5jdGlvbihvYmplY3QsIHByb3BlcnR5KSB7IHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wZXJ0eSk7IH07XG5cbiBcdC8vIF9fd2VicGFja19wdWJsaWNfcGF0aF9fXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnAgPSBcIlwiO1xuXG5cbiBcdC8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuIFx0cmV0dXJuIF9fd2VicGFja19yZXF1aXJlX18oX193ZWJwYWNrX3JlcXVpcmVfXy5zID0gXCIuL3ByZXZpZXctc3JjL2luZGV4LnRzXCIpO1xuIiwiLyoqXG4gKiBsb2Rhc2ggKEN1c3RvbSBCdWlsZCkgPGh0dHBzOi8vbG9kYXNoLmNvbS8+XG4gKiBCdWlsZDogYGxvZGFzaCBtb2R1bGFyaXplIGV4cG9ydHM9XCJucG1cIiAtbyAuL2BcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzIDxodHRwczovL2pxdWVyeS5vcmcvPlxuICogUmVsZWFzZWQgdW5kZXIgTUlUIGxpY2Vuc2UgPGh0dHBzOi8vbG9kYXNoLmNvbS9saWNlbnNlPlxuICogQmFzZWQgb24gVW5kZXJzY29yZS5qcyAxLjguMyA8aHR0cDovL3VuZGVyc2NvcmVqcy5vcmcvTElDRU5TRT5cbiAqIENvcHlyaWdodCBKZXJlbXkgQXNoa2VuYXMsIERvY3VtZW50Q2xvdWQgYW5kIEludmVzdGlnYXRpdmUgUmVwb3J0ZXJzICYgRWRpdG9yc1xuICovXG5cbi8qKiBVc2VkIGFzIHRoZSBgVHlwZUVycm9yYCBtZXNzYWdlIGZvciBcIkZ1bmN0aW9uc1wiIG1ldGhvZHMuICovXG52YXIgRlVOQ19FUlJPUl9URVhUID0gJ0V4cGVjdGVkIGEgZnVuY3Rpb24nO1xuXG4vKiogVXNlZCBhcyByZWZlcmVuY2VzIGZvciB2YXJpb3VzIGBOdW1iZXJgIGNvbnN0YW50cy4gKi9cbnZhciBOQU4gPSAwIC8gMDtcblxuLyoqIGBPYmplY3QjdG9TdHJpbmdgIHJlc3VsdCByZWZlcmVuY2VzLiAqL1xudmFyIHN5bWJvbFRhZyA9ICdbb2JqZWN0IFN5bWJvbF0nO1xuXG4vKiogVXNlZCB0byBtYXRjaCBsZWFkaW5nIGFuZCB0cmFpbGluZyB3aGl0ZXNwYWNlLiAqL1xudmFyIHJlVHJpbSA9IC9eXFxzK3xcXHMrJC9nO1xuXG4vKiogVXNlZCB0byBkZXRlY3QgYmFkIHNpZ25lZCBoZXhhZGVjaW1hbCBzdHJpbmcgdmFsdWVzLiAqL1xudmFyIHJlSXNCYWRIZXggPSAvXlstK10weFswLTlhLWZdKyQvaTtcblxuLyoqIFVzZWQgdG8gZGV0ZWN0IGJpbmFyeSBzdHJpbmcgdmFsdWVzLiAqL1xudmFyIHJlSXNCaW5hcnkgPSAvXjBiWzAxXSskL2k7XG5cbi8qKiBVc2VkIHRvIGRldGVjdCBvY3RhbCBzdHJpbmcgdmFsdWVzLiAqL1xudmFyIHJlSXNPY3RhbCA9IC9eMG9bMC03XSskL2k7XG5cbi8qKiBCdWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcyB3aXRob3V0IGEgZGVwZW5kZW5jeSBvbiBgcm9vdGAuICovXG52YXIgZnJlZVBhcnNlSW50ID0gcGFyc2VJbnQ7XG5cbi8qKiBEZXRlY3QgZnJlZSB2YXJpYWJsZSBgZ2xvYmFsYCBmcm9tIE5vZGUuanMuICovXG52YXIgZnJlZUdsb2JhbCA9IHR5cGVvZiBnbG9iYWwgPT0gJ29iamVjdCcgJiYgZ2xvYmFsICYmIGdsb2JhbC5PYmplY3QgPT09IE9iamVjdCAmJiBnbG9iYWw7XG5cbi8qKiBEZXRlY3QgZnJlZSB2YXJpYWJsZSBgc2VsZmAuICovXG52YXIgZnJlZVNlbGYgPSB0eXBlb2Ygc2VsZiA9PSAnb2JqZWN0JyAmJiBzZWxmICYmIHNlbGYuT2JqZWN0ID09PSBPYmplY3QgJiYgc2VsZjtcblxuLyoqIFVzZWQgYXMgYSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvYmplY3QuICovXG52YXIgcm9vdCA9IGZyZWVHbG9iYWwgfHwgZnJlZVNlbGYgfHwgRnVuY3Rpb24oJ3JldHVybiB0aGlzJykoKTtcblxuLyoqIFVzZWQgZm9yIGJ1aWx0LWluIG1ldGhvZCByZWZlcmVuY2VzLiAqL1xudmFyIG9iamVjdFByb3RvID0gT2JqZWN0LnByb3RvdHlwZTtcblxuLyoqXG4gKiBVc2VkIHRvIHJlc29sdmUgdGhlXG4gKiBbYHRvU3RyaW5nVGFnYF0oaHR0cDovL2VjbWEtaW50ZXJuYXRpb25hbC5vcmcvZWNtYS0yNjIvNy4wLyNzZWMtb2JqZWN0LnByb3RvdHlwZS50b3N0cmluZylcbiAqIG9mIHZhbHVlcy5cbiAqL1xudmFyIG9iamVjdFRvU3RyaW5nID0gb2JqZWN0UHJvdG8udG9TdHJpbmc7XG5cbi8qIEJ1aWx0LWluIG1ldGhvZCByZWZlcmVuY2VzIGZvciB0aG9zZSB3aXRoIHRoZSBzYW1lIG5hbWUgYXMgb3RoZXIgYGxvZGFzaGAgbWV0aG9kcy4gKi9cbnZhciBuYXRpdmVNYXggPSBNYXRoLm1heCxcbiAgICBuYXRpdmVNaW4gPSBNYXRoLm1pbjtcblxuLyoqXG4gKiBHZXRzIHRoZSB0aW1lc3RhbXAgb2YgdGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdGhhdCBoYXZlIGVsYXBzZWQgc2luY2VcbiAqIHRoZSBVbml4IGVwb2NoICgxIEphbnVhcnkgMTk3MCAwMDowMDowMCBVVEMpLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMi40LjBcbiAqIEBjYXRlZ29yeSBEYXRlXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBSZXR1cm5zIHRoZSB0aW1lc3RhbXAuXG4gKiBAZXhhbXBsZVxuICpcbiAqIF8uZGVmZXIoZnVuY3Rpb24oc3RhbXApIHtcbiAqICAgY29uc29sZS5sb2coXy5ub3coKSAtIHN0YW1wKTtcbiAqIH0sIF8ubm93KCkpO1xuICogLy8gPT4gTG9ncyB0aGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBpdCB0b29rIGZvciB0aGUgZGVmZXJyZWQgaW52b2NhdGlvbi5cbiAqL1xudmFyIG5vdyA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gcm9vdC5EYXRlLm5vdygpO1xufTtcblxuLyoqXG4gKiBDcmVhdGVzIGEgZGVib3VuY2VkIGZ1bmN0aW9uIHRoYXQgZGVsYXlzIGludm9raW5nIGBmdW5jYCB1bnRpbCBhZnRlciBgd2FpdGBcbiAqIG1pbGxpc2Vjb25kcyBoYXZlIGVsYXBzZWQgc2luY2UgdGhlIGxhc3QgdGltZSB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uIHdhc1xuICogaW52b2tlZC4gVGhlIGRlYm91bmNlZCBmdW5jdGlvbiBjb21lcyB3aXRoIGEgYGNhbmNlbGAgbWV0aG9kIHRvIGNhbmNlbFxuICogZGVsYXllZCBgZnVuY2AgaW52b2NhdGlvbnMgYW5kIGEgYGZsdXNoYCBtZXRob2QgdG8gaW1tZWRpYXRlbHkgaW52b2tlIHRoZW0uXG4gKiBQcm92aWRlIGBvcHRpb25zYCB0byBpbmRpY2F0ZSB3aGV0aGVyIGBmdW5jYCBzaG91bGQgYmUgaW52b2tlZCBvbiB0aGVcbiAqIGxlYWRpbmcgYW5kL29yIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIGB3YWl0YCB0aW1lb3V0LiBUaGUgYGZ1bmNgIGlzIGludm9rZWRcbiAqIHdpdGggdGhlIGxhc3QgYXJndW1lbnRzIHByb3ZpZGVkIHRvIHRoZSBkZWJvdW5jZWQgZnVuY3Rpb24uIFN1YnNlcXVlbnRcbiAqIGNhbGxzIHRvIHRoZSBkZWJvdW5jZWQgZnVuY3Rpb24gcmV0dXJuIHRoZSByZXN1bHQgb2YgdGhlIGxhc3QgYGZ1bmNgXG4gKiBpbnZvY2F0aW9uLlxuICpcbiAqICoqTm90ZToqKiBJZiBgbGVhZGluZ2AgYW5kIGB0cmFpbGluZ2Agb3B0aW9ucyBhcmUgYHRydWVgLCBgZnVuY2AgaXNcbiAqIGludm9rZWQgb24gdGhlIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQgb25seSBpZiB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uXG4gKiBpcyBpbnZva2VkIG1vcmUgdGhhbiBvbmNlIGR1cmluZyB0aGUgYHdhaXRgIHRpbWVvdXQuXG4gKlxuICogSWYgYHdhaXRgIGlzIGAwYCBhbmQgYGxlYWRpbmdgIGlzIGBmYWxzZWAsIGBmdW5jYCBpbnZvY2F0aW9uIGlzIGRlZmVycmVkXG4gKiB1bnRpbCB0byB0aGUgbmV4dCB0aWNrLCBzaW1pbGFyIHRvIGBzZXRUaW1lb3V0YCB3aXRoIGEgdGltZW91dCBvZiBgMGAuXG4gKlxuICogU2VlIFtEYXZpZCBDb3JiYWNobydzIGFydGljbGVdKGh0dHBzOi8vY3NzLXRyaWNrcy5jb20vZGVib3VuY2luZy10aHJvdHRsaW5nLWV4cGxhaW5lZC1leGFtcGxlcy8pXG4gKiBmb3IgZGV0YWlscyBvdmVyIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIGBfLmRlYm91bmNlYCBhbmQgYF8udGhyb3R0bGVgLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMC4xLjBcbiAqIEBjYXRlZ29yeSBGdW5jdGlvblxuICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBUaGUgZnVuY3Rpb24gdG8gZGVib3VuY2UuXG4gKiBAcGFyYW0ge251bWJlcn0gW3dhaXQ9MF0gVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gZGVsYXkuXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnM9e31dIFRoZSBvcHRpb25zIG9iamVjdC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMubGVhZGluZz1mYWxzZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSBsZWFkaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQuXG4gKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMubWF4V2FpdF1cbiAqICBUaGUgbWF4aW11bSB0aW1lIGBmdW5jYCBpcyBhbGxvd2VkIHRvIGJlIGRlbGF5ZWQgYmVmb3JlIGl0J3MgaW52b2tlZC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMudHJhaWxpbmc9dHJ1ZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgZGVib3VuY2VkIGZ1bmN0aW9uLlxuICogQGV4YW1wbGVcbiAqXG4gKiAvLyBBdm9pZCBjb3N0bHkgY2FsY3VsYXRpb25zIHdoaWxlIHRoZSB3aW5kb3cgc2l6ZSBpcyBpbiBmbHV4LlxuICogalF1ZXJ5KHdpbmRvdykub24oJ3Jlc2l6ZScsIF8uZGVib3VuY2UoY2FsY3VsYXRlTGF5b3V0LCAxNTApKTtcbiAqXG4gKiAvLyBJbnZva2UgYHNlbmRNYWlsYCB3aGVuIGNsaWNrZWQsIGRlYm91bmNpbmcgc3Vic2VxdWVudCBjYWxscy5cbiAqIGpRdWVyeShlbGVtZW50KS5vbignY2xpY2snLCBfLmRlYm91bmNlKHNlbmRNYWlsLCAzMDAsIHtcbiAqICAgJ2xlYWRpbmcnOiB0cnVlLFxuICogICAndHJhaWxpbmcnOiBmYWxzZVxuICogfSkpO1xuICpcbiAqIC8vIEVuc3VyZSBgYmF0Y2hMb2dgIGlzIGludm9rZWQgb25jZSBhZnRlciAxIHNlY29uZCBvZiBkZWJvdW5jZWQgY2FsbHMuXG4gKiB2YXIgZGVib3VuY2VkID0gXy5kZWJvdW5jZShiYXRjaExvZywgMjUwLCB7ICdtYXhXYWl0JzogMTAwMCB9KTtcbiAqIHZhciBzb3VyY2UgPSBuZXcgRXZlbnRTb3VyY2UoJy9zdHJlYW0nKTtcbiAqIGpRdWVyeShzb3VyY2UpLm9uKCdtZXNzYWdlJywgZGVib3VuY2VkKTtcbiAqXG4gKiAvLyBDYW5jZWwgdGhlIHRyYWlsaW5nIGRlYm91bmNlZCBpbnZvY2F0aW9uLlxuICogalF1ZXJ5KHdpbmRvdykub24oJ3BvcHN0YXRlJywgZGVib3VuY2VkLmNhbmNlbCk7XG4gKi9cbmZ1bmN0aW9uIGRlYm91bmNlKGZ1bmMsIHdhaXQsIG9wdGlvbnMpIHtcbiAgdmFyIGxhc3RBcmdzLFxuICAgICAgbGFzdFRoaXMsXG4gICAgICBtYXhXYWl0LFxuICAgICAgcmVzdWx0LFxuICAgICAgdGltZXJJZCxcbiAgICAgIGxhc3RDYWxsVGltZSxcbiAgICAgIGxhc3RJbnZva2VUaW1lID0gMCxcbiAgICAgIGxlYWRpbmcgPSBmYWxzZSxcbiAgICAgIG1heGluZyA9IGZhbHNlLFxuICAgICAgdHJhaWxpbmcgPSB0cnVlO1xuXG4gIGlmICh0eXBlb2YgZnVuYyAhPSAnZnVuY3Rpb24nKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihGVU5DX0VSUk9SX1RFWFQpO1xuICB9XG4gIHdhaXQgPSB0b051bWJlcih3YWl0KSB8fCAwO1xuICBpZiAoaXNPYmplY3Qob3B0aW9ucykpIHtcbiAgICBsZWFkaW5nID0gISFvcHRpb25zLmxlYWRpbmc7XG4gICAgbWF4aW5nID0gJ21heFdhaXQnIGluIG9wdGlvbnM7XG4gICAgbWF4V2FpdCA9IG1heGluZyA/IG5hdGl2ZU1heCh0b051bWJlcihvcHRpb25zLm1heFdhaXQpIHx8IDAsIHdhaXQpIDogbWF4V2FpdDtcbiAgICB0cmFpbGluZyA9ICd0cmFpbGluZycgaW4gb3B0aW9ucyA/ICEhb3B0aW9ucy50cmFpbGluZyA6IHRyYWlsaW5nO1xuICB9XG5cbiAgZnVuY3Rpb24gaW52b2tlRnVuYyh0aW1lKSB7XG4gICAgdmFyIGFyZ3MgPSBsYXN0QXJncyxcbiAgICAgICAgdGhpc0FyZyA9IGxhc3RUaGlzO1xuXG4gICAgbGFzdEFyZ3MgPSBsYXN0VGhpcyA9IHVuZGVmaW5lZDtcbiAgICBsYXN0SW52b2tlVGltZSA9IHRpbWU7XG4gICAgcmVzdWx0ID0gZnVuYy5hcHBseSh0aGlzQXJnLCBhcmdzKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gbGVhZGluZ0VkZ2UodGltZSkge1xuICAgIC8vIFJlc2V0IGFueSBgbWF4V2FpdGAgdGltZXIuXG4gICAgbGFzdEludm9rZVRpbWUgPSB0aW1lO1xuICAgIC8vIFN0YXJ0IHRoZSB0aW1lciBmb3IgdGhlIHRyYWlsaW5nIGVkZ2UuXG4gICAgdGltZXJJZCA9IHNldFRpbWVvdXQodGltZXJFeHBpcmVkLCB3YWl0KTtcbiAgICAvLyBJbnZva2UgdGhlIGxlYWRpbmcgZWRnZS5cbiAgICByZXR1cm4gbGVhZGluZyA/IGludm9rZUZ1bmModGltZSkgOiByZXN1bHQ7XG4gIH1cblxuICBmdW5jdGlvbiByZW1haW5pbmdXYWl0KHRpbWUpIHtcbiAgICB2YXIgdGltZVNpbmNlTGFzdENhbGwgPSB0aW1lIC0gbGFzdENhbGxUaW1lLFxuICAgICAgICB0aW1lU2luY2VMYXN0SW52b2tlID0gdGltZSAtIGxhc3RJbnZva2VUaW1lLFxuICAgICAgICByZXN1bHQgPSB3YWl0IC0gdGltZVNpbmNlTGFzdENhbGw7XG5cbiAgICByZXR1cm4gbWF4aW5nID8gbmF0aXZlTWluKHJlc3VsdCwgbWF4V2FpdCAtIHRpbWVTaW5jZUxhc3RJbnZva2UpIDogcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gc2hvdWxkSW52b2tlKHRpbWUpIHtcbiAgICB2YXIgdGltZVNpbmNlTGFzdENhbGwgPSB0aW1lIC0gbGFzdENhbGxUaW1lLFxuICAgICAgICB0aW1lU2luY2VMYXN0SW52b2tlID0gdGltZSAtIGxhc3RJbnZva2VUaW1lO1xuXG4gICAgLy8gRWl0aGVyIHRoaXMgaXMgdGhlIGZpcnN0IGNhbGwsIGFjdGl2aXR5IGhhcyBzdG9wcGVkIGFuZCB3ZSdyZSBhdCB0aGVcbiAgICAvLyB0cmFpbGluZyBlZGdlLCB0aGUgc3lzdGVtIHRpbWUgaGFzIGdvbmUgYmFja3dhcmRzIGFuZCB3ZSdyZSB0cmVhdGluZ1xuICAgIC8vIGl0IGFzIHRoZSB0cmFpbGluZyBlZGdlLCBvciB3ZSd2ZSBoaXQgdGhlIGBtYXhXYWl0YCBsaW1pdC5cbiAgICByZXR1cm4gKGxhc3RDYWxsVGltZSA9PT0gdW5kZWZpbmVkIHx8ICh0aW1lU2luY2VMYXN0Q2FsbCA+PSB3YWl0KSB8fFxuICAgICAgKHRpbWVTaW5jZUxhc3RDYWxsIDwgMCkgfHwgKG1heGluZyAmJiB0aW1lU2luY2VMYXN0SW52b2tlID49IG1heFdhaXQpKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHRpbWVyRXhwaXJlZCgpIHtcbiAgICB2YXIgdGltZSA9IG5vdygpO1xuICAgIGlmIChzaG91bGRJbnZva2UodGltZSkpIHtcbiAgICAgIHJldHVybiB0cmFpbGluZ0VkZ2UodGltZSk7XG4gICAgfVxuICAgIC8vIFJlc3RhcnQgdGhlIHRpbWVyLlxuICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgcmVtYWluaW5nV2FpdCh0aW1lKSk7XG4gIH1cblxuICBmdW5jdGlvbiB0cmFpbGluZ0VkZ2UodGltZSkge1xuICAgIHRpbWVySWQgPSB1bmRlZmluZWQ7XG5cbiAgICAvLyBPbmx5IGludm9rZSBpZiB3ZSBoYXZlIGBsYXN0QXJnc2Agd2hpY2ggbWVhbnMgYGZ1bmNgIGhhcyBiZWVuXG4gICAgLy8gZGVib3VuY2VkIGF0IGxlYXN0IG9uY2UuXG4gICAgaWYgKHRyYWlsaW5nICYmIGxhc3RBcmdzKSB7XG4gICAgICByZXR1cm4gaW52b2tlRnVuYyh0aW1lKTtcbiAgICB9XG4gICAgbGFzdEFyZ3MgPSBsYXN0VGhpcyA9IHVuZGVmaW5lZDtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gY2FuY2VsKCkge1xuICAgIGlmICh0aW1lcklkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aW1lcklkKTtcbiAgICB9XG4gICAgbGFzdEludm9rZVRpbWUgPSAwO1xuICAgIGxhc3RBcmdzID0gbGFzdENhbGxUaW1lID0gbGFzdFRoaXMgPSB0aW1lcklkID0gdW5kZWZpbmVkO1xuICB9XG5cbiAgZnVuY3Rpb24gZmx1c2goKSB7XG4gICAgcmV0dXJuIHRpbWVySWQgPT09IHVuZGVmaW5lZCA/IHJlc3VsdCA6IHRyYWlsaW5nRWRnZShub3coKSk7XG4gIH1cblxuICBmdW5jdGlvbiBkZWJvdW5jZWQoKSB7XG4gICAgdmFyIHRpbWUgPSBub3coKSxcbiAgICAgICAgaXNJbnZva2luZyA9IHNob3VsZEludm9rZSh0aW1lKTtcblxuICAgIGxhc3RBcmdzID0gYXJndW1lbnRzO1xuICAgIGxhc3RUaGlzID0gdGhpcztcbiAgICBsYXN0Q2FsbFRpbWUgPSB0aW1lO1xuXG4gICAgaWYgKGlzSW52b2tpbmcpIHtcbiAgICAgIGlmICh0aW1lcklkID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIGxlYWRpbmdFZGdlKGxhc3RDYWxsVGltZSk7XG4gICAgICB9XG4gICAgICBpZiAobWF4aW5nKSB7XG4gICAgICAgIC8vIEhhbmRsZSBpbnZvY2F0aW9ucyBpbiBhIHRpZ2h0IGxvb3AuXG4gICAgICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgd2FpdCk7XG4gICAgICAgIHJldHVybiBpbnZva2VGdW5jKGxhc3RDYWxsVGltZSk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmICh0aW1lcklkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgd2FpdCk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbiAgZGVib3VuY2VkLmNhbmNlbCA9IGNhbmNlbDtcbiAgZGVib3VuY2VkLmZsdXNoID0gZmx1c2g7XG4gIHJldHVybiBkZWJvdW5jZWQ7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIHRocm90dGxlZCBmdW5jdGlvbiB0aGF0IG9ubHkgaW52b2tlcyBgZnVuY2AgYXQgbW9zdCBvbmNlIHBlclxuICogZXZlcnkgYHdhaXRgIG1pbGxpc2Vjb25kcy4gVGhlIHRocm90dGxlZCBmdW5jdGlvbiBjb21lcyB3aXRoIGEgYGNhbmNlbGBcbiAqIG1ldGhvZCB0byBjYW5jZWwgZGVsYXllZCBgZnVuY2AgaW52b2NhdGlvbnMgYW5kIGEgYGZsdXNoYCBtZXRob2QgdG9cbiAqIGltbWVkaWF0ZWx5IGludm9rZSB0aGVtLiBQcm92aWRlIGBvcHRpb25zYCB0byBpbmRpY2F0ZSB3aGV0aGVyIGBmdW5jYFxuICogc2hvdWxkIGJlIGludm9rZWQgb24gdGhlIGxlYWRpbmcgYW5kL29yIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIGB3YWl0YFxuICogdGltZW91dC4gVGhlIGBmdW5jYCBpcyBpbnZva2VkIHdpdGggdGhlIGxhc3QgYXJndW1lbnRzIHByb3ZpZGVkIHRvIHRoZVxuICogdGhyb3R0bGVkIGZ1bmN0aW9uLiBTdWJzZXF1ZW50IGNhbGxzIHRvIHRoZSB0aHJvdHRsZWQgZnVuY3Rpb24gcmV0dXJuIHRoZVxuICogcmVzdWx0IG9mIHRoZSBsYXN0IGBmdW5jYCBpbnZvY2F0aW9uLlxuICpcbiAqICoqTm90ZToqKiBJZiBgbGVhZGluZ2AgYW5kIGB0cmFpbGluZ2Agb3B0aW9ucyBhcmUgYHRydWVgLCBgZnVuY2AgaXNcbiAqIGludm9rZWQgb24gdGhlIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQgb25seSBpZiB0aGUgdGhyb3R0bGVkIGZ1bmN0aW9uXG4gKiBpcyBpbnZva2VkIG1vcmUgdGhhbiBvbmNlIGR1cmluZyB0aGUgYHdhaXRgIHRpbWVvdXQuXG4gKlxuICogSWYgYHdhaXRgIGlzIGAwYCBhbmQgYGxlYWRpbmdgIGlzIGBmYWxzZWAsIGBmdW5jYCBpbnZvY2F0aW9uIGlzIGRlZmVycmVkXG4gKiB1bnRpbCB0byB0aGUgbmV4dCB0aWNrLCBzaW1pbGFyIHRvIGBzZXRUaW1lb3V0YCB3aXRoIGEgdGltZW91dCBvZiBgMGAuXG4gKlxuICogU2VlIFtEYXZpZCBDb3JiYWNobydzIGFydGljbGVdKGh0dHBzOi8vY3NzLXRyaWNrcy5jb20vZGVib3VuY2luZy10aHJvdHRsaW5nLWV4cGxhaW5lZC1leGFtcGxlcy8pXG4gKiBmb3IgZGV0YWlscyBvdmVyIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIGBfLnRocm90dGxlYCBhbmQgYF8uZGVib3VuY2VgLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMC4xLjBcbiAqIEBjYXRlZ29yeSBGdW5jdGlvblxuICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBUaGUgZnVuY3Rpb24gdG8gdGhyb3R0bGUuXG4gKiBAcGFyYW0ge251bWJlcn0gW3dhaXQ9MF0gVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gdGhyb3R0bGUgaW52b2NhdGlvbnMgdG8uXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnM9e31dIFRoZSBvcHRpb25zIG9iamVjdC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMubGVhZGluZz10cnVlXVxuICogIFNwZWNpZnkgaW52b2tpbmcgb24gdGhlIGxlYWRpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMudHJhaWxpbmc9dHJ1ZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgdGhyb3R0bGVkIGZ1bmN0aW9uLlxuICogQGV4YW1wbGVcbiAqXG4gKiAvLyBBdm9pZCBleGNlc3NpdmVseSB1cGRhdGluZyB0aGUgcG9zaXRpb24gd2hpbGUgc2Nyb2xsaW5nLlxuICogalF1ZXJ5KHdpbmRvdykub24oJ3Njcm9sbCcsIF8udGhyb3R0bGUodXBkYXRlUG9zaXRpb24sIDEwMCkpO1xuICpcbiAqIC8vIEludm9rZSBgcmVuZXdUb2tlbmAgd2hlbiB0aGUgY2xpY2sgZXZlbnQgaXMgZmlyZWQsIGJ1dCBub3QgbW9yZSB0aGFuIG9uY2UgZXZlcnkgNSBtaW51dGVzLlxuICogdmFyIHRocm90dGxlZCA9IF8udGhyb3R0bGUocmVuZXdUb2tlbiwgMzAwMDAwLCB7ICd0cmFpbGluZyc6IGZhbHNlIH0pO1xuICogalF1ZXJ5KGVsZW1lbnQpLm9uKCdjbGljaycsIHRocm90dGxlZCk7XG4gKlxuICogLy8gQ2FuY2VsIHRoZSB0cmFpbGluZyB0aHJvdHRsZWQgaW52b2NhdGlvbi5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdwb3BzdGF0ZScsIHRocm90dGxlZC5jYW5jZWwpO1xuICovXG5mdW5jdGlvbiB0aHJvdHRsZShmdW5jLCB3YWl0LCBvcHRpb25zKSB7XG4gIHZhciBsZWFkaW5nID0gdHJ1ZSxcbiAgICAgIHRyYWlsaW5nID0gdHJ1ZTtcblxuICBpZiAodHlwZW9mIGZ1bmMgIT0gJ2Z1bmN0aW9uJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoRlVOQ19FUlJPUl9URVhUKTtcbiAgfVxuICBpZiAoaXNPYmplY3Qob3B0aW9ucykpIHtcbiAgICBsZWFkaW5nID0gJ2xlYWRpbmcnIGluIG9wdGlvbnMgPyAhIW9wdGlvbnMubGVhZGluZyA6IGxlYWRpbmc7XG4gICAgdHJhaWxpbmcgPSAndHJhaWxpbmcnIGluIG9wdGlvbnMgPyAhIW9wdGlvbnMudHJhaWxpbmcgOiB0cmFpbGluZztcbiAgfVxuICByZXR1cm4gZGVib3VuY2UoZnVuYywgd2FpdCwge1xuICAgICdsZWFkaW5nJzogbGVhZGluZyxcbiAgICAnbWF4V2FpdCc6IHdhaXQsXG4gICAgJ3RyYWlsaW5nJzogdHJhaWxpbmdcbiAgfSk7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgdGhlXG4gKiBbbGFuZ3VhZ2UgdHlwZV0oaHR0cDovL3d3dy5lY21hLWludGVybmF0aW9uYWwub3JnL2VjbWEtMjYyLzcuMC8jc2VjLWVjbWFzY3JpcHQtbGFuZ3VhZ2UtdHlwZXMpXG4gKiBvZiBgT2JqZWN0YC4gKGUuZy4gYXJyYXlzLCBmdW5jdGlvbnMsIG9iamVjdHMsIHJlZ2V4ZXMsIGBuZXcgTnVtYmVyKDApYCwgYW5kIGBuZXcgU3RyaW5nKCcnKWApXG4gKlxuICogQHN0YXRpY1xuICogQG1lbWJlck9mIF9cbiAqIEBzaW5jZSAwLjEuMFxuICogQGNhdGVnb3J5IExhbmdcbiAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGB2YWx1ZWAgaXMgYW4gb2JqZWN0LCBlbHNlIGBmYWxzZWAuXG4gKiBAZXhhbXBsZVxuICpcbiAqIF8uaXNPYmplY3Qoe30pO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNPYmplY3QoWzEsIDIsIDNdKTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0KF8ubm9vcCk7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc09iamVjdChudWxsKTtcbiAqIC8vID0+IGZhbHNlXG4gKi9cbmZ1bmN0aW9uIGlzT2JqZWN0KHZhbHVlKSB7XG4gIHZhciB0eXBlID0gdHlwZW9mIHZhbHVlO1xuICByZXR1cm4gISF2YWx1ZSAmJiAodHlwZSA9PSAnb2JqZWN0JyB8fCB0eXBlID09ICdmdW5jdGlvbicpO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIG9iamVjdC1saWtlLiBBIHZhbHVlIGlzIG9iamVjdC1saWtlIGlmIGl0J3Mgbm90IGBudWxsYFxuICogYW5kIGhhcyBhIGB0eXBlb2ZgIHJlc3VsdCBvZiBcIm9iamVjdFwiLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgNC4wLjBcbiAqIEBjYXRlZ29yeSBMYW5nXG4gKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiBgdmFsdWVgIGlzIG9iamVjdC1saWtlLCBlbHNlIGBmYWxzZWAuXG4gKiBAZXhhbXBsZVxuICpcbiAqIF8uaXNPYmplY3RMaWtlKHt9KTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZShbMSwgMiwgM10pO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNPYmplY3RMaWtlKF8ubm9vcCk7XG4gKiAvLyA9PiBmYWxzZVxuICpcbiAqIF8uaXNPYmplY3RMaWtlKG51bGwpO1xuICogLy8gPT4gZmFsc2VcbiAqL1xuZnVuY3Rpb24gaXNPYmplY3RMaWtlKHZhbHVlKSB7XG4gIHJldHVybiAhIXZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PSAnb2JqZWN0Jztcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBjbGFzc2lmaWVkIGFzIGEgYFN5bWJvbGAgcHJpbWl0aXZlIG9yIG9iamVjdC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDQuMC4wXG4gKiBAY2F0ZWdvcnkgTGFuZ1xuICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYHZhbHVlYCBpcyBhIHN5bWJvbCwgZWxzZSBgZmFsc2VgLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmlzU3ltYm9sKFN5bWJvbC5pdGVyYXRvcik7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc1N5bWJvbCgnYWJjJyk7XG4gKiAvLyA9PiBmYWxzZVxuICovXG5mdW5jdGlvbiBpc1N5bWJvbCh2YWx1ZSkge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09ICdzeW1ib2wnIHx8XG4gICAgKGlzT2JqZWN0TGlrZSh2YWx1ZSkgJiYgb2JqZWN0VG9TdHJpbmcuY2FsbCh2YWx1ZSkgPT0gc3ltYm9sVGFnKTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBgdmFsdWVgIHRvIGEgbnVtYmVyLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgNC4wLjBcbiAqIEBjYXRlZ29yeSBMYW5nXG4gKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBwcm9jZXNzLlxuICogQHJldHVybnMge251bWJlcn0gUmV0dXJucyB0aGUgbnVtYmVyLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLnRvTnVtYmVyKDMuMik7XG4gKiAvLyA9PiAzLjJcbiAqXG4gKiBfLnRvTnVtYmVyKE51bWJlci5NSU5fVkFMVUUpO1xuICogLy8gPT4gNWUtMzI0XG4gKlxuICogXy50b051bWJlcihJbmZpbml0eSk7XG4gKiAvLyA9PiBJbmZpbml0eVxuICpcbiAqIF8udG9OdW1iZXIoJzMuMicpO1xuICogLy8gPT4gMy4yXG4gKi9cbmZ1bmN0aW9uIHRvTnVtYmVyKHZhbHVlKSB7XG4gIGlmICh0eXBlb2YgdmFsdWUgPT0gJ251bWJlcicpIHtcbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cbiAgaWYgKGlzU3ltYm9sKHZhbHVlKSkge1xuICAgIHJldHVybiBOQU47XG4gIH1cbiAgaWYgKGlzT2JqZWN0KHZhbHVlKSkge1xuICAgIHZhciBvdGhlciA9IHR5cGVvZiB2YWx1ZS52YWx1ZU9mID09ICdmdW5jdGlvbicgPyB2YWx1ZS52YWx1ZU9mKCkgOiB2YWx1ZTtcbiAgICB2YWx1ZSA9IGlzT2JqZWN0KG90aGVyKSA/IChvdGhlciArICcnKSA6IG90aGVyO1xuICB9XG4gIGlmICh0eXBlb2YgdmFsdWUgIT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gdmFsdWUgPT09IDAgPyB2YWx1ZSA6ICt2YWx1ZTtcbiAgfVxuICB2YWx1ZSA9IHZhbHVlLnJlcGxhY2UocmVUcmltLCAnJyk7XG4gIHZhciBpc0JpbmFyeSA9IHJlSXNCaW5hcnkudGVzdCh2YWx1ZSk7XG4gIHJldHVybiAoaXNCaW5hcnkgfHwgcmVJc09jdGFsLnRlc3QodmFsdWUpKVxuICAgID8gZnJlZVBhcnNlSW50KHZhbHVlLnNsaWNlKDIpLCBpc0JpbmFyeSA/IDIgOiA4KVxuICAgIDogKHJlSXNCYWRIZXgudGVzdCh2YWx1ZSkgPyBOQU4gOiArdmFsdWUpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHRocm90dGxlO1xuIiwidmFyIGc7XHJcblxyXG4vLyBUaGlzIHdvcmtzIGluIG5vbi1zdHJpY3QgbW9kZVxyXG5nID0gKGZ1bmN0aW9uKCkge1xyXG5cdHJldHVybiB0aGlzO1xyXG59KSgpO1xyXG5cclxudHJ5IHtcclxuXHQvLyBUaGlzIHdvcmtzIGlmIGV2YWwgaXMgYWxsb3dlZCAoc2VlIENTUClcclxuXHRnID0gZyB8fCBGdW5jdGlvbihcInJldHVybiB0aGlzXCIpKCkgfHwgKDEsIGV2YWwpKFwidGhpc1wiKTtcclxufSBjYXRjaCAoZSkge1xyXG5cdC8vIFRoaXMgd29ya3MgaWYgdGhlIHdpbmRvdyByZWZlcmVuY2UgaXMgYXZhaWxhYmxlXHJcblx0aWYgKHR5cGVvZiB3aW5kb3cgPT09IFwib2JqZWN0XCIpIGcgPSB3aW5kb3c7XHJcbn1cclxuXHJcbi8vIGcgY2FuIHN0aWxsIGJlIHVuZGVmaW5lZCwgYnV0IG5vdGhpbmcgdG8gZG8gYWJvdXQgaXQuLi5cclxuLy8gV2UgcmV0dXJuIHVuZGVmaW5lZCwgaW5zdGVhZCBvZiBub3RoaW5nIGhlcmUsIHNvIGl0J3NcclxuLy8gZWFzaWVyIHRvIGhhbmRsZSB0aGlzIGNhc2UuIGlmKCFnbG9iYWwpIHsgLi4ufVxyXG5cclxubW9kdWxlLmV4cG9ydHMgPSBnO1xyXG4iLCJcInVzZSBzdHJpY3RcIjtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuY29uc3Qgc2Nyb2xsX3N5bmNfMSA9IHJlcXVpcmUoXCIuL3Njcm9sbC1zeW5jXCIpO1xuY2xhc3MgQWN0aXZlTGluZU1hcmtlciB7XG4gICAgb25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGxpbmUpIHtcbiAgICAgICAgY29uc3QgeyBwcmV2aW91cyB9ID0gc2Nyb2xsX3N5bmNfMS5nZXRFbGVtZW50c0ZvclNvdXJjZUxpbmUobGluZSk7XG4gICAgICAgIHRoaXMuX3VwZGF0ZShwcmV2aW91cyAmJiBwcmV2aW91cy5lbGVtZW50KTtcbiAgICB9XG4gICAgX3VwZGF0ZShiZWZvcmUpIHtcbiAgICAgICAgdGhpcy5fdW5tYXJrQWN0aXZlRWxlbWVudCh0aGlzLl9jdXJyZW50KTtcbiAgICAgICAgdGhpcy5fbWFya0FjdGl2ZUVsZW1lbnQoYmVmb3JlKTtcbiAgICAgICAgdGhpcy5fY3VycmVudCA9IGJlZm9yZTtcbiAgICB9XG4gICAgX3VubWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlbGVtZW50LmNsYXNzTmFtZSA9IGVsZW1lbnQuY2xhc3NOYW1lLnJlcGxhY2UoL1xcYmNvZGUtYWN0aXZlLWxpbmVcXGIvZywgJycpO1xuICAgIH1cbiAgICBfbWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlbGVtZW50LmNsYXNzTmFtZSArPSAnIGNvZGUtYWN0aXZlLWxpbmUnO1xuICAgIH1cbn1cbmV4cG9ydHMuQWN0aXZlTGluZU1hcmtlciA9IEFjdGl2ZUxpbmVNYXJrZXI7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZnVuY3Rpb24gb25jZURvY3VtZW50TG9hZGVkKGYpIHtcbiAgICBpZiAoZG9jdW1lbnQucmVhZHlTdGF0ZSA9PT0gJ2xvYWRpbmcnIHx8IGRvY3VtZW50LnJlYWR5U3RhdGUgPT09ICd1bmluaXRpYWxpemVkJykge1xuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgZik7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBmKCk7XG4gICAgfVxufVxuZXhwb3J0cy5vbmNlRG9jdW1lbnRMb2FkZWQgPSBvbmNlRG9jdW1lbnRMb2FkZWQ7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3QgYWN0aXZlTGluZU1hcmtlcl8xID0gcmVxdWlyZShcIi4vYWN0aXZlTGluZU1hcmtlclwiKTtcbmNvbnN0IGV2ZW50c18xID0gcmVxdWlyZShcIi4vZXZlbnRzXCIpO1xuY29uc3QgbWVzc2FnaW5nXzEgPSByZXF1aXJlKFwiLi9tZXNzYWdpbmdcIik7XG5jb25zdCBzY3JvbGxfc3luY18xID0gcmVxdWlyZShcIi4vc2Nyb2xsLXN5bmNcIik7XG5jb25zdCBzZXR0aW5nc18xID0gcmVxdWlyZShcIi4vc2V0dGluZ3NcIik7XG5jb25zdCB0aHJvdHRsZSA9IHJlcXVpcmUoXCJsb2Rhc2gudGhyb3R0bGVcIik7XG5sZXQgc2Nyb2xsRGlzYWJsZWQgPSB0cnVlO1xuY29uc3QgbWFya2VyID0gbmV3IGFjdGl2ZUxpbmVNYXJrZXJfMS5BY3RpdmVMaW5lTWFya2VyKCk7XG5jb25zdCBzZXR0aW5ncyA9IHNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKTtcbmNvbnN0IHZzY29kZSA9IGFjcXVpcmVWc0NvZGVBcGkoKTtcbi8vIFNldCBWUyBDb2RlIHN0YXRlXG5sZXQgc3RhdGUgPSBzZXR0aW5nc18xLmdldERhdGEoJ2RhdGEtc3RhdGUnKTtcbnZzY29kZS5zZXRTdGF0ZShzdGF0ZSk7XG5jb25zdCBtZXNzYWdpbmcgPSBtZXNzYWdpbmdfMS5jcmVhdGVQb3N0ZXJGb3JWc0NvZGUodnNjb2RlKTtcbndpbmRvdy5jc3BBbGVydGVyLnNldFBvc3RlcihtZXNzYWdpbmcpO1xud2luZG93LnN0eWxlTG9hZGluZ01vbml0b3Iuc2V0UG9zdGVyKG1lc3NhZ2luZyk7XG53aW5kb3cub25sb2FkID0gKCkgPT4ge1xuICAgIHVwZGF0ZUltYWdlU2l6ZXMoKTtcbn07XG5ldmVudHNfMS5vbmNlRG9jdW1lbnRMb2FkZWQoKCkgPT4ge1xuICAgIGlmIChzZXR0aW5ncy5zY3JvbGxQcmV2aWV3V2l0aEVkaXRvcikge1xuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIC8vIFRyeSB0byBzY3JvbGwgdG8gZnJhZ21lbnQgaWYgYXZhaWxhYmxlXG4gICAgICAgICAgICBpZiAoc3RhdGUuZnJhZ21lbnQpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBlbGVtZW50ID0gc2Nyb2xsX3N5bmNfMS5nZXRMaW5lRWxlbWVudEZvckZyYWdtZW50KHN0YXRlLmZyYWdtZW50KTtcbiAgICAgICAgICAgICAgICBpZiAoZWxlbWVudCkge1xuICAgICAgICAgICAgICAgICAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNjcm9sbF9zeW5jXzEuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGVsZW1lbnQubGluZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc3QgaW5pdGlhbExpbmUgPSArc2V0dGluZ3MubGluZTtcbiAgICAgICAgICAgICAgICBpZiAoIWlzTmFOKGluaXRpYWxMaW5lKSkge1xuICAgICAgICAgICAgICAgICAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNjcm9sbF9zeW5jXzEuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGluaXRpYWxMaW5lKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIDApO1xuICAgIH1cbn0pO1xuY29uc3Qgb25VcGRhdGVWaWV3ID0gKCgpID0+IHtcbiAgICBjb25zdCBkb1Njcm9sbCA9IHRocm90dGxlKChsaW5lKSA9PiB7XG4gICAgICAgIHNjcm9sbERpc2FibGVkID0gdHJ1ZTtcbiAgICAgICAgc2Nyb2xsX3N5bmNfMS5zY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUobGluZSk7XG4gICAgfSwgNTApO1xuICAgIHJldHVybiAobGluZSwgc2V0dGluZ3MpID0+IHtcbiAgICAgICAgaWYgKCFpc05hTihsaW5lKSkge1xuICAgICAgICAgICAgc2V0dGluZ3MubGluZSA9IGxpbmU7XG4gICAgICAgICAgICBkb1Njcm9sbChsaW5lKTtcbiAgICAgICAgfVxuICAgIH07XG59KSgpO1xubGV0IHVwZGF0ZUltYWdlU2l6ZXMgPSB0aHJvdHRsZSgoKSA9PiB7XG4gICAgY29uc3QgaW1hZ2VJbmZvID0gW107XG4gICAgbGV0IGltYWdlcyA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdpbWcnKTtcbiAgICBpZiAoaW1hZ2VzKSB7XG4gICAgICAgIGxldCBpO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgaW1hZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBpbWcgPSBpbWFnZXNbaV07XG4gICAgICAgICAgICBpZiAoaW1nLmNsYXNzTGlzdC5jb250YWlucygnbG9hZGluZycpKSB7XG4gICAgICAgICAgICAgICAgaW1nLmNsYXNzTGlzdC5yZW1vdmUoJ2xvYWRpbmcnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGltYWdlSW5mby5wdXNoKHtcbiAgICAgICAgICAgICAgICBpZDogaW1nLmlkLFxuICAgICAgICAgICAgICAgIGhlaWdodDogaW1nLmhlaWdodCxcbiAgICAgICAgICAgICAgICB3aWR0aDogaW1nLndpZHRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ2NhY2hlSW1hZ2VTaXplcycsIGltYWdlSW5mbyk7XG4gICAgfVxufSwgNTApO1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsICgpID0+IHtcbiAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgdXBkYXRlSW1hZ2VTaXplcygpO1xufSwgdHJ1ZSk7XG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIGV2ZW50ID0+IHtcbiAgICBpZiAoZXZlbnQuZGF0YS5zb3VyY2UgIT09IHNldHRpbmdzLnNvdXJjZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHN3aXRjaCAoZXZlbnQuZGF0YS50eXBlKSB7XG4gICAgICAgIGNhc2UgJ29uRGlkQ2hhbmdlVGV4dEVkaXRvclNlbGVjdGlvbic6XG4gICAgICAgICAgICBtYXJrZXIub25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGV2ZW50LmRhdGEubGluZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAndXBkYXRlVmlldyc6XG4gICAgICAgICAgICBvblVwZGF0ZVZpZXcoZXZlbnQuZGF0YS5saW5lLCBzZXR0aW5ncyk7XG4gICAgICAgICAgICBicmVhaztcbiAgICB9XG59LCBmYWxzZSk7XG5kb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdkYmxjbGljaycsIGV2ZW50ID0+IHtcbiAgICBpZiAoIXNldHRpbmdzLmRvdWJsZUNsaWNrVG9Td2l0Y2hUb0VkaXRvcikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIElnbm9yZSBjbGlja3Mgb24gbGlua3NcbiAgICBmb3IgKGxldCBub2RlID0gZXZlbnQudGFyZ2V0OyBub2RlOyBub2RlID0gbm9kZS5wYXJlbnROb2RlKSB7XG4gICAgICAgIGlmIChub2RlLnRhZ05hbWUgPT09ICdBJykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0IG9mZnNldCA9IGV2ZW50LnBhZ2VZO1xuICAgIGNvbnN0IGxpbmUgPSBzY3JvbGxfc3luY18xLmdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0KG9mZnNldCk7XG4gICAgaWYgKHR5cGVvZiBsaW5lID09PSAnbnVtYmVyJyAmJiAhaXNOYU4obGluZSkpIHtcbiAgICAgICAgbWVzc2FnaW5nLnBvc3RNZXNzYWdlKCdkaWRDbGljaycsIHsgbGluZTogTWF0aC5mbG9vcihsaW5lKSB9KTtcbiAgICB9XG59KTtcbmRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZXZlbnQgPT4ge1xuICAgIGlmICghZXZlbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgbm9kZSA9IGV2ZW50LnRhcmdldDtcbiAgICB3aGlsZSAobm9kZSkge1xuICAgICAgICBpZiAobm9kZS50YWdOYW1lICYmIG5vZGUudGFnTmFtZSA9PT0gJ0EnICYmIG5vZGUuaHJlZikge1xuICAgICAgICAgICAgaWYgKG5vZGUuZ2V0QXR0cmlidXRlKCdocmVmJykuc3RhcnRzV2l0aCgnIycpKSB7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobm9kZS5ocmVmLnN0YXJ0c1dpdGgoJ2ZpbGU6Ly8nKSB8fCBub2RlLmhyZWYuc3RhcnRzV2l0aCgndnNjb2RlLXJlc291cmNlOicpIHx8IG5vZGUuaHJlZi5zdGFydHNXaXRoKHNldHRpbmdzLndlYnZpZXdSZXNvdXJjZVJvb3QpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgW3BhdGgsIGZyYWdtZW50XSA9IG5vZGUuaHJlZi5yZXBsYWNlKC9eKGZpbGU6XFwvXFwvfHZzY29kZS1yZXNvdXJjZTopL2ksICcnKS5yZXBsYWNlKG5ldyBSZWdFeHAoYF4ke2VzY2FwZVJlZ0V4cChzZXR0aW5ncy53ZWJ2aWV3UmVzb3VyY2VSb290KX1gKSkuc3BsaXQoJyMnKTtcbiAgICAgICAgICAgICAgICBtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ2NsaWNrTGluaycsIHsgcGF0aCwgZnJhZ21lbnQgfSk7XG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIG5vZGUgPSBub2RlLnBhcmVudE5vZGU7XG4gICAgfVxufSwgdHJ1ZSk7XG5pZiAoc2V0dGluZ3Muc2Nyb2xsRWRpdG9yV2l0aFByZXZpZXcpIHtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgdGhyb3R0bGUoKCkgPT4ge1xuICAgICAgICBpZiAoc2Nyb2xsRGlzYWJsZWQpIHtcbiAgICAgICAgICAgIHNjcm9sbERpc2FibGVkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBsaW5lID0gc2Nyb2xsX3N5bmNfMS5nZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldCh3aW5kb3cuc2Nyb2xsWSk7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGxpbmUgPT09ICdudW1iZXInICYmICFpc05hTihsaW5lKSkge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2luZy5wb3N0TWVzc2FnZSgncmV2ZWFsTGluZScsIHsgbGluZSB9KTtcbiAgICAgICAgICAgICAgICBzdGF0ZS5saW5lID0gbGluZTtcbiAgICAgICAgICAgICAgICB2c2NvZGUuc2V0U3RhdGUoc3RhdGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSwgNTApKTtcbn1cbmZ1bmN0aW9uIGVzY2FwZVJlZ0V4cCh0ZXh0KSB7XG4gICAgcmV0dXJuIHRleHQucmVwbGFjZSgvWy1bXFxde30oKSorPy4sXFxcXF4kfCNcXHNdL2csICdcXFxcJCYnKTtcbn1cbiIsIlwidXNlIHN0cmljdFwiO1xuLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5jb25zdCBzZXR0aW5nc18xID0gcmVxdWlyZShcIi4vc2V0dGluZ3NcIik7XG5leHBvcnRzLmNyZWF0ZVBvc3RlckZvclZzQ29kZSA9ICh2c2NvZGUpID0+IHtcbiAgICByZXR1cm4gbmV3IGNsYXNzIHtcbiAgICAgICAgcG9zdE1lc3NhZ2UodHlwZSwgYm9keSkge1xuICAgICAgICAgICAgdnNjb2RlLnBvc3RNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICB0eXBlLFxuICAgICAgICAgICAgICAgIHNvdXJjZTogc2V0dGluZ3NfMS5nZXRTZXR0aW5ncygpLnNvdXJjZSxcbiAgICAgICAgICAgICAgICBib2R5XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH07XG59O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG4vKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmNvbnN0IHNldHRpbmdzXzEgPSByZXF1aXJlKFwiLi9zZXR0aW5nc1wiKTtcbmZ1bmN0aW9uIGNsYW1wKG1pbiwgbWF4LCB2YWx1ZSkge1xuICAgIHJldHVybiBNYXRoLm1pbihtYXgsIE1hdGgubWF4KG1pbiwgdmFsdWUpKTtcbn1cbmZ1bmN0aW9uIGNsYW1wTGluZShsaW5lKSB7XG4gICAgcmV0dXJuIGNsYW1wKDAsIHNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKS5saW5lQ291bnQgLSAxLCBsaW5lKTtcbn1cbmNvbnN0IGdldENvZGVMaW5lRWxlbWVudHMgPSAoKCkgPT4ge1xuICAgIGxldCBlbGVtZW50cztcbiAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICBpZiAoIWVsZW1lbnRzKSB7XG4gICAgICAgICAgICBlbGVtZW50cyA9IFt7IGVsZW1lbnQ6IGRvY3VtZW50LmJvZHksIGxpbmU6IDAgfV07XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSgnY29kZS1saW5lJykpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBsaW5lID0gK2VsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLWxpbmUnKTtcbiAgICAgICAgICAgICAgICBpZiAoIWlzTmFOKGxpbmUpKSB7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzLnB1c2goeyBlbGVtZW50OiBlbGVtZW50LCBsaW5lIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZWxlbWVudHM7XG4gICAgfTtcbn0pKCk7XG4vKipcbiAqIEZpbmQgdGhlIGh0bWwgZWxlbWVudHMgdGhhdCBtYXAgdG8gYSBzcGVjaWZpYyB0YXJnZXQgbGluZSBpbiB0aGUgZWRpdG9yLlxuICpcbiAqIElmIGFuIGV4YWN0IG1hdGNoLCByZXR1cm5zIGEgc2luZ2xlIGVsZW1lbnQuIElmIHRoZSBsaW5lIGlzIGJldHdlZW4gZWxlbWVudHMsXG4gKiByZXR1cm5zIHRoZSBlbGVtZW50IHByaW9yIHRvIGFuZCB0aGUgZWxlbWVudCBhZnRlciB0aGUgZ2l2ZW4gbGluZS5cbiAqL1xuZnVuY3Rpb24gZ2V0RWxlbWVudHNGb3JTb3VyY2VMaW5lKHRhcmdldExpbmUpIHtcbiAgICBjb25zdCBsaW5lTnVtYmVyID0gTWF0aC5mbG9vcih0YXJnZXRMaW5lKTtcbiAgICBjb25zdCBsaW5lcyA9IGdldENvZGVMaW5lRWxlbWVudHMoKTtcbiAgICBsZXQgcHJldmlvdXMgPSBsaW5lc1swXSB8fCBudWxsO1xuICAgIGZvciAoY29uc3QgZW50cnkgb2YgbGluZXMpIHtcbiAgICAgICAgaWYgKGVudHJ5LmxpbmUgPT09IGxpbmVOdW1iZXIpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHByZXZpb3VzOiBlbnRyeSwgbmV4dDogdW5kZWZpbmVkIH07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZW50cnkubGluZSA+IGxpbmVOdW1iZXIpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHByZXZpb3VzLCBuZXh0OiBlbnRyeSB9O1xuICAgICAgICB9XG4gICAgICAgIHByZXZpb3VzID0gZW50cnk7XG4gICAgfVxuICAgIHJldHVybiB7IHByZXZpb3VzIH07XG59XG5leHBvcnRzLmdldEVsZW1lbnRzRm9yU291cmNlTGluZSA9IGdldEVsZW1lbnRzRm9yU291cmNlTGluZTtcbi8qKlxuICogRmluZCB0aGUgaHRtbCBlbGVtZW50cyB0aGF0IGFyZSBhdCBhIHNwZWNpZmljIHBpeGVsIG9mZnNldCBvbiB0aGUgcGFnZS5cbiAqL1xuZnVuY3Rpb24gZ2V0TGluZUVsZW1lbnRzQXRQYWdlT2Zmc2V0KG9mZnNldCkge1xuICAgIGNvbnN0IGxpbmVzID0gZ2V0Q29kZUxpbmVFbGVtZW50cygpO1xuICAgIGNvbnN0IHBvc2l0aW9uID0gb2Zmc2V0IC0gd2luZG93LnNjcm9sbFk7XG4gICAgbGV0IGxvID0gLTE7XG4gICAgbGV0IGhpID0gbGluZXMubGVuZ3RoIC0gMTtcbiAgICB3aGlsZSAobG8gKyAxIDwgaGkpIHtcbiAgICAgICAgY29uc3QgbWlkID0gTWF0aC5mbG9vcigobG8gKyBoaSkgLyAyKTtcbiAgICAgICAgY29uc3QgYm91bmRzID0gbGluZXNbbWlkXS5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBpZiAoYm91bmRzLnRvcCArIGJvdW5kcy5oZWlnaHQgPj0gcG9zaXRpb24pIHtcbiAgICAgICAgICAgIGhpID0gbWlkO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgbG8gPSBtaWQ7XG4gICAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgaGlFbGVtZW50ID0gbGluZXNbaGldO1xuICAgIGNvbnN0IGhpQm91bmRzID0gaGlFbGVtZW50LmVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgaWYgKGhpID49IDEgJiYgaGlCb3VuZHMudG9wID4gcG9zaXRpb24pIHtcbiAgICAgICAgY29uc3QgbG9FbGVtZW50ID0gbGluZXNbbG9dO1xuICAgICAgICByZXR1cm4geyBwcmV2aW91czogbG9FbGVtZW50LCBuZXh0OiBoaUVsZW1lbnQgfTtcbiAgICB9XG4gICAgcmV0dXJuIHsgcHJldmlvdXM6IGhpRWxlbWVudCB9O1xufVxuZXhwb3J0cy5nZXRMaW5lRWxlbWVudHNBdFBhZ2VPZmZzZXQgPSBnZXRMaW5lRWxlbWVudHNBdFBhZ2VPZmZzZXQ7XG4vKipcbiAqIEF0dGVtcHQgdG8gcmV2ZWFsIHRoZSBlbGVtZW50IGZvciBhIHNvdXJjZSBsaW5lIGluIHRoZSBlZGl0b3IuXG4gKi9cbmZ1bmN0aW9uIHNjcm9sbFRvUmV2ZWFsU291cmNlTGluZShsaW5lKSB7XG4gICAgaWYgKCFzZXR0aW5nc18xLmdldFNldHRpbmdzKCkuc2Nyb2xsUHJldmlld1dpdGhFZGl0b3IpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAobGluZSA8PSAwKSB7XG4gICAgICAgIHdpbmRvdy5zY3JvbGwod2luZG93LnNjcm9sbFgsIDApO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHsgcHJldmlvdXMsIG5leHQgfSA9IGdldEVsZW1lbnRzRm9yU291cmNlTGluZShsaW5lKTtcbiAgICBpZiAoIXByZXZpb3VzKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgbGV0IHNjcm9sbFRvID0gMDtcbiAgICBjb25zdCByZWN0ID0gcHJldmlvdXMuZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICBjb25zdCBwcmV2aW91c1RvcCA9IHJlY3QudG9wO1xuICAgIGlmIChuZXh0ICYmIG5leHQubGluZSAhPT0gcHJldmlvdXMubGluZSkge1xuICAgICAgICAvLyBCZXR3ZWVuIHR3byBlbGVtZW50cy4gR28gdG8gcGVyY2VudGFnZSBvZmZzZXQgYmV0d2VlbiB0aGVtLlxuICAgICAgICBjb25zdCBiZXR3ZWVuUHJvZ3Jlc3MgPSAobGluZSAtIHByZXZpb3VzLmxpbmUpIC8gKG5leHQubGluZSAtIHByZXZpb3VzLmxpbmUpO1xuICAgICAgICBjb25zdCBlbGVtZW50T2Zmc2V0ID0gbmV4dC5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCAtIHByZXZpb3VzVG9wO1xuICAgICAgICBzY3JvbGxUbyA9IHByZXZpb3VzVG9wICsgYmV0d2VlblByb2dyZXNzICogZWxlbWVudE9mZnNldDtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGNvbnN0IHByb2dyZXNzSW5FbGVtZW50ID0gbGluZSAtIE1hdGguZmxvb3IobGluZSk7XG4gICAgICAgIHNjcm9sbFRvID0gcHJldmlvdXNUb3AgKyAocmVjdC5oZWlnaHQgKiBwcm9ncmVzc0luRWxlbWVudCk7XG4gICAgfVxuICAgIHdpbmRvdy5zY3JvbGwod2luZG93LnNjcm9sbFgsIE1hdGgubWF4KDEsIHdpbmRvdy5zY3JvbGxZICsgc2Nyb2xsVG8pKTtcbn1cbmV4cG9ydHMuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lID0gc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lO1xuZnVuY3Rpb24gZ2V0RWRpdG9yTGluZU51bWJlckZvclBhZ2VPZmZzZXQob2Zmc2V0KSB7XG4gICAgY29uc3QgeyBwcmV2aW91cywgbmV4dCB9ID0gZ2V0TGluZUVsZW1lbnRzQXRQYWdlT2Zmc2V0KG9mZnNldCk7XG4gICAgaWYgKHByZXZpb3VzKSB7XG4gICAgICAgIGNvbnN0IHByZXZpb3VzQm91bmRzID0gcHJldmlvdXMuZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgICAgY29uc3Qgb2Zmc2V0RnJvbVByZXZpb3VzID0gKG9mZnNldCAtIHdpbmRvdy5zY3JvbGxZIC0gcHJldmlvdXNCb3VuZHMudG9wKTtcbiAgICAgICAgaWYgKG5leHQpIHtcbiAgICAgICAgICAgIGNvbnN0IHByb2dyZXNzQmV0d2VlbkVsZW1lbnRzID0gb2Zmc2V0RnJvbVByZXZpb3VzIC8gKG5leHQuZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3AgLSBwcmV2aW91c0JvdW5kcy50b3ApO1xuICAgICAgICAgICAgY29uc3QgbGluZSA9IHByZXZpb3VzLmxpbmUgKyBwcm9ncmVzc0JldHdlZW5FbGVtZW50cyAqIChuZXh0LmxpbmUgLSBwcmV2aW91cy5saW5lKTtcbiAgICAgICAgICAgIHJldHVybiBjbGFtcExpbmUobGluZSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBwcm9ncmVzc1dpdGhpbkVsZW1lbnQgPSBvZmZzZXRGcm9tUHJldmlvdXMgLyAocHJldmlvdXNCb3VuZHMuaGVpZ2h0KTtcbiAgICAgICAgICAgIGNvbnN0IGxpbmUgPSBwcmV2aW91cy5saW5lICsgcHJvZ3Jlc3NXaXRoaW5FbGVtZW50O1xuICAgICAgICAgICAgcmV0dXJuIGNsYW1wTGluZShsaW5lKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cbmV4cG9ydHMuZ2V0RWRpdG9yTGluZU51bWJlckZvclBhZ2VPZmZzZXQgPSBnZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldDtcbi8qKlxuICogVHJ5IHRvIGZpbmQgdGhlIGh0bWwgZWxlbWVudCBieSB1c2luZyBhIGZyYWdtZW50IGlkXG4gKi9cbmZ1bmN0aW9uIGdldExpbmVFbGVtZW50Rm9yRnJhZ21lbnQoZnJhZ21lbnQpIHtcbiAgICByZXR1cm4gZ2V0Q29kZUxpbmVFbGVtZW50cygpLmZpbmQoKGVsZW1lbnQpID0+IHtcbiAgICAgICAgcmV0dXJuIGVsZW1lbnQuZWxlbWVudC5pZCA9PT0gZnJhZ21lbnQ7XG4gICAgfSk7XG59XG5leHBvcnRzLmdldExpbmVFbGVtZW50Rm9yRnJhZ21lbnQgPSBnZXRMaW5lRWxlbWVudEZvckZyYWdtZW50O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG4vKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmxldCBjYWNoZWRTZXR0aW5ncyA9IHVuZGVmaW5lZDtcbmZ1bmN0aW9uIGdldERhdGEoa2V5KSB7XG4gICAgY29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2c2NvZGUtbWFya2Rvd24tcHJldmlldy1kYXRhJyk7XG4gICAgaWYgKGVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgZGF0YSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKGtleSk7XG4gICAgICAgIGlmIChkYXRhKSB7XG4gICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShkYXRhKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCBsb2FkIGRhdGEgZm9yICR7a2V5fWApO1xufVxuZXhwb3J0cy5nZXREYXRhID0gZ2V0RGF0YTtcbmZ1bmN0aW9uIGdldFNldHRpbmdzKCkge1xuICAgIGlmIChjYWNoZWRTZXR0aW5ncykge1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG4gICAgfVxuICAgIGNhY2hlZFNldHRpbmdzID0gZ2V0RGF0YSgnZGF0YS1zZXR0aW5ncycpO1xuICAgIGlmIChjYWNoZWRTZXR0aW5ncykge1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcignQ291bGQgbm90IGxvYWQgc2V0dGluZ3MnKTtcbn1cbmV4cG9ydHMuZ2V0U2V0dGluZ3MgPSBnZXRTZXR0aW5ncztcbiJdLCJzb3VyY2VSb290IjoiIn0= \ No newline at end of file diff --git a/extensions/markdown-language-features/media/pre.js b/extensions/markdown-language-features/media/pre.js index 85e9c264915..5c9c7fb3b8b 100644 --- a/extensions/markdown-language-features/media/pre.js +++ b/extensions/markdown-language-features/media/pre.js @@ -277,4 +277,4 @@ exports.getStrings = getStrings; /***/ }) /******/ }); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvY3NwLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2xvYWRpbmcudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvcHJlLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL3NldHRpbmdzLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL3N0cmluZ3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0EseURBQWlELGNBQWM7QUFDL0Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsbUNBQTJCLDBCQUEwQixFQUFFO0FBQ3ZELHlDQUFpQyxlQUFlO0FBQ2hEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhEQUFzRCwrREFBK0Q7O0FBRXJIO0FBQ0E7OztBQUdBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDbkVBOzs7Z0dBR2dHOztBQUdoRyxzRkFBeUM7QUFDekMsbUZBQXVDO0FBRXZDOztHQUVHO0FBQ0gsTUFBYSxVQUFVO0lBTXRCO1FBTFEsWUFBTyxHQUFHLEtBQUssQ0FBQztRQUNoQixzQkFBaUIsR0FBRyxLQUFLLENBQUM7UUFLakMsUUFBUSxDQUFDLGdCQUFnQixDQUFDLHlCQUF5QixFQUFFLEdBQUcsRUFBRTtZQUN6RCxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDckIsQ0FBQyxDQUFDLENBQUM7UUFFSCxNQUFNLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDNUMsSUFBSSxLQUFLLElBQUksS0FBSyxDQUFDLElBQUksSUFBSSxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksS0FBSyxzQkFBc0IsRUFBRTtnQkFDdEUsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO2FBQ3BCO1FBQ0YsQ0FBQyxDQUFDLENBQUM7SUFDSixDQUFDO0lBRU0sU0FBUyxDQUFDLE1BQXFCO1FBQ3JDLElBQUksQ0FBQyxTQUFTLEdBQUcsTUFBTSxDQUFDO1FBQ3hCLElBQUksSUFBSSxDQUFDLGlCQUFpQixFQUFFO1lBQzNCLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztTQUN0QjtJQUNGLENBQUM7SUFFTyxZQUFZO1FBQ25CLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUM7UUFDOUIsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQ3ZCLENBQUM7SUFFTyxjQUFjO1FBQ3JCLE1BQU0sT0FBTyxHQUFHLG9CQUFVLEVBQUUsQ0FBQztRQUM3QixNQUFNLFFBQVEsR0FBRyxzQkFBVyxFQUFFLENBQUM7UUFFL0IsSUFBSSxJQUFJLENBQUMsT0FBTyxJQUFJLFFBQVEsQ0FBQyx1QkFBdUIsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDeEUsT0FBTztTQUNQO1FBQ0QsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7UUFFcEIsTUFBTSxZQUFZLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNqRCxZQUFZLENBQUMsU0FBUyxHQUFHLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQztRQUNyRCxZQUFZLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO1FBQ3BELFlBQVksQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBRWpFLFlBQVksQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQzVDLFlBQVksQ0FBQyxZQUFZLENBQUMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQ3RFLFlBQVksQ0FBQyxPQUFPLEdBQUcsR0FBRyxFQUFFO1lBQzNCLElBQUksQ0FBQyxTQUFVLENBQUMsV0FBVyxDQUFDLDZCQUE2QixFQUFFLEVBQUUsTUFBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQ3pGLENBQUMsQ0FBQztRQUNGLFFBQVEsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQ3pDLENBQUM7Q0FDRDtBQW5ERCxnQ0FtREM7Ozs7Ozs7Ozs7Ozs7OztBQ3pERCxNQUFhLG1CQUFtQjtJQU0vQjtRQUxRLG1CQUFjLEdBQWEsRUFBRSxDQUFDO1FBQzlCLG9CQUFlLEdBQVksS0FBSyxDQUFDO1FBS3hDLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxLQUFVLEVBQUUsRUFBRTtZQUN2QyxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7WUFDM0MsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDbEMsQ0FBQyxDQUFDO1FBRUYsTUFBTSxDQUFDLGdCQUFnQixDQUFDLGtCQUFrQixFQUFFLEdBQUcsRUFBRTtZQUNoRCxLQUFLLE1BQU0sSUFBSSxJQUFJLFFBQVEsQ0FBQyxzQkFBc0IsQ0FBQyxpQkFBaUIsQ0FBa0MsRUFBRTtnQkFDdkcsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRTtvQkFDeEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxnQkFBZ0IsQ0FBQztpQkFDaEM7YUFDRDtRQUNGLENBQUMsQ0FBQyxDQUFDO1FBRUgsTUFBTSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUU7WUFDcEMsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFO2dCQUNoQyxPQUFPO2FBQ1A7WUFDRCxJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQztZQUM1QixJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUU7Z0JBQ2hCLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLHVCQUF1QixFQUFFLEVBQUUsY0FBYyxFQUFFLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDO2FBQzFGO1FBQ0YsQ0FBQyxDQUFDLENBQUM7SUFDSixDQUFDO0lBRU0sU0FBUyxDQUFDLE1BQXFCO1FBQ3JDLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksSUFBSSxDQUFDLGVBQWUsRUFBRTtZQUN6QixNQUFNLENBQUMsV0FBVyxDQUFDLHVCQUF1QixFQUFFLEVBQUUsY0FBYyxFQUFFLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDO1NBQ3JGO0lBQ0YsQ0FBQztDQUNEO0FBckNELGtEQXFDQzs7Ozs7Ozs7Ozs7Ozs7QUMzQ0Q7OztnR0FHZ0c7O0FBRWhHLHVFQUFtQztBQUNuQyxtRkFBZ0Q7QUFTaEQsTUFBTSxDQUFDLFVBQVUsR0FBRyxJQUFJLGdCQUFVLEVBQUUsQ0FBQztBQUNyQyxNQUFNLENBQUMsbUJBQW1CLEdBQUcsSUFBSSw2QkFBbUIsRUFBRSxDQUFDOzs7Ozs7Ozs7Ozs7OztBQ2hCdkQ7OztnR0FHZ0c7O0FBYWhHLElBQUksY0FBYyxHQUFnQyxTQUFTLENBQUM7QUFFNUQsU0FBZ0IsT0FBTyxDQUFTLEdBQVc7SUFDMUMsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDLGNBQWMsQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO0lBQ3hFLElBQUksT0FBTyxFQUFFO1FBQ1osTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN2QyxJQUFJLElBQUksRUFBRTtZQUNULE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUN4QjtLQUNEO0lBRUQsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsR0FBRyxFQUFFLENBQUMsQ0FBQztBQUNuRCxDQUFDO0FBVkQsMEJBVUM7QUFFRCxTQUFnQixXQUFXO0lBQzFCLElBQUksY0FBYyxFQUFFO1FBQ25CLE9BQU8sY0FBYyxDQUFDO0tBQ3RCO0lBRUQsY0FBYyxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUMxQyxJQUFJLGNBQWMsRUFBRTtRQUNuQixPQUFPLGNBQWMsQ0FBQztLQUN0QjtJQUVELE1BQU0sSUFBSSxLQUFLLENBQUMseUJBQXlCLENBQUMsQ0FBQztBQUM1QyxDQUFDO0FBWEQsa0NBV0M7Ozs7Ozs7Ozs7Ozs7O0FDekNEOzs7Z0dBR2dHOztBQUVoRyxTQUFnQixVQUFVO0lBQ3pCLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxjQUFjLENBQUMsOEJBQThCLENBQUMsQ0FBQztJQUN0RSxJQUFJLEtBQUssRUFBRTtRQUNWLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxZQUFZLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDaEQsSUFBSSxJQUFJLEVBQUU7WUFDVCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDeEI7S0FDRDtJQUNELE1BQU0sSUFBSSxLQUFLLENBQUMsd0JBQXdCLENBQUMsQ0FBQztBQUMzQyxDQUFDO0FBVEQsZ0NBU0MiLCJmaWxlIjoicHJlLmpzIiwic291cmNlc0NvbnRlbnQiOlsiIFx0Ly8gVGhlIG1vZHVsZSBjYWNoZVxuIFx0dmFyIGluc3RhbGxlZE1vZHVsZXMgPSB7fTtcblxuIFx0Ly8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbiBcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblxuIFx0XHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcbiBcdFx0aWYoaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0pIHtcbiBcdFx0XHRyZXR1cm4gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0uZXhwb3J0cztcbiBcdFx0fVxuIFx0XHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuIFx0XHR2YXIgbW9kdWxlID0gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0gPSB7XG4gXHRcdFx0aTogbW9kdWxlSWQsXG4gXHRcdFx0bDogZmFsc2UsXG4gXHRcdFx0ZXhwb3J0czoge31cbiBcdFx0fTtcblxuIFx0XHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cbiBcdFx0bW9kdWxlc1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cbiBcdFx0Ly8gRmxhZyB0aGUgbW9kdWxlIGFzIGxvYWRlZFxuIFx0XHRtb2R1bGUubCA9IHRydWU7XG5cbiBcdFx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcbiBcdFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuIFx0fVxuXG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZSBjYWNoZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5jID0gaW5zdGFsbGVkTW9kdWxlcztcblxuIFx0Ly8gZGVmaW5lIGdldHRlciBmdW5jdGlvbiBmb3IgaGFybW9ueSBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQgPSBmdW5jdGlvbihleHBvcnRzLCBuYW1lLCBnZXR0ZXIpIHtcbiBcdFx0aWYoIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBuYW1lKSkge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBuYW1lLCB7XG4gXHRcdFx0XHRjb25maWd1cmFibGU6IGZhbHNlLFxuIFx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcbiBcdFx0XHRcdGdldDogZ2V0dGVyXG4gXHRcdFx0fSk7XG4gXHRcdH1cbiBcdH07XG5cbiBcdC8vIGRlZmluZSBfX2VzTW9kdWxlIG9uIGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uciA9IGZ1bmN0aW9uKGV4cG9ydHMpIHtcbiBcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogdHJ1ZSB9KTtcbiBcdH07XG5cbiBcdC8vIGdldERlZmF1bHRFeHBvcnQgZnVuY3Rpb24gZm9yIGNvbXBhdGliaWxpdHkgd2l0aCBub24taGFybW9ueSBtb2R1bGVzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm4gPSBmdW5jdGlvbihtb2R1bGUpIHtcbiBcdFx0dmFyIGdldHRlciA9IG1vZHVsZSAmJiBtb2R1bGUuX19lc01vZHVsZSA/XG4gXHRcdFx0ZnVuY3Rpb24gZ2V0RGVmYXVsdCgpIHsgcmV0dXJuIG1vZHVsZVsnZGVmYXVsdCddOyB9IDpcbiBcdFx0XHRmdW5jdGlvbiBnZXRNb2R1bGVFeHBvcnRzKCkgeyByZXR1cm4gbW9kdWxlOyB9O1xuIFx0XHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQoZ2V0dGVyLCAnYScsIGdldHRlcik7XG4gXHRcdHJldHVybiBnZXR0ZXI7XG4gXHR9O1xuXG4gXHQvLyBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGxcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubyA9IGZ1bmN0aW9uKG9iamVjdCwgcHJvcGVydHkpIHsgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3QsIHByb3BlcnR5KTsgfTtcblxuIFx0Ly8gX193ZWJwYWNrX3B1YmxpY19wYXRoX19cbiBcdF9fd2VicGFja19yZXF1aXJlX18ucCA9IFwiXCI7XG5cblxuIFx0Ly8gTG9hZCBlbnRyeSBtb2R1bGUgYW5kIHJldHVybiBleHBvcnRzXG4gXHRyZXR1cm4gX193ZWJwYWNrX3JlcXVpcmVfXyhfX3dlYnBhY2tfcmVxdWlyZV9fLnMgPSBcIi4vcHJldmlldy1zcmMvcHJlLnRzXCIpO1xuIiwiLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbmltcG9ydCB7IE1lc3NhZ2VQb3N0ZXIgfSBmcm9tICcuL21lc3NhZ2luZyc7XG5pbXBvcnQgeyBnZXRTZXR0aW5ncyB9IGZyb20gJy4vc2V0dGluZ3MnO1xuaW1wb3J0IHsgZ2V0U3RyaW5ncyB9IGZyb20gJy4vc3RyaW5ncyc7XG5cbi8qKlxuICogU2hvd3MgYW4gYWxlcnQgd2hlbiB0aGVyZSBpcyBhIGNvbnRlbnQgc2VjdXJpdHkgcG9saWN5IHZpb2xhdGlvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIENzcEFsZXJ0ZXIge1xuXHRwcml2YXRlIGRpZFNob3cgPSBmYWxzZTtcblx0cHJpdmF0ZSBkaWRIYXZlQ3NwV2FybmluZyA9IGZhbHNlO1xuXG5cdHByaXZhdGUgbWVzc2FnaW5nPzogTWVzc2FnZVBvc3RlcjtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblx0XHRkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdzZWN1cml0eXBvbGljeXZpb2xhdGlvbicsICgpID0+IHtcblx0XHRcdHRoaXMub25Dc3BXYXJuaW5nKCk7XG5cdFx0fSk7XG5cblx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIChldmVudCkgPT4ge1xuXHRcdFx0aWYgKGV2ZW50ICYmIGV2ZW50LmRhdGEgJiYgZXZlbnQuZGF0YS5uYW1lID09PSAndnNjb2RlLWRpZC1ibG9jay1zdmcnKSB7XG5cdFx0XHRcdHRoaXMub25Dc3BXYXJuaW5nKCk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cblxuXHRwdWJsaWMgc2V0UG9zdGVyKHBvc3RlcjogTWVzc2FnZVBvc3Rlcikge1xuXHRcdHRoaXMubWVzc2FnaW5nID0gcG9zdGVyO1xuXHRcdGlmICh0aGlzLmRpZEhhdmVDc3BXYXJuaW5nKSB7XG5cdFx0XHR0aGlzLnNob3dDc3BXYXJuaW5nKCk7XG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSBvbkNzcFdhcm5pbmcoKSB7XG5cdFx0dGhpcy5kaWRIYXZlQ3NwV2FybmluZyA9IHRydWU7XG5cdFx0dGhpcy5zaG93Q3NwV2FybmluZygpO1xuXHR9XG5cblx0cHJpdmF0ZSBzaG93Q3NwV2FybmluZygpIHtcblx0XHRjb25zdCBzdHJpbmdzID0gZ2V0U3RyaW5ncygpO1xuXHRcdGNvbnN0IHNldHRpbmdzID0gZ2V0U2V0dGluZ3MoKTtcblxuXHRcdGlmICh0aGlzLmRpZFNob3cgfHwgc2V0dGluZ3MuZGlzYWJsZVNlY3VyaXR5V2FybmluZ3MgfHwgIXRoaXMubWVzc2FnaW5nKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdHRoaXMuZGlkU2hvdyA9IHRydWU7XG5cblx0XHRjb25zdCBub3RpZmljYXRpb24gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG5cdFx0bm90aWZpY2F0aW9uLmlubmVyVGV4dCA9IHN0cmluZ3MuY3NwQWxlcnRNZXNzYWdlVGV4dDtcblx0XHRub3RpZmljYXRpb24uc2V0QXR0cmlidXRlKCdpZCcsICdjb2RlLWNzcC13YXJuaW5nJyk7XG5cdFx0bm90aWZpY2F0aW9uLnNldEF0dHJpYnV0ZSgndGl0bGUnLCBzdHJpbmdzLmNzcEFsZXJ0TWVzc2FnZVRpdGxlKTtcblxuXHRcdG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ3JvbGUnLCAnYnV0dG9uJyk7XG5cdFx0bm90aWZpY2F0aW9uLnNldEF0dHJpYnV0ZSgnYXJpYS1sYWJlbCcsIHN0cmluZ3MuY3NwQWxlcnRNZXNzYWdlTGFiZWwpO1xuXHRcdG5vdGlmaWNhdGlvbi5vbmNsaWNrID0gKCkgPT4ge1xuXHRcdFx0dGhpcy5tZXNzYWdpbmchLnBvc3RNZXNzYWdlKCdzaG93UHJldmlld1NlY3VyaXR5U2VsZWN0b3InLCB7IHNvdXJjZTogc2V0dGluZ3Muc291cmNlIH0pO1xuXHRcdH07XG5cdFx0ZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChub3RpZmljYXRpb24pO1xuXHR9XG59XG4iLCIvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbmltcG9ydCB7IE1lc3NhZ2VQb3N0ZXIgfSBmcm9tICcuL21lc3NhZ2luZyc7XG5cbmV4cG9ydCBjbGFzcyBTdHlsZUxvYWRpbmdNb25pdG9yIHtcblx0cHJpdmF0ZSB1bmxvYWRlZFN0eWxlczogc3RyaW5nW10gPSBbXTtcblx0cHJpdmF0ZSBmaW5pc2hlZExvYWRpbmc6IGJvb2xlYW4gPSBmYWxzZTtcblxuXHRwcml2YXRlIHBvc3Rlcj86IE1lc3NhZ2VQb3N0ZXI7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cdFx0Y29uc3Qgb25TdHlsZUxvYWRFcnJvciA9IChldmVudDogYW55KSA9PiB7XG5cdFx0XHRjb25zdCBzb3VyY2UgPSBldmVudC50YXJnZXQuZGF0YXNldC5zb3VyY2U7XG5cdFx0XHR0aGlzLnVubG9hZGVkU3R5bGVzLnB1c2goc291cmNlKTtcblx0XHR9O1xuXG5cdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ0RPTUNvbnRlbnRMb2FkZWQnLCAoKSA9PiB7XG5cdFx0XHRmb3IgKGNvbnN0IGxpbmsgb2YgZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSgnY29kZS11c2VyLXN0eWxlJykgYXMgSFRNTENvbGxlY3Rpb25PZjxIVE1MRWxlbWVudD4pIHtcblx0XHRcdFx0aWYgKGxpbmsuZGF0YXNldC5zb3VyY2UpIHtcblx0XHRcdFx0XHRsaW5rLm9uZXJyb3IgPSBvblN0eWxlTG9hZEVycm9yO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsICgpID0+IHtcblx0XHRcdGlmICghdGhpcy51bmxvYWRlZFN0eWxlcy5sZW5ndGgpIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5maW5pc2hlZExvYWRpbmcgPSB0cnVlO1xuXHRcdFx0aWYgKHRoaXMucG9zdGVyKSB7XG5cdFx0XHRcdHRoaXMucG9zdGVyLnBvc3RNZXNzYWdlKCdwcmV2aWV3U3R5bGVMb2FkRXJyb3InLCB7IHVubG9hZGVkU3R5bGVzOiB0aGlzLnVubG9hZGVkU3R5bGVzIH0pO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHR9XG5cblx0cHVibGljIHNldFBvc3Rlcihwb3N0ZXI6IE1lc3NhZ2VQb3N0ZXIpOiB2b2lkIHtcblx0XHR0aGlzLnBvc3RlciA9IHBvc3Rlcjtcblx0XHRpZiAodGhpcy5maW5pc2hlZExvYWRpbmcpIHtcblx0XHRcdHBvc3Rlci5wb3N0TWVzc2FnZSgncHJldmlld1N0eWxlTG9hZEVycm9yJywgeyB1bmxvYWRlZFN0eWxlczogdGhpcy51bmxvYWRlZFN0eWxlcyB9KTtcblx0XHR9XG5cdH1cbn0iLCIvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuaW1wb3J0IHsgQ3NwQWxlcnRlciB9IGZyb20gJy4vY3NwJztcbmltcG9ydCB7IFN0eWxlTG9hZGluZ01vbml0b3IgfSBmcm9tICcuL2xvYWRpbmcnO1xuXG5kZWNsYXJlIGdsb2JhbCB7XG5cdGludGVyZmFjZSBXaW5kb3cge1xuXHRcdGNzcEFsZXJ0ZXI6IENzcEFsZXJ0ZXI7XG5cdFx0c3R5bGVMb2FkaW5nTW9uaXRvcjogU3R5bGVMb2FkaW5nTW9uaXRvcjtcblx0fVxufVxuXG53aW5kb3cuY3NwQWxlcnRlciA9IG5ldyBDc3BBbGVydGVyKCk7XG53aW5kb3cuc3R5bGVMb2FkaW5nTW9uaXRvciA9IG5ldyBTdHlsZUxvYWRpbmdNb25pdG9yKCk7IiwiLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbmV4cG9ydCBpbnRlcmZhY2UgUHJldmlld1NldHRpbmdzIHtcblx0cmVhZG9ubHkgc291cmNlOiBzdHJpbmc7XG5cdHJlYWRvbmx5IGxpbmU6IG51bWJlcjtcblx0cmVhZG9ubHkgbGluZUNvdW50OiBudW1iZXI7XG5cdHJlYWRvbmx5IHNjcm9sbFByZXZpZXdXaXRoRWRpdG9yPzogYm9vbGVhbjtcblx0cmVhZG9ubHkgc2Nyb2xsRWRpdG9yV2l0aFByZXZpZXc6IGJvb2xlYW47XG5cdHJlYWRvbmx5IGRpc2FibGVTZWN1cml0eVdhcm5pbmdzOiBib29sZWFuO1xuXHRyZWFkb25seSBkb3VibGVDbGlja1RvU3dpdGNoVG9FZGl0b3I6IGJvb2xlYW47XG5cdHJlYWRvbmx5IHdlYnZpZXdSZXNvdXJjZVJvb3Q6IHN0cmluZztcbn1cblxubGV0IGNhY2hlZFNldHRpbmdzOiBQcmV2aWV3U2V0dGluZ3MgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXREYXRhPFQgPSB7fT4oa2V5OiBzdHJpbmcpOiBUIHtcblx0Y29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2c2NvZGUtbWFya2Rvd24tcHJldmlldy1kYXRhJyk7XG5cdGlmIChlbGVtZW50KSB7XG5cdFx0Y29uc3QgZGF0YSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKGtleSk7XG5cdFx0aWYgKGRhdGEpIHtcblx0XHRcdHJldHVybiBKU09OLnBhcnNlKGRhdGEpO1xuXHRcdH1cblx0fVxuXG5cdHRocm93IG5ldyBFcnJvcihgQ291bGQgbm90IGxvYWQgZGF0YSBmb3IgJHtrZXl9YCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRTZXR0aW5ncygpOiBQcmV2aWV3U2V0dGluZ3Mge1xuXHRpZiAoY2FjaGVkU2V0dGluZ3MpIHtcblx0XHRyZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG5cdH1cblxuXHRjYWNoZWRTZXR0aW5ncyA9IGdldERhdGEoJ2RhdGEtc2V0dGluZ3MnKTtcblx0aWYgKGNhY2hlZFNldHRpbmdzKSB7XG5cdFx0cmV0dXJuIGNhY2hlZFNldHRpbmdzO1xuXHR9XG5cblx0dGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgbG9hZCBzZXR0aW5ncycpO1xufVxuIiwiLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRTdHJpbmdzKCk6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH0ge1xuXHRjb25zdCBzdG9yZSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2c2NvZGUtbWFya2Rvd24tcHJldmlldy1kYXRhJyk7XG5cdGlmIChzdG9yZSkge1xuXHRcdGNvbnN0IGRhdGEgPSBzdG9yZS5nZXRBdHRyaWJ1dGUoJ2RhdGEtc3RyaW5ncycpO1xuXHRcdGlmIChkYXRhKSB7XG5cdFx0XHRyZXR1cm4gSlNPTi5wYXJzZShkYXRhKTtcblx0XHR9XG5cdH1cblx0dGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgbG9hZCBzdHJpbmdzJyk7XG59XG4iXSwic291cmNlUm9vdCI6IiJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvY3NwLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2xvYWRpbmcudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvcHJlLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL3NldHRpbmdzLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL3N0cmluZ3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0EseURBQWlELGNBQWM7QUFDL0Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsbUNBQTJCLDBCQUEwQixFQUFFO0FBQ3ZELHlDQUFpQyxlQUFlO0FBQ2hEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhEQUFzRCwrREFBK0Q7O0FBRXJIO0FBQ0E7OztBQUdBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7QUNuRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhDQUE4QyxjQUFjO0FBQzVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1RUFBdUUsMEJBQTBCO0FBQ2pHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7QUNyREE7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtFQUFrRSxzQ0FBc0M7QUFDeEc7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5REFBeUQsc0NBQXNDO0FBQy9GO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7O0FDbENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQ0FBK0MsSUFBSTtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQzVCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDLGNBQWM7QUFDNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJwcmUuanMiLCJzb3VyY2VzQ29udGVudCI6WyIgXHQvLyBUaGUgbW9kdWxlIGNhY2hlXG4gXHR2YXIgaW5zdGFsbGVkTW9kdWxlcyA9IHt9O1xuXG4gXHQvLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuIFx0ZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXG4gXHRcdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxuIFx0XHRpZihpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSkge1xuIFx0XHRcdHJldHVybiBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXS5leHBvcnRzO1xuIFx0XHR9XG4gXHRcdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG4gXHRcdHZhciBtb2R1bGUgPSBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSA9IHtcbiBcdFx0XHRpOiBtb2R1bGVJZCxcbiBcdFx0XHRsOiBmYWxzZSxcbiBcdFx0XHRleHBvcnRzOiB7fVxuIFx0XHR9O1xuXG4gXHRcdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuIFx0XHRtb2R1bGVzW21vZHVsZUlkXS5jYWxsKG1vZHVsZS5leHBvcnRzLCBtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuIFx0XHQvLyBGbGFnIHRoZSBtb2R1bGUgYXMgbG9hZGVkXG4gXHRcdG1vZHVsZS5sID0gdHJ1ZTtcblxuIFx0XHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuIFx0XHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG4gXHR9XG5cblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGVzIG9iamVjdCAoX193ZWJwYWNrX21vZHVsZXNfXylcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubSA9IG1vZHVsZXM7XG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlIGNhY2hlXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmMgPSBpbnN0YWxsZWRNb2R1bGVzO1xuXG4gXHQvLyBkZWZpbmUgZ2V0dGVyIGZ1bmN0aW9uIGZvciBoYXJtb255IGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uZCA9IGZ1bmN0aW9uKGV4cG9ydHMsIG5hbWUsIGdldHRlcikge1xuIFx0XHRpZighX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIG5hbWUpKSB7XG4gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIG5hbWUsIHtcbiBcdFx0XHRcdGNvbmZpZ3VyYWJsZTogZmFsc2UsXG4gXHRcdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuIFx0XHRcdFx0Z2V0OiBnZXR0ZXJcbiBcdFx0XHR9KTtcbiBcdFx0fVxuIFx0fTtcblxuIFx0Ly8gZGVmaW5lIF9fZXNNb2R1bGUgb24gZXhwb3J0c1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5yID0gZnVuY3Rpb24oZXhwb3J0cykge1xuIFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgJ19fZXNNb2R1bGUnLCB7IHZhbHVlOiB0cnVlIH0pO1xuIFx0fTtcblxuIFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubiA9IGZ1bmN0aW9uKG1vZHVsZSkge1xuIFx0XHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cbiBcdFx0XHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuIFx0XHRcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18uZChnZXR0ZXIsICdhJywgZ2V0dGVyKTtcbiBcdFx0cmV0dXJuIGdldHRlcjtcbiBcdH07XG5cbiBcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkgeyByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpOyB9O1xuXG4gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCJcIjtcblxuXG4gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbiBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IFwiLi9wcmV2aWV3LXNyYy9wcmUudHNcIik7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3Qgc2V0dGluZ3NfMSA9IHJlcXVpcmUoXCIuL3NldHRpbmdzXCIpO1xuY29uc3Qgc3RyaW5nc18xID0gcmVxdWlyZShcIi4vc3RyaW5nc1wiKTtcbi8qKlxuICogU2hvd3MgYW4gYWxlcnQgd2hlbiB0aGVyZSBpcyBhIGNvbnRlbnQgc2VjdXJpdHkgcG9saWN5IHZpb2xhdGlvbi5cbiAqL1xuY2xhc3MgQ3NwQWxlcnRlciB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHRoaXMuZGlkU2hvdyA9IGZhbHNlO1xuICAgICAgICB0aGlzLmRpZEhhdmVDc3BXYXJuaW5nID0gZmFsc2U7XG4gICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3NlY3VyaXR5cG9saWN5dmlvbGF0aW9uJywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5vbkNzcFdhcm5pbmcoKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICBpZiAoZXZlbnQgJiYgZXZlbnQuZGF0YSAmJiBldmVudC5kYXRhLm5hbWUgPT09ICd2c2NvZGUtZGlkLWJsb2NrLXN2ZycpIHtcbiAgICAgICAgICAgICAgICB0aGlzLm9uQ3NwV2FybmluZygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgc2V0UG9zdGVyKHBvc3Rlcikge1xuICAgICAgICB0aGlzLm1lc3NhZ2luZyA9IHBvc3RlcjtcbiAgICAgICAgaWYgKHRoaXMuZGlkSGF2ZUNzcFdhcm5pbmcpIHtcbiAgICAgICAgICAgIHRoaXMuc2hvd0NzcFdhcm5pbmcoKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBvbkNzcFdhcm5pbmcoKSB7XG4gICAgICAgIHRoaXMuZGlkSGF2ZUNzcFdhcm5pbmcgPSB0cnVlO1xuICAgICAgICB0aGlzLnNob3dDc3BXYXJuaW5nKCk7XG4gICAgfVxuICAgIHNob3dDc3BXYXJuaW5nKCkge1xuICAgICAgICBjb25zdCBzdHJpbmdzID0gc3RyaW5nc18xLmdldFN0cmluZ3MoKTtcbiAgICAgICAgY29uc3Qgc2V0dGluZ3MgPSBzZXR0aW5nc18xLmdldFNldHRpbmdzKCk7XG4gICAgICAgIGlmICh0aGlzLmRpZFNob3cgfHwgc2V0dGluZ3MuZGlzYWJsZVNlY3VyaXR5V2FybmluZ3MgfHwgIXRoaXMubWVzc2FnaW5nKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kaWRTaG93ID0gdHJ1ZTtcbiAgICAgICAgY29uc3Qgbm90aWZpY2F0aW9uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO1xuICAgICAgICBub3RpZmljYXRpb24uaW5uZXJUZXh0ID0gc3RyaW5ncy5jc3BBbGVydE1lc3NhZ2VUZXh0O1xuICAgICAgICBub3RpZmljYXRpb24uc2V0QXR0cmlidXRlKCdpZCcsICdjb2RlLWNzcC13YXJuaW5nJyk7XG4gICAgICAgIG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ3RpdGxlJywgc3RyaW5ncy5jc3BBbGVydE1lc3NhZ2VUaXRsZSk7XG4gICAgICAgIG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ3JvbGUnLCAnYnV0dG9uJyk7XG4gICAgICAgIG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ2FyaWEtbGFiZWwnLCBzdHJpbmdzLmNzcEFsZXJ0TWVzc2FnZUxhYmVsKTtcbiAgICAgICAgbm90aWZpY2F0aW9uLm9uY2xpY2sgPSAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2luZy5wb3N0TWVzc2FnZSgnc2hvd1ByZXZpZXdTZWN1cml0eVNlbGVjdG9yJywgeyBzb3VyY2U6IHNldHRpbmdzLnNvdXJjZSB9KTtcbiAgICAgICAgfTtcbiAgICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChub3RpZmljYXRpb24pO1xuICAgIH1cbn1cbmV4cG9ydHMuQ3NwQWxlcnRlciA9IENzcEFsZXJ0ZXI7XG4iLCJcInVzZSBzdHJpY3RcIjtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmNsYXNzIFN0eWxlTG9hZGluZ01vbml0b3Ige1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLnVubG9hZGVkU3R5bGVzID0gW107XG4gICAgICAgIHRoaXMuZmluaXNoZWRMb2FkaW5nID0gZmFsc2U7XG4gICAgICAgIGNvbnN0IG9uU3R5bGVMb2FkRXJyb3IgPSAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHNvdXJjZSA9IGV2ZW50LnRhcmdldC5kYXRhc2V0LnNvdXJjZTtcbiAgICAgICAgICAgIHRoaXMudW5sb2FkZWRTdHlsZXMucHVzaChzb3VyY2UpO1xuICAgICAgICB9O1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignRE9NQ29udGVudExvYWRlZCcsICgpID0+IHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgbGluayBvZiBkb2N1bWVudC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKCdjb2RlLXVzZXItc3R5bGUnKSkge1xuICAgICAgICAgICAgICAgIGlmIChsaW5rLmRhdGFzZXQuc291cmNlKSB7XG4gICAgICAgICAgICAgICAgICAgIGxpbmsub25lcnJvciA9IG9uU3R5bGVMb2FkRXJyb3I7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCAoKSA9PiB7XG4gICAgICAgICAgICBpZiAoIXRoaXMudW5sb2FkZWRTdHlsZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5maW5pc2hlZExvYWRpbmcgPSB0cnVlO1xuICAgICAgICAgICAgaWYgKHRoaXMucG9zdGVyKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5wb3N0ZXIucG9zdE1lc3NhZ2UoJ3ByZXZpZXdTdHlsZUxvYWRFcnJvcicsIHsgdW5sb2FkZWRTdHlsZXM6IHRoaXMudW5sb2FkZWRTdHlsZXMgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBzZXRQb3N0ZXIocG9zdGVyKSB7XG4gICAgICAgIHRoaXMucG9zdGVyID0gcG9zdGVyO1xuICAgICAgICBpZiAodGhpcy5maW5pc2hlZExvYWRpbmcpIHtcbiAgICAgICAgICAgIHBvc3Rlci5wb3N0TWVzc2FnZSgncHJldmlld1N0eWxlTG9hZEVycm9yJywgeyB1bmxvYWRlZFN0eWxlczogdGhpcy51bmxvYWRlZFN0eWxlcyB9KTtcbiAgICAgICAgfVxuICAgIH1cbn1cbmV4cG9ydHMuU3R5bGVMb2FkaW5nTW9uaXRvciA9IFN0eWxlTG9hZGluZ01vbml0b3I7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3QgY3NwXzEgPSByZXF1aXJlKFwiLi9jc3BcIik7XG5jb25zdCBsb2FkaW5nXzEgPSByZXF1aXJlKFwiLi9sb2FkaW5nXCIpO1xud2luZG93LmNzcEFsZXJ0ZXIgPSBuZXcgY3NwXzEuQ3NwQWxlcnRlcigpO1xud2luZG93LnN0eWxlTG9hZGluZ01vbml0b3IgPSBuZXcgbG9hZGluZ18xLlN0eWxlTG9hZGluZ01vbml0b3IoKTtcbiIsIlwidXNlIHN0cmljdFwiO1xuLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5sZXQgY2FjaGVkU2V0dGluZ3MgPSB1bmRlZmluZWQ7XG5mdW5jdGlvbiBnZXREYXRhKGtleSkge1xuICAgIGNvbnN0IGVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndnNjb2RlLW1hcmtkb3duLXByZXZpZXctZGF0YScpO1xuICAgIGlmIChlbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBlbGVtZW50LmdldEF0dHJpYnV0ZShrZXkpO1xuICAgICAgICBpZiAoZGF0YSkge1xuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGF0YSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKGBDb3VsZCBub3QgbG9hZCBkYXRhIGZvciAke2tleX1gKTtcbn1cbmV4cG9ydHMuZ2V0RGF0YSA9IGdldERhdGE7XG5mdW5jdGlvbiBnZXRTZXR0aW5ncygpIHtcbiAgICBpZiAoY2FjaGVkU2V0dGluZ3MpIHtcbiAgICAgICAgcmV0dXJuIGNhY2hlZFNldHRpbmdzO1xuICAgIH1cbiAgICBjYWNoZWRTZXR0aW5ncyA9IGdldERhdGEoJ2RhdGEtc2V0dGluZ3MnKTtcbiAgICBpZiAoY2FjaGVkU2V0dGluZ3MpIHtcbiAgICAgICAgcmV0dXJuIGNhY2hlZFNldHRpbmdzO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBsb2FkIHNldHRpbmdzJyk7XG59XG5leHBvcnRzLmdldFNldHRpbmdzID0gZ2V0U2V0dGluZ3M7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZnVuY3Rpb24gZ2V0U3RyaW5ncygpIHtcbiAgICBjb25zdCBzdG9yZSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2c2NvZGUtbWFya2Rvd24tcHJldmlldy1kYXRhJyk7XG4gICAgaWYgKHN0b3JlKSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBzdG9yZS5nZXRBdHRyaWJ1dGUoJ2RhdGEtc3RyaW5ncycpO1xuICAgICAgICBpZiAoZGF0YSkge1xuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGF0YSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgbG9hZCBzdHJpbmdzJyk7XG59XG5leHBvcnRzLmdldFN0cmluZ3MgPSBnZXRTdHJpbmdzO1xuIl0sInNvdXJjZVJvb3QiOiIifQ== \ No newline at end of file diff --git a/extensions/markdown-language-features/preview-src/tsconfig.json b/extensions/markdown-language-features/preview-src/tsconfig.json index 8a1e8a03fb8..85159a000d9 100644 --- a/extensions/markdown-language-features/preview-src/tsconfig.json +++ b/extensions/markdown-language-features/preview-src/tsconfig.json @@ -1,13 +1,7 @@ { + "extends": "../../shared.tsconfig.json", "compilerOptions": { "outDir": "./dist/", - "module": "commonjs", - "target": "es6", - "jsx": "react", - "sourceMap": true, - "strict": true, - "strictBindCallApply": true, - "noImplicitAny": true, - "noUnusedLocals": true + "jsx": "react" } -} \ No newline at end of file +} diff --git a/extensions/package.json b/extensions/package.json index ed5fcecf4cb..cbdafd7231d 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "3.6.2" + "typescript": "3.6.3-insiders.20190909" }, "scripts": { "postinstall": "node ./postinstall" diff --git a/extensions/typescript-basics/test/colorize-fixtures/tsconfig.json b/extensions/typescript-basics/test/colorize-fixtures/tsconfig_off.json similarity index 100% rename from extensions/typescript-basics/test/colorize-fixtures/tsconfig.json rename to extensions/typescript-basics/test/colorize-fixtures/tsconfig_off.json diff --git a/extensions/typescript-basics/test/colorize-results/tsconfig_json.json b/extensions/typescript-basics/test/colorize-results/tsconfig_off_json.json similarity index 54% rename from extensions/typescript-basics/test/colorize-results/tsconfig_json.json rename to extensions/typescript-basics/test/colorize-results/tsconfig_off_json.json index 69ce07f643d..13700965aba 100644 --- a/extensions/typescript-basics/test/colorize-results/tsconfig_json.json +++ b/extensions/typescript-basics/test/colorize-results/tsconfig_off_json.json @@ -1,7 +1,7 @@ [ { "c": "{", - "t": "source.json.comments meta.structure.dictionary.json.comments punctuation.definition.dictionary.begin.json.comments", + "t": "source.json meta.structure.dictionary.json punctuation.definition.dictionary.begin.json", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -12,7 +12,7 @@ }, { "c": "\t", - "t": "source.json.comments meta.structure.dictionary.json.comments", + "t": "source.json meta.structure.dictionary.json", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -23,7 +23,7 @@ }, { "c": "\"", - "t": "source.json.comments meta.structure.dictionary.json.comments string.json.comments support.type.property-name.json.comments punctuation.support.type.property-name.begin.json.comments", + "t": "source.json meta.structure.dictionary.json string.json support.type.property-name.json punctuation.support.type.property-name.begin.json", "r": { "dark_plus": "support.type.property-name: #9CDCFE", "light_plus": "support.type.property-name.json: #0451A5", @@ -34,7 +34,7 @@ }, { "c": "compilerOptions", - "t": "source.json.comments meta.structure.dictionary.json.comments string.json.comments support.type.property-name.json.comments", + "t": "source.json meta.structure.dictionary.json string.json support.type.property-name.json", "r": { "dark_plus": "support.type.property-name: #9CDCFE", "light_plus": "support.type.property-name.json: #0451A5", @@ -45,7 +45,7 @@ }, { "c": "\"", - "t": "source.json.comments meta.structure.dictionary.json.comments string.json.comments support.type.property-name.json.comments punctuation.support.type.property-name.end.json.comments", + "t": "source.json meta.structure.dictionary.json string.json support.type.property-name.json punctuation.support.type.property-name.end.json", "r": { "dark_plus": "support.type.property-name: #9CDCFE", "light_plus": "support.type.property-name.json: #0451A5", @@ -56,7 +56,7 @@ }, { "c": ":", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments punctuation.separator.dictionary.key-value.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json punctuation.separator.dictionary.key-value.json", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -67,7 +67,7 @@ }, { "c": " ", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -78,7 +78,7 @@ }, { "c": "{", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments meta.structure.dictionary.json.comments punctuation.definition.dictionary.begin.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json punctuation.definition.dictionary.begin.json", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -89,7 +89,7 @@ }, { "c": "\t\t", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments meta.structure.dictionary.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -100,7 +100,7 @@ }, { "c": "\"", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments meta.structure.dictionary.json.comments string.json.comments support.type.property-name.json.comments punctuation.support.type.property-name.begin.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json string.json support.type.property-name.json punctuation.support.type.property-name.begin.json", "r": { "dark_plus": "support.type.property-name: #9CDCFE", "light_plus": "support.type.property-name.json: #0451A5", @@ -111,7 +111,7 @@ }, { "c": "target", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments meta.structure.dictionary.json.comments string.json.comments support.type.property-name.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json string.json support.type.property-name.json", "r": { "dark_plus": "support.type.property-name: #9CDCFE", "light_plus": "support.type.property-name.json: #0451A5", @@ -122,7 +122,7 @@ }, { "c": "\"", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments meta.structure.dictionary.json.comments string.json.comments support.type.property-name.json.comments punctuation.support.type.property-name.end.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json string.json support.type.property-name.json punctuation.support.type.property-name.end.json", "r": { "dark_plus": "support.type.property-name: #9CDCFE", "light_plus": "support.type.property-name.json: #0451A5", @@ -133,7 +133,7 @@ }, { "c": ":", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments punctuation.separator.dictionary.key-value.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json punctuation.separator.dictionary.key-value.json", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -144,7 +144,7 @@ }, { "c": " ", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -155,7 +155,7 @@ }, { "c": "\"", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments string.quoted.double.json.comments punctuation.definition.string.begin.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json punctuation.definition.string.begin.json", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -166,7 +166,7 @@ }, { "c": "es6", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments string.quoted.double.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -177,7 +177,7 @@ }, { "c": "\"", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments string.quoted.double.json.comments punctuation.definition.string.end.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json punctuation.definition.string.end.json", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -188,7 +188,7 @@ }, { "c": "\t", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -199,7 +199,7 @@ }, { "c": "}", - "t": "source.json.comments meta.structure.dictionary.json.comments meta.structure.dictionary.value.json.comments meta.structure.dictionary.json.comments punctuation.definition.dictionary.end.json.comments", + "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json punctuation.definition.dictionary.end.json", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -210,7 +210,7 @@ }, { "c": "}", - "t": "source.json.comments meta.structure.dictionary.json.comments punctuation.definition.dictionary.end.json.comments", + "t": "source.json meta.structure.dictionary.json punctuation.definition.dictionary.end.json", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", diff --git a/extensions/yarn.lock b/extensions/yarn.lock index 5368726a68d..f6ffdca517a 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -typescript@3.6.2: - version "3.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.2.tgz#105b0f1934119dde543ac8eb71af3a91009efe54" - integrity sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw== +typescript@3.6.3-insiders.20190909: + version "3.6.3-insiders.20190909" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.3-insiders.20190909.tgz#65b6b2d809288311a970819849e1964ac73e1fda" + integrity sha512-Lr7ONd8Y05EhrI+zKoI5tgvO5dhuRDrK5pyOLG33DeMln8zb8w7Yc8AoIEyqvxB5Btj9F7zBmXBXJdTI3SuX0Q== diff --git a/package.json b/package.json index 1e1daccda9a..965864e8adc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.39.0", - "distro": "f9c6a279531bde40e55acc8a4a6d5d526f90333f", + "distro": "11a8f56d5044ab27417b2d81f5d8f65c5d55f48c", "author": { "name": "Microsoft Corporation" }, @@ -49,10 +49,10 @@ "vscode-chokidar": "2.1.7", "vscode-minimist": "^1.2.1", "vscode-proxy-agent": "0.4.0", - "vscode-ripgrep": "^1.5.6", + "vscode-ripgrep": "^1.5.7", "vscode-sqlite3": "4.0.8", "vscode-textmate": "^4.2.2", - "xterm": "3.15.0-beta101", + "xterm": "3.15.0-beta108", "xterm-addon-search": "0.2.0-beta5", "xterm-addon-web-links": "0.1.0-beta10", "yauzl": "^2.9.2", @@ -97,7 +97,7 @@ "gulp-rename": "^1.2.0", "gulp-replace": "^0.5.4", "gulp-shell": "^0.6.5", - "gulp-tsb": "4.0.0", + "gulp-tsb": "4.0.2", "gulp-tslint": "^8.1.3", "gulp-untar": "^0.0.7", "gulp-vinyl-zip": "^2.1.2", diff --git a/remote/package.json b/remote/package.json index bb43760e610..b1e9ba10c32 100644 --- a/remote/package.json +++ b/remote/package.json @@ -19,9 +19,9 @@ "vscode-chokidar": "2.1.7", "vscode-minimist": "^1.2.1", "vscode-proxy-agent": "0.4.0", - "vscode-ripgrep": "^1.5.6", + "vscode-ripgrep": "^1.5.7", "vscode-textmate": "^4.2.2", - "xterm": "3.15.0-beta101", + "xterm": "3.15.0-beta108", "xterm-addon-search": "0.2.0-beta5", "xterm-addon-web-links": "0.1.0-beta10", "yauzl": "^2.9.2", diff --git a/remote/web/package.json b/remote/web/package.json index 675b6f9c5a3..e3f57bab9a9 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -6,7 +6,7 @@ "onigasm-umd": "^2.2.2", "semver-umd": "^5.5.3", "vscode-textmate": "^4.2.2", - "xterm": "3.15.0-beta101", + "xterm": "3.15.0-beta108", "xterm-addon-search": "0.2.0-beta5", "xterm-addon-web-links": "0.1.0-beta10" } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index c8ee2cb5da7..82a415dc249 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -109,7 +109,7 @@ xterm-addon-web-links@0.1.0-beta10: resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== -xterm@3.15.0-beta101: - version "3.15.0-beta101" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta101.tgz#38ffa0df5a3e9bdcb1818e74fe59b2f98b0fff69" - integrity sha512-HRa7+FDqQ8iWBTvb1Ni+uMGILnu6k9mF7JHMHRHfWxFoQlSoGYCyfdyXlJjk68YN8GsEQREmrII6cPLiQizdEQ== +xterm@3.15.0-beta108: + version "3.15.0-beta108" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta108.tgz#d113f6d1e4d4b7645ab3ff002c81a4dba8a78a28" + integrity sha512-btZXgI9BeawFzitw3EZvFPsH3kfBgJS55LOdz9DjEany3y9FfvmnVhq7wn4x1PmTU/djHobGGhMNemxptk+ryg== diff --git a/remote/yarn.lock b/remote/yarn.lock index 2919e2342b2..20accc7c140 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -1139,10 +1139,10 @@ vscode-proxy-agent@0.4.0: https-proxy-agent "2.2.1" socks-proxy-agent "4.0.1" -vscode-ripgrep@^1.5.6: - version "1.5.6" - resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.6.tgz#93bf5c99ca5f8248950a305e224f6ca153c30af4" - integrity sha512-WRIM9XpUj6dsfdAmuI3ANbmT1ysPUVsYy/2uCLDHJa9kbiB4T7uGvFnnc0Rgx2qQnyRAwL7PeWaFgUljPPxf2g== +vscode-ripgrep@^1.5.7: + version "1.5.7" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.7.tgz#acb6b548af488a4bca5d0f1bb5faf761343289ce" + integrity sha512-/Vsz/+k8kTvui0q3O74pif9FK0nKopgFTiGNVvxicZANxtSA8J8gUE9GQ/4dpi7D/2yI/YVORszwVskFbz46hQ== vscode-textmate@^4.2.2: version "4.2.2" @@ -1173,10 +1173,10 @@ xterm-addon-web-links@0.1.0-beta10: resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== -xterm@3.15.0-beta101: - version "3.15.0-beta101" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta101.tgz#38ffa0df5a3e9bdcb1818e74fe59b2f98b0fff69" - integrity sha512-HRa7+FDqQ8iWBTvb1Ni+uMGILnu6k9mF7JHMHRHfWxFoQlSoGYCyfdyXlJjk68YN8GsEQREmrII6cPLiQizdEQ== +xterm@3.15.0-beta108: + version "3.15.0-beta108" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta108.tgz#d113f6d1e4d4b7645ab3ff002c81a4dba8a78a28" + integrity sha512-btZXgI9BeawFzitw3EZvFPsH3kfBgJS55LOdz9DjEany3y9FfvmnVhq7wn4x1PmTU/djHobGGhMNemxptk+ryg== yauzl@^2.9.2: version "2.10.0" diff --git a/resources/linux/bin/code.sh b/resources/linux/bin/code.sh index 64109f1fa12..564f13ef95c 100755 --- a/resources/linux/bin/code.sh +++ b/resources/linux/bin/code.sh @@ -4,7 +4,7 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # test that VSCode wasn't installed inside WSL -if grep -qi Microsoft /proc/version; then +if grep -qi Microsoft /proc/version && [ -z "$DONT_PROMPT_WSL_INSTALL" ]; then echo "To use VS Code with the Windows Subsystem for Linux, please install VS Code in Windows and uninstall the Linux version in WSL. You can then use the '@@PRODNAME@@' command in a WSL terminal just as you would in a normal command prompt." 1>&2 read -e -p "Do you want to continue anyways ? [y/N] " YN diff --git a/resources/linux/code-url-handler.desktop b/resources/linux/code-url-handler.desktop index 09e39c57c51..7106e0e0969 100644 --- a/resources/linux/code-url-handler.desktop +++ b/resources/linux/code-url-handler.desktop @@ -2,7 +2,7 @@ Name=@@NAME_LONG@@ - URL Handler Comment=Code Editing. Redefined. GenericName=Text Editor -Exec=/usr/share/@@NAME@@/@@NAME@@ --open-url %U +Exec=@@EXEC@@ --open-url %U Icon=@@ICON@@ Type=Application NoDisplay=true diff --git a/resources/linux/code.desktop b/resources/linux/code.desktop index dbc7818cecf..1273bb2db7c 100644 --- a/resources/linux/code.desktop +++ b/resources/linux/code.desktop @@ -2,7 +2,7 @@ Name=@@NAME_LONG@@ Comment=Code Editing. Redefined. GenericName=Text Editor -Exec=/usr/share/@@NAME@@/@@NAME@@ --unity-launch %F +Exec=@@EXEC@@ --unity-launch %F Icon=@@ICON@@ Type=Application StartupNotify=false @@ -14,5 +14,5 @@ Keywords=vscode; [Desktop Action new-empty-window] Name=New Empty Window -Exec=/usr/share/@@NAME@@/@@NAME@@ --new-window %F +Exec=@@EXEC@@ --new-window %F Icon=@@ICON@@ diff --git a/resources/linux/snap/snapcraft.yaml b/resources/linux/snap/snapcraft.yaml index 28b3e59ad7e..0f872089195 100644 --- a/resources/linux/snap/snapcraft.yaml +++ b/resources/linux/snap/snapcraft.yaml @@ -49,16 +49,14 @@ parts: apps: @@NAME@@: - command: electron-launch $SNAP/usr/share/@@NAME@@/bin/@@NAME@@ - desktop: usr/share/applications/@@NAME@@.desktop + command: electron-launch $SNAP/usr/share/@@NAME@@/@@NAME@@ common-id: @@NAME@@.desktop environment: DISABLE_WAYLAND: 1 GSETTINGS_SCHEMA_DIR: $SNAP/usr/share/glib-2.0/schemas url-handler: - command: electron-launch $SNAP/usr/share/@@NAME@@/bin/@@NAME@@ --open-url - desktop: usr/share/applications/@@NAME@@-url-handler.desktop + command: electron-launch $SNAP/usr/share/@@NAME@@/@@NAME@@ --open-url environment: DISABLE_WAYLAND: 1 - GSETTINGS_SCHEMA_DIR: $SNAP/usr/share/glib-2.0/schemas \ No newline at end of file + GSETTINGS_SCHEMA_DIR: $SNAP/usr/share/glib-2.0/schemas diff --git a/scripts/code.sh b/scripts/code.sh index a074797ce0f..e82babd818a 100755 --- a/scripts/code.sh +++ b/scripts/code.sh @@ -47,6 +47,7 @@ function code() { export VSCODE_CLI=1 export ELECTRON_ENABLE_STACK_DUMPING=1 export ELECTRON_ENABLE_LOGGING=1 + export VSCODE_LOGS= # Launch Code exec "$CODE" . "$@" diff --git a/src/typings/xterm.d.ts b/src/typings/xterm.d.ts index df7f20e233e..695f872bcd5 100644 --- a/src/typings/xterm.d.ts +++ b/src/typings/xterm.d.ts @@ -1043,39 +1043,3 @@ declare module 'xterm' { addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable; } } - - - - - -// Modifications to official .d.ts below -declare module 'xterm' { - interface TerminalCore { - _onScroll: IEventEmitter; - _onKey: IEventEmitter<{ key: string }>; - - _charSizeService: { - width: number; - height: number; - }; - - _coreService: { - triggerDataEvent(data: string, wasUserInput?: boolean): void; - } - - _renderService: { - _renderer: { - _renderLayers: any[]; - }; - _onIntersectionChange: any; - }; - } - - interface IEventEmitter { - fire(e: T): void; - } - - interface Terminal { - _core: TerminalCore; - } -} diff --git a/src/vs/base/browser/markdownRenderer.ts b/src/vs/base/browser/markdownRenderer.ts index 31d645fe271..7749f2c1f79 100644 --- a/src/vs/base/browser/markdownRenderer.ts +++ b/src/vs/base/browser/markdownRenderer.ts @@ -14,6 +14,7 @@ import { parse } from 'vs/base/common/marshalling'; import { cloneAndChange } from 'vs/base/common/objects'; import { escape } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; +import { Schemas } from 'vs/base/common/network'; export interface MarkdownRenderOptions extends FormattedTextRenderOptions { codeBlockRenderer?: (modeId: string, value: string) => Promise; @@ -172,9 +173,9 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende renderer }; - const allowedSchemes = ['http', 'https', 'mailto', 'data']; + const allowedSchemes = [Schemas.http, Schemas.https, Schemas.mailto, Schemas.data, Schemas.file, Schemas.vscodeRemote]; if (markdown.isTrusted) { - allowedSchemes.push('command'); + allowedSchemes.push(Schemas.command); } const renderedMarkdown = marked.parse(markdown.value, markedOptions); diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 87d2ffad2db..284a66f41b9 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { getOrDefault } from 'vs/base/common/objects'; -import { IDisposable, dispose, Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Gesture, EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch'; import * as DOM from 'vs/base/browser/dom'; import { Event, Emitter } from 'vs/base/common/event'; @@ -188,7 +188,7 @@ export class ListView implements ISpliceable, IDisposable { private currentDragFeedbackDisposable: IDisposable = Disposable.None; private onDragLeaveTimeout: IDisposable = Disposable.None; - private disposables: IDisposable[]; + private readonly disposables: DisposableStore = new DisposableStore(); private _onDidChangeContentHeight = new Emitter(); readonly onDidChangeContentHeight: Event = Event.latch(this._onDidChangeContentHeight.event); @@ -214,7 +214,7 @@ export class ListView implements ISpliceable, IDisposable { this.renderers.set(renderer.templateId, renderer); } - this.cache = new RowCache(this.renderers); + this.cache = this.disposables.add(new RowCache(this.renderers)); this.lastRenderTop = 0; this.lastRenderHeight = 0; @@ -238,18 +238,16 @@ export class ListView implements ISpliceable, IDisposable { this.rowsContainer.className = 'monaco-list-rows'; Gesture.addTarget(this.rowsContainer); - this.scrollableElement = new ScrollableElement(this.rowsContainer, { + this.scrollableElement = this.disposables.add(new ScrollableElement(this.rowsContainer, { alwaysConsumeMouseWheel: true, horizontal: this.horizontalScrolling ? ScrollbarVisibility.Auto : ScrollbarVisibility.Hidden, vertical: getOrDefault(options, o => o.verticalScrollMode, DefaultOptions.verticalScrollMode), useShadows: getOrDefault(options, o => o.useShadows, DefaultOptions.useShadows) - }); + })); this.domNode.appendChild(this.scrollableElement.getDomNode()); container.appendChild(this.domNode); - this.disposables = [this.scrollableElement, this.cache]; - this.scrollableElement.onScroll(this.onScroll, this, this.disposables); domEvent(this.rowsContainer, TouchEventType.Change)(this.onTouchChange, this, this.disposables); @@ -1178,6 +1176,6 @@ export class ListView implements ISpliceable, IDisposable { this.domNode.parentNode.removeChild(this.domNode); } - this.disposables = dispose(this.disposables); + dispose(this.disposables); } } diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css index 5a87b9095c0..d16f7a00cf7 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css @@ -1,7 +1,7 @@ @font-face { font-family: "octicons2"; - src: url("./octicons2.ttf?d8711b2fb33d14ed72f2a5859ed5f80a") format("truetype"), -url("./octicons2.svg?d8711b2fb33d14ed72f2a5859ed5f80a#octicons2") format("svg"); + src: url("./octicons2.ttf?04609cb7b40cfe676d00e166656be7e8") format("truetype"), +url("./octicons2.svg?04609cb7b40cfe676d00e166656be7e8#octicons2") format("svg"); } .octicon, .mega-octicon { diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.svg b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.svg index f84fb747a0a..e25c9f56e82 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.svg +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.svg @@ -375,7 +375,7 @@ horiz-adv-x="1000" d=" M866.4625 465.46625C873.56875 482.96625 896.5375 552.419375 859.3499999999999 646.481875C859.3499999999999 646.481875 801.93125 664.52875 671.2249999999999 575.388125C616.5374999999999 590.700625 558.021875 592.888125 500.053125 592.888125C442.084375 592.888125 383.56875 590.700625 328.88125 575.388125C198.178125 665.075625 140.75625 646.481875 140.75625 646.481875C103.56875 552.419375 126.5375 482.96625 133.646875 465.46625C89.35 417.888125 62.553125 356.638125 62.553125 282.263125C62.553125 0.625 244.6625 -62.8125 498.959375 -62.8125C753.2562499999999 -62.8125 937.55625 0.625 937.55625 282.263125C937.55625 356.638125 910.75625 417.888125 866.4625 465.46625zM500.053125 -9.21875C319.584375 -9.21875 173.021875 -1.0187500000001 173.021875 173.9812500000001C173.021875 215.544375 193.803125 254.919375 228.803125 287.185C287.31875 340.77875 387.396875 312.34125 500.053125 312.34125C613.2562499999999 312.34125 712.24375 340.77875 771.30625 287.185C806.8499999999999 254.919375 827.0875 216.0912500000001 827.0875 173.9812500000001C827.0875 -0.46875 680.5250000000001 -9.21875 500.053125 -9.21875zM362.7875 264.7631250000001C326.69375 264.7631250000001 297.1625 221.013125 297.1625 167.4187500000001C297.1625 113.8250000000001 326.69375 69.53125 362.7875 69.53125C398.88125 69.53125 428.4125 113.28125 428.4125 167.4187500000001C428.4125 221.5600000000001 398.88125 264.7631250000001 362.7875 264.7631250000001zM637.31875 264.7631250000001C601.225625 264.7631250000001 571.6943749999999 221.5600000000001 571.6943749999999 167.4187500000001C571.6943749999999 113.28125 601.225625 69.53125 637.31875 69.53125C673.4125 69.53125 702.94375 113.28125 702.94375 167.4187500000001C702.94375 221.5600000000001 673.9625 264.7631250000001 637.31875 264.7631250000001z" /> + horiz-adv-x="1000" d=" M569.446875 528.565625C548.890625 514.8299999999999 524.7225 507.500625 500 507.500625C466.848125 507.500625 435.055625 520.671875 411.61375 544.114375C388.1712500000001 567.55625 375 599.34875 375 632.500625C375 657.223125 382.3293750000001 681.3875 396.065 701.943125C409.8 722.499375 429.323125 738.525625 452.16375 747.986875C475.004375 757.4475 500.14 759.9205625 524.3875 755.0975C548.635 750.274375 570.905 738.36875 588.38625 720.8875C605.868125 703.405625 617.7737500000001 681.131875 622.5968750000001 656.884375C627.41875 632.636875 624.946875 607.505 615.48625 584.6643750000001C606.0250000000001 561.82375 590.0024999999999 542.300625 569.446875 528.565625zM534.72125 684.464375C524.443125 691.331875 512.36125 695.000625 500 695.000625C483.42375 695.000625 467.5275 688.41875 455.806875 676.6975C444.085625 664.976875 437.5 649.076875 437.5 632.500625C437.5 620.139375 441.165 608.0575 448.0325000000001 597.779375C454.9 587.50125 464.6612500000001 579.491875 476.081875 574.76125C487.5025 570.03125 500.068125 568.786875 512.191875 571.19875C524.315625 573.61 535.4525 579.563125 544.193125 588.30375C552.93375 597.044375 558.886875 608.185 561.298125 620.30875C563.71 632.4325 562.47375 644.99875 557.743125 656.41875C553.0125 667.839375 544.999375 677.596875 534.72125 684.464375zM697.9125 682.52C713.33125 692.880625 731.4562500000001 698.410625 750 698.410625C774.8625 698.410625 798.7125000000001 688.4762499999999 816.29375 670.79375C833.875 653.1112499999999 843.75 629.12875 843.75 604.12125C843.75 585.473125 838.25 567.243125 827.9499999999999 551.7375C817.65 536.231875 803.00625 524.14625 785.875 517.01C768.74375 509.87375 749.8937500000001 508.00625 731.7125 511.644375C713.525 515.2825 696.81875 524.2625 683.70625 537.4493749999999C670.6 550.635625 661.66875 567.43625 658.0500000000001 585.7268750000001C654.43125 604.016875 656.29375 622.975 663.3875 640.204375C670.48125 657.433125 682.5 672.159375 697.9125 682.52zM727.9 581.8975C733.7624999999999 576.003125 741.7125 572.691875 750 572.691875C758.2875 572.691875 766.2375000000001 576.003125 772.1 581.8975C777.9562500000001 587.791875 781.25 595.785625 781.25 604.12125C781.0875000000001 612.406875 777.74375 620.308125 771.9187499999999 626.1675C766.09375 632.0275 758.2375 635.39 750 635.55125C741.7125 635.55125 733.7624999999999 632.24 727.9 626.345625C722.0437499999999 620.4512500000001 718.75 612.4575 718.75 604.12125C718.75 595.785625 722.0437499999999 587.791875 727.9 581.8975zM199.37625 39.6437500000001H312.5012500000001V-23.2125H199.37625C179.59375 -23.05 160.676875 -15.025 146.746875 -0.9C132.81625 13.2312499999999 125.000625 32.31875 125.00125 52.21875V165.3625000000001C116.5975 165.6437500000001 108.33625 167.625 100.71125 171.1875C93.08625 174.75 86.255 179.8249999999999 80.62625 186.1062499999999C74.681875 192.13125 70.01125 199.300625 66.89625 207.186875C63.78125 215.073125 62.2863125 223.5118749999999 62.50125 231.995V368.399375C62.68875 397.86 74.3575 426.07125 95.00125 446.97375C115.55375 467.698125 143.39875 479.441875 172.50125 479.660625H287.50125C272.0025 461.21375 260.3162500000001 439.84375 253.12625 416.80125H172.50125C159.83625 416.45625 147.77375 411.289375 138.75125 402.34375C129.920625 393.279375 124.983125 381.089375 125.00125 368.399375V228.8525H187.50125V52.21875C187.3575 50.5125 187.560625 48.8 188.098125 47.18125C188.635 45.55625 189.495625 44.0625 190.62625 42.7875C193.13875 40.8375 196.2025 39.7375000000001 199.37625 39.6437500000001zM655.625 446.97375C634.9187499999999 467.85125 606.820625 479.6075 577.500625 479.660625H422.500625C393.398125 479.441875 365.553125 467.698125 345.000625 446.97375C324.3575 426.07125 312.6887500000001 397.86 312.500625 368.399375V169.7624999999999C312.4125 152.6875 318.90875 136.2375 330.625625 123.875C336.2550000000001 117.59375 343.08625 112.5187500000001 350.71125 108.9562500000001C358.335625 105.39375 366.5975000000001 103.4124999999999 375.000625 103.1312499999999V-42.06875C374.9425 -51.99375 376.84625 -61.8249999999999 380.601875 -70.99375C384.356875 -80.1687499999999 389.889375 -88.5 396.875625 -95.5C408.114375 -106.025 422.295 -112.8312499999999 437.500625 -114.9874999999999H562.500625C580.060625 -112.80625 596.18625 -104.1374999999999 607.73875 -90.65625C619.29125 -77.1812500000001 625.4437499999999 -59.8624999999999 625 -42.06875V103.1312499999999C633.40625 103.4124999999999 641.66875 105.39375 649.29375 108.9562500000001C656.9125 112.5187500000001 663.75 117.59375 669.375 123.875C675.31875 129.9 679.99375 137.06875 683.10625 144.95625C686.21875 152.84375 687.71875 161.28125 687.5 169.7624999999999V368.399375C687.54375 397.784375 676.1 426.008125 655.625 446.97375zM625 166.61875H562.500625V-42.06875C562.45375 -45.3874999999999 561.10625 -48.5500000000001 558.7506249999999 -50.86875C557.684375 -52.14375 556.338125 -53.14375 554.819375 -53.8000000000001C553.300625 -54.4499999999999 551.650625 -54.7437500000001 550.000625 -54.6437500000001H449.375625C446.11 -54.4875 443.018125 -53.1187500000001 440.705625 -50.79375C438.39375 -48.4625 437.028125 -45.35625 436.875625 -42.06875V166.61875H375.000625V368.399375C374.9825 381.089375 379.9206250000001 393.279375 388.750625 402.34375C397.773125 411.289375 409.83625 416.45625 422.500625 416.80125H577.500625C590.193125 416.585 602.30125 411.398125 611.250625 402.34375C615.70875 397.916875 619.226875 392.6262500000001 621.59 386.7912500000001C623.95375 380.95625 625.1125 374.699375 625 368.399375V166.61875zM800.625 -23.2125H687.5V39.6437500000001H800C803.175 39.7375000000001 806.2375000000001 40.8375 808.75 42.7875C809.99375 44.0124999999999 810.96875 45.4812499999999 811.6125 47.1062499999999C812.2625 48.73125 812.5625 50.46875 812.5 52.21875V228.8525H875V368.399375C875.01875 381.089375 870.0812500000001 393.279375 861.25 402.34375C852.225 411.289375 840.1625 416.45625 827.5 416.80125H746.875C739.6875 439.84375 728 461.21375 712.5 479.660625H827.5C856.6 479.441875 884.4499999999999 467.698125 905 446.97375C925.64375 426.07125 937.3125 397.86 937.5 368.399375V231.995C937.525 214.958125 931.0625 198.5575 919.4375 186.1624999999999C907.8125 173.775 891.9125 166.33125 875 165.3625000000001V52.21875C875 32.31875 867.1875 13.2312499999999 853.25625 -0.9C839.3249999999999 -15.025 820.40625 -23.05 800.625 -23.2125zM250 698.410625C231.458125 698.410625 213.3325 692.880625 197.915625 682.52C182.498125 672.159375 170.481875 657.433125 163.38625 640.204375C156.290625 622.975 154.43375 604.016875 158.05125 585.7268750000001C161.66875 567.43625 170.5975 550.635625 183.70875 537.4493749999999C196.82 524.2625 213.524375 515.2825 231.710625 511.644375C249.89625 508.00625 268.7462500000001 509.87375 285.876875 517.01C303.0068750000001 524.14625 317.64875 536.231875 327.9500000000001 551.7375C338.251875 567.243125 343.75 585.473125 343.75 604.12125C343.75 629.12875 333.873125 653.1112499999999 316.2912500000001 670.79375C298.71 688.4762499999999 274.864375 698.410625 250 698.410625zM250 572.691875C241.711875 572.691875 233.76375 576.003125 227.903125 581.8975C222.0425 587.791875 218.75 595.785625 218.75 604.12125C218.75 612.4575 222.0425 620.4512500000001 227.903125 626.345625C233.76375 632.24 241.711875 635.55125 250 635.55125C258.238125 635.39 266.09375 632.0275 271.92 626.1675C277.74625 620.308125 281.0900000000001 612.406875 281.25 604.12125C281.25 595.785625 277.9575000000001 587.791875 272.096875 581.8975C266.236875 576.003125 258.288125 572.691875 250 572.691875z" /> @@ -498,7 +498,7 @@ horiz-adv-x="1000" d=" M256.938125 683.769375C328.885 731.8425 413.4700000000001 757.5 499.999375 757.5C616.031875 757.5 727.3125 711.40375 809.3625 629.356875C891.40625 547.309375 937.5 436.0325 937.5 320C937.5 233.470625 911.84375 148.88125 863.76875 76.9375C815.69375 4.9875 747.3625000000001 -51.0812500000001 667.4250000000001 -84.2C587.48 -117.3125 499.5125 -125.975 414.645625 -109.09375C329.77875 -92.2125 251.824375 -50.5437499999999 190.63875 10.64375C129.45375 71.83125 87.788125 149.78125 70.906875 234.65C54.026 319.516875 62.688125 407.484375 95.801875 487.426875C128.915 567.37 184.991875 635.69625 256.938125 683.769375zM291.66 8.2C353.328125 -33.0062499999999 425.83125 -55 499.999375 -55C599.455625 -55 694.8375 -15.4937500000001 765.1625 54.8312500000001C835.4875000000001 125.15625 875 220.5437499999999 875 320C875 394.168125 853.0062499999999 466.6675 811.8 528.335625C770.59375 590.004375 712.025 638.075625 643.5062499999999 666.458125C574.9825 694.84125 499.58375 702.2675 426.84125 687.798125C354.098125 673.328125 287.280625 637.611875 234.83625 585.1675C182.39125 532.7225 146.675 465.90125 132.205625 393.1581250000001C117.73625 320.415625 125.161875 245.013125 153.545 176.4937500000001C181.9275 107.96875 229.99125 49.40625 291.66 8.2zM508.1250000000001 353.125L660.625 507.5L704.375 463.125L551.875 308.75L704.375 153.75L660.625 110L508.1250000000001 264.375L356.25 110L312.5 153.75L465 308.75L312.5 463.125L356.25 507.5L508.1250000000001 353.125z" /> + horiz-adv-x="1000" d=" M799.53125 335.2275C797.925 381.845 785.59375 427.7825000000001 763.1125 469.338125C729.85 530.8143749999999 676.40625 578.938125 611.7875 605.5925C547.171875 632.24625 475.34 635.8 408.40875 615.653125C341.4775 595.506875 283.5425 552.893125 244.375625 495L195.625625 543.75C230.550625 590.7225 275.986875 628.8675 328.2975 655.131875C380.60875 681.395625 438.34125 695.049375 496.875625 695C535.6999999999999 694.8075 574.268125 688.6956250000001 611.250625 676.875C700.375 646.71875 774.90625 584.16125 820.0625 501.614375C848.3375 449.919375 863.79375 392.75125 865.8312500000001 334.81125L939.375 407.496875L986.25 359.996875L855.625 230.6218750000001L808.125 231.2468750000001L677.5 363.121875L725 410.6218750000001L799.53125 335.2275zM130.625 403.748125L0.00017881375 274.3731250000001L48.7501875 226.248125L119.261875 297.179375C121.631875 240.0556250000001 137.0525 183.74375 164.94125 132.7562499999999C210.093125 50.2125000000001 284.6262500000001 -12.35 373.75125 -42.5C410.13375 -54.1375 448.05625 -60.24375 486.25125 -60.625C545.3718749999999 -61.525 603.84875 -48.2625 656.8000000000001 -21.9499999999999C709.75 4.3625 755.6374999999999 42.9625 790.625 90.625L741.875 139.375C712.70625 96.125 672.875 61.13125 626.225 37.7875C579.5756250000001 14.44375 527.690625 3.53125 475.589375 6.10625C423.488125 8.68125 372.933125 24.6625 328.815 52.4937500000001C284.6968750000001 80.3312500000001 248.509375 119.08125 223.75125 165C201.011875 206.2575000000001 188.485625 252.005 186.771875 298.4675000000001L261.25 223.1231250000001L308.75 270.623125L178.125 403.123125L130.625 403.748125z" /> diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf index 60d7dfabfbf..a5cf3ce10e2 100644 Binary files a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf and b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf differ diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index d89028622d3..93b50dbcb4b 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -911,7 +911,7 @@ export class SplitView extends Disposable { position += this.viewItems[i].size; if (this.sashItems[i].sash === sash) { - return position; + return Math.min(position, this.contentSize - 2); } } diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 410368f5f49..c51308ae6c8 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -1053,13 +1053,15 @@ class TreeNodeListMouseController extends MouseController< return super.onPointer(e); } - const model = ((this.tree as any).model as ITreeModel); // internal - const location = model.getNodeLocation(node); - const recursive = e.browserEvent.altKey; - model.setCollapsed(location, undefined, recursive); + if (node.collapsible) { + const model = ((this.tree as any).model as ITreeModel); // internal + const location = model.getNodeLocation(node); + const recursive = e.browserEvent.altKey; + model.setCollapsed(location, undefined, recursive); - if (expandOnlyOnTwistieClick && onTwistie) { - return; + if (expandOnlyOnTwistieClick && onTwistie) { + return; + } } super.onPointer(e); @@ -1418,6 +1420,10 @@ export abstract class AbstractTree implements IDisposable return this.model.isCollapsible(location); } + setCollapsible(location: TRef, collapsible?: boolean): boolean { + return this.model.setCollapsible(location, collapsible); + } + isCollapsed(location: TRef): boolean { return this.model.isCollapsed(location); } diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index f9380aaf243..c20a8771c87 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -451,7 +451,7 @@ export class AsyncDataTree implements IDisposable const viewStateContext = viewState && { viewState, focus: [], selection: [] } as IAsyncDataTreeViewStateContext; - await this.updateChildren(input, true, viewStateContext); + await this._updateChildren(input, true, viewStateContext); if (viewStateContext) { this.tree.setFocus(viewStateContext.focus); @@ -463,7 +463,11 @@ export class AsyncDataTree implements IDisposable } } - async updateChildren(element: TInput | T = this.root.element, recursive = true, viewStateContext?: IAsyncDataTreeViewStateContext): Promise { + async updateChildren(element: TInput | T = this.root.element, recursive = true): Promise { + await this._updateChildren(element, recursive); + } + + private async _updateChildren(element: TInput | T = this.root.element, recursive = true, viewStateContext?: IAsyncDataTreeViewStateContext): Promise { if (typeof this.root.element === 'undefined') { throw new TreeError(this.user, 'Tree input not set'); } @@ -874,6 +878,11 @@ export class AsyncDataTree implements IDisposable private render(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): void { const children = node.children.map(c => asTreeElement(c, viewStateContext)); this.tree.setChildren(node === this.root ? null : node, children); + + if (node !== this.root) { + this.tree.setCollapsible(node, node.hasChildren); + } + this._onDidRender.fire(); } diff --git a/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts index 81cae3bcd0c..22f9ce43205 100644 --- a/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts +++ b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts @@ -231,6 +231,11 @@ export class CompressedTreeModel, TFilterData extends return this.model.isCollapsible(compressedNode); } + setCollapsible(location: T | null, collapsible?: boolean): boolean { + const compressedNode = this.getCompressedNode(location); + return this.model.setCollapsible(compressedNode, collapsible); + } + isCollapsed(location: T | null): boolean { const compressedNode = this.getCompressedNode(location); return this.model.isCollapsed(compressedNode); @@ -397,6 +402,10 @@ export class CompressedObjectTreeModel, TFilterData e return this.model.isCollapsible(location); } + setCollapsible(location: T | null, collapsed?: boolean): boolean { + return this.model.setCollapsible(location, collapsed); + } + isCollapsed(location: T | null): boolean { return this.model.isCollapsed(location); } diff --git a/src/vs/base/browser/ui/tree/indexTreeModel.ts b/src/vs/base/browser/ui/tree/indexTreeModel.ts index 022d612c0a3..511ccbbf66c 100644 --- a/src/vs/base/browser/ui/tree/indexTreeModel.ts +++ b/src/vs/base/browser/ui/tree/indexTreeModel.ts @@ -46,6 +46,21 @@ export interface IIndexTreeModelOptions { readonly autoExpandSingleChildren?: boolean; } +interface CollapsibleStateUpdate { + readonly collapsible: boolean; +} + +interface CollapsedStateUpdate { + readonly collapsed: boolean; + readonly recursive: boolean; +} + +type CollapseStateUpdate = CollapsibleStateUpdate | CollapsedStateUpdate; + +function isCollapsibleStateUpdate(update: CollapseStateUpdate): update is CollapsibleStateUpdate { + return typeof (update as any).collapsible === 'boolean'; +} + export class IndexTreeModel, TFilterData = void> implements ITreeModel { readonly rootRef = []; @@ -205,6 +220,17 @@ export class IndexTreeModel, TFilterData = voi return this.getTreeNode(location).collapsible; } + setCollapsible(location: number[], collapsible?: boolean): boolean { + const node = this.getTreeNode(location); + + if (typeof collapsible === 'undefined') { + collapsible = !node.collapsible; + } + + const update: CollapsibleStateUpdate = { collapsible }; + return this.eventBufferer.bufferEvents(() => this._setCollapseState(location, update)); + } + isCollapsed(location: number[]): boolean { return this.getTreeNode(location).collapsed; } @@ -216,15 +242,16 @@ export class IndexTreeModel, TFilterData = voi collapsed = !node.collapsed; } - return this.eventBufferer.bufferEvents(() => this._setCollapsed(location, collapsed!, recursive)); + const update: CollapsedStateUpdate = { collapsed, recursive: recursive || false }; + return this.eventBufferer.bufferEvents(() => this._setCollapseState(location, update)); } - private _setCollapsed(location: number[], collapsed: boolean, recursive?: boolean): boolean { + private _setCollapseState(location: number[], update: CollapseStateUpdate): boolean { const { node, listIndex, revealed } = this.getTreeNodeWithListIndex(location); - const result = this._setListNodeCollapsed(node, listIndex, revealed, collapsed!, recursive || false); + const result = this._setListNodeCollapseState(node, listIndex, revealed, update); - if (node !== this.root && this.autoExpandSingleChildren && !collapsed! && !recursive) { + if (node !== this.root && this.autoExpandSingleChildren && result && !isCollapsibleStateUpdate(update) && node.collapsible && !node.collapsed && !update.recursive) { let onlyVisibleChildIndex = -1; for (let i = 0; i < node.children.length; i++) { @@ -241,17 +268,17 @@ export class IndexTreeModel, TFilterData = voi } if (onlyVisibleChildIndex > -1) { - this._setCollapsed([...location, onlyVisibleChildIndex], false, false); + this._setCollapseState([...location, onlyVisibleChildIndex], update); } } return result; } - private _setListNodeCollapsed(node: IMutableTreeNode, listIndex: number, revealed: boolean, collapsed: boolean, recursive: boolean): boolean { - const result = this._setNodeCollapsed(node, collapsed, recursive, false); + private _setListNodeCollapseState(node: IMutableTreeNode, listIndex: number, revealed: boolean, update: CollapseStateUpdate): boolean { + const result = this._setNodeCollapseState(node, update, false); - if (!revealed || !node.visible) { + if (!revealed || !node.visible || !result) { return result; } @@ -263,20 +290,28 @@ export class IndexTreeModel, TFilterData = voi return result; } - private _setNodeCollapsed(node: IMutableTreeNode, collapsed: boolean, recursive: boolean, deep: boolean): boolean { - let result = node.collapsible && node.collapsed !== collapsed; + private _setNodeCollapseState(node: IMutableTreeNode, update: CollapseStateUpdate, deep: boolean): boolean { + let result: boolean; - if (node.collapsible) { - node.collapsed = collapsed; + if (node === this.root) { + result = false; + } else { + if (isCollapsibleStateUpdate(update)) { + result = node.collapsible !== update.collapsible; + node.collapsible = update.collapsible; + } else { + result = node.collapsed !== update.collapsed; + node.collapsed = update.collapsed; + } if (result) { this._onDidChangeCollapseState.fire({ node, deep }); } } - if (recursive) { + if (!isCollapsibleStateUpdate(update) && update.recursive) { for (const child of node.children) { - result = this._setNodeCollapsed(child, collapsed, true, true) || result; + result = this._setNodeCollapseState(child, update, true) || result; } } @@ -292,7 +327,7 @@ export class IndexTreeModel, TFilterData = voi location = location.slice(0, location.length - 1); if (node.collapsed) { - this._setCollapsed(location, false); + this._setCollapseState(location, { collapsed: false, recursive: false }); } } }); diff --git a/src/vs/base/browser/ui/tree/objectTreeModel.ts b/src/vs/base/browser/ui/tree/objectTreeModel.ts index df4dabcdbc6..e2f78b9ebea 100644 --- a/src/vs/base/browser/ui/tree/objectTreeModel.ts +++ b/src/vs/base/browser/ui/tree/objectTreeModel.ts @@ -216,6 +216,11 @@ export class ObjectTreeModel, TFilterData extends Non return this.model.isCollapsible(location); } + setCollapsible(element: T | null, collapsible?: boolean): boolean { + const location = this.getElementLocation(element); + return this.model.setCollapsible(location, collapsible); + } + isCollapsed(element: T | null): boolean { const location = this.getElementLocation(element); return this.model.isCollapsed(location); diff --git a/src/vs/base/browser/ui/tree/tree.ts b/src/vs/base/browser/ui/tree/tree.ts index 930e76634bb..5be49ab229f 100644 --- a/src/vs/base/browser/ui/tree/tree.ts +++ b/src/vs/base/browser/ui/tree/tree.ts @@ -120,6 +120,7 @@ export interface ITreeModel { getLastElementAncestor(location?: TRef): T | undefined; isCollapsible(location: TRef): boolean; + setCollapsible(location: TRef, collapsible?: boolean): boolean; isCollapsed(location: TRef): boolean; setCollapsed(location: TRef, collapsed?: boolean, recursive?: boolean): boolean; expandTo(location: TRef): void; diff --git a/src/vs/base/common/amd.ts b/src/vs/base/common/amd.ts index d985c46deeb..90497f4b418 100644 --- a/src/vs/base/common/amd.ts +++ b/src/vs/base/common/amd.ts @@ -8,3 +8,11 @@ import { URI } from 'vs/base/common/uri'; export function getPathFromAmdModule(requirefn: typeof require, relativePath: string): string { return URI.parse(requirefn.toUrl(relativePath)).fsPath; } + +/** + * Reference a resource that might be inlined. + * Do not rename this method unless you adopt the build scripts. + */ +export function registerAndGetAmdImageURL(absolutePath: string): string { + return require.toUrl(absolutePath); +} diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 1c4251e7803..eadbb152df0 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -5,11 +5,6 @@ import { CharCode } from 'vs/base/common/charCode'; -/** - * The empty string. - */ -export const empty = ''; - export function isFalsyOrWhitespace(str: string | undefined): boolean { if (!str || typeof str !== 'string') { return true; @@ -70,7 +65,7 @@ export function escape(html: string): string { * Escapes regular expression characters in a given string */ export function escapeRegExpCharacters(value: string): string { - return value.replace(/[\\\{\}\*\+\?\|\^\$\.\[\]\(\)\#]/g, '\\$&'); + return value.replace(/[\\\{\}\*\+\?\|\^\$\.\[\]\(\)]/g, '\\$&'); } /** @@ -608,7 +603,7 @@ export function lcut(text: string, n: number) { re.lastIndex += 1; } - return text.substring(i).replace(/^\s/, empty); + return text.substring(i).replace(/^\s/, ''); } // Escape codes @@ -636,7 +631,7 @@ export const removeAccents: (str: string) => string = (function () { // see: https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript/37511463#37511463 const regex = /[\u0300-\u036f]/g; return function (str: string) { - return (str as any).normalize('NFD').replace(regex, empty); + return (str as any).normalize('NFD').replace(regex, ''); }; } })(); diff --git a/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts index 3192f789ac1..1177889e12a 100644 --- a/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts +++ b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts @@ -355,4 +355,38 @@ suite('AsyncDataTree', function () { race = await Promise.race([pExpandA.then(() => 'expand'), timeout(1).then(() => 'timeout')]); assert.equal(race, 'expand', 'expand(a) should now be done'); }); + + test('issue #78388 - tree should react to hasChildren toggles', async () => { + const container = document.createElement('div'); + const model = new Model({ + id: 'root', + children: [{ + id: 'a' + }] + }); + + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], new DataSource(), { identityProvider: new IdentityProvider() }); + tree.layout(200); + + await tree.setInput(model.root); + assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); + + let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; + assert(!hasClass(twistie, 'collapsible')); + assert(!hasClass(twistie, 'collapsed')); + + model.get('a').children = [{ id: 'aa' }]; + await tree.updateChildren(model.get('a'), false); + assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); + twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; + assert(hasClass(twistie, 'collapsible')); + assert(hasClass(twistie, 'collapsed')); + + model.get('a').children = []; + await tree.updateChildren(model.get('a'), false); + assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); + twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; + assert(!hasClass(twistie, 'collapsible')); + assert(!hasClass(twistie, 'collapsed')); + }); }); diff --git a/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts b/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts index de92f9b2732..6d660f358e9 100644 --- a/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts +++ b/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts @@ -333,6 +333,67 @@ suite('IndexTreeModel', function () { assert.deepEqual(toArray(list), [1, 11, 2]); }); + test('setCollapsible', () => { + const list: ITreeNode[] = []; + const model = new IndexTreeModel('test', toSpliceable(list), -1); + + model.splice([0], 0, Iterator.fromArray([ + { + element: 0, children: Iterator.fromArray([ + { element: 10 } + ]) + } + ])); + + assert.deepEqual(list.length, 2); + + model.setCollapsible([0], false); + assert.deepEqual(list.length, 2); + assert.deepEqual(list[0].element, 0); + assert.deepEqual(list[0].collapsible, false); + assert.deepEqual(list[0].collapsed, false); + assert.deepEqual(list[1].element, 10); + assert.deepEqual(list[1].collapsible, false); + assert.deepEqual(list[1].collapsed, false); + + model.setCollapsed([0], true); + assert.deepEqual(list.length, 1); + assert.deepEqual(list[0].element, 0); + assert.deepEqual(list[0].collapsible, false); + assert.deepEqual(list[0].collapsed, true); + + model.setCollapsed([0], false); + assert.deepEqual(list[0].element, 0); + assert.deepEqual(list[0].collapsible, false); + assert.deepEqual(list[0].collapsed, false); + assert.deepEqual(list[1].element, 10); + assert.deepEqual(list[1].collapsible, false); + assert.deepEqual(list[1].collapsed, false); + + model.setCollapsible([0], true); + assert.deepEqual(list.length, 2); + assert.deepEqual(list[0].element, 0); + assert.deepEqual(list[0].collapsible, true); + assert.deepEqual(list[0].collapsed, false); + assert.deepEqual(list[1].element, 10); + assert.deepEqual(list[1].collapsible, false); + assert.deepEqual(list[1].collapsed, false); + + model.setCollapsed([0], true); + assert.deepEqual(list.length, 1); + assert.deepEqual(list[0].element, 0); + assert.deepEqual(list[0].collapsible, true); + assert.deepEqual(list[0].collapsed, true); + + model.setCollapsed([0], false); + assert.deepEqual(list[0].element, 0); + assert.deepEqual(list[0].collapsible, true); + assert.deepEqual(list[0].collapsed, false); + assert.deepEqual(list[1].element, 10); + assert.deepEqual(list[1].collapsible, false); + assert.deepEqual(list[1].collapsed, false); + }); + test('simple filter', function () { const list: ITreeNode[] = []; const filter = new class implements ITreeFilter { diff --git a/src/vs/code/browser/workbench/callback.html b/src/vs/code/browser/workbench/callback.html new file mode 100644 index 00000000000..da6c907b666 --- /dev/null +++ b/src/vs/code/browser/workbench/callback.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + + Visual Studio Code + + + + + + + Visual Studio Code + +
+
+ You can close this page now. +
+
+ + diff --git a/src/vs/code/browser/workbench/web.main.ts b/src/vs/code/browser/workbench/web.main.ts new file mode 100644 index 00000000000..656bee0daa7 --- /dev/null +++ b/src/vs/code/browser/workbench/web.main.ts @@ -0,0 +1,210 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IWorkbenchConstructionOptions, create } from 'vs/workbench/workbench.web.api'; +import { IURLCallbackProvider } from 'vs/workbench/services/url/browser/urlService'; +import { Event, Emitter } from 'vs/base/common/event'; +import { URI, UriComponents } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { streamToBuffer } from 'vs/base/common/buffer'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { request } from 'vs/base/parts/request/browser/request'; +import { ICredentialsProvider } from 'vs/workbench/services/credentials/browser/credentialsService'; + +export function main(): void { + const options: IWorkbenchConstructionOptions = JSON.parse(document.getElementById('vscode-workbench-web-configuration')!.getAttribute('data-settings')!); + options.urlCallbackProvider = new PollingURLCallbackProvider(); + options.credentialsProvider = new LocalStorageCredentialsProvider(); + + create(document.body, options); +} + +interface ICredential { + service: string; + account: string; + password: string; +} + +class LocalStorageCredentialsProvider implements ICredentialsProvider { + + static readonly CREDENTIALS_OPENED_KEY = 'credentials.provider'; + + private _credentials: ICredential[]; + private get credentials(): ICredential[] { + if (!this._credentials) { + try { + const serializedCredentials = window.localStorage.getItem(LocalStorageCredentialsProvider.CREDENTIALS_OPENED_KEY); + if (serializedCredentials) { + this._credentials = JSON.parse(serializedCredentials); + } + } catch (error) { + // ignore + } + + if (!Array.isArray(this._credentials)) { + this._credentials = []; + } + } + + return this._credentials; + } + + private save(): void { + window.localStorage.setItem(LocalStorageCredentialsProvider.CREDENTIALS_OPENED_KEY, JSON.stringify(this.credentials)); + } + + async getPassword(service: string, account: string): Promise { + return this.doGetPassword(service, account); + } + + private async doGetPassword(service: string, account?: string): Promise { + for (const credential of this.credentials) { + if (credential.service === service) { + if (typeof account !== 'string' || account === credential.account) { + return credential.password; + } + } + } + + return null; + } + + async setPassword(service: string, account: string, password: string): Promise { + this.deletePassword(service, account); + + this.credentials.push({ service, account, password }); + + this.save(); + } + + async deletePassword(service: string, account: string): Promise { + let found = false; + + this._credentials = this.credentials.filter(credential => { + if (credential.service === service && credential.account === account) { + found = true; + + return false; + } + + return true; + }); + + if (found) { + this.save(); + } + + return found; + } + + async findPassword(service: string): Promise { + return this.doGetPassword(service); + } + + async findCredentials(service: string): Promise> { + return this.credentials + .filter(credential => credential.service === service) + .map(({ account, password }) => ({ account, password })); + } +} + +class PollingURLCallbackProvider extends Disposable implements IURLCallbackProvider { + + static FETCH_INTERVAL = 500; // fetch every 500ms + static FETCH_TIMEOUT = 5 * 60 * 1000; // ...but stop after 5min + + static QUERY_KEYS = { + REQUEST_ID: 'vscode-requestId', + SCHEME: 'vscode-scheme', + AUTHORITY: 'vscode-authority', + PATH: 'vscode-path', + QUERY: 'vscode-query', + FRAGMENT: 'vscode-fragment' + }; + + private readonly _onCallback: Emitter = this._register(new Emitter()); + readonly onCallback: Event = this._onCallback.event; + + create(options?: Partial): URI { + const queryValues: Map = new Map(); + + const requestId = generateUuid(); + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId); + + const { scheme, authority, path, query, fragment } = options ? options : { scheme: undefined, authority: undefined, path: undefined, query: undefined, fragment: undefined }; + + if (scheme) { + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.SCHEME, scheme); + } + + if (authority) { + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.AUTHORITY, authority); + } + + if (path) { + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.PATH, path); + } + + if (query) { + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.QUERY, query); + } + + if (fragment) { + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.FRAGMENT, fragment); + } + + // Start to poll on the callback being fired + this.periodicFetchCallback(requestId, Date.now()); + + return this.doCreateUri('/callback', queryValues); + } + + private async periodicFetchCallback(requestId: string, startTime: number): Promise { + + // Ask server for callback results + const queryValues: Map = new Map(); + queryValues.set(PollingURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId); + + const result = await request({ + url: this.doCreateUri('/fetch-callback', queryValues).toString(true) + }, CancellationToken.None); + + // Check for callback results + const content = await streamToBuffer(result.stream); + if (content.byteLength > 0) { + try { + this._onCallback.fire(URI.revive(JSON.parse(content.toString()))); + } catch (error) { + console.error(error); + } + + return; // done + } + + // Continue fetching unless we hit the timeout + if (Date.now() - startTime < PollingURLCallbackProvider.FETCH_TIMEOUT) { + setTimeout(() => this.periodicFetchCallback(requestId, startTime), PollingURLCallbackProvider.FETCH_INTERVAL); + } + } + + private doCreateUri(path: string, queryValues: Map): URI { + let query: string | undefined = undefined; + + if (queryValues) { + let index = 0; + queryValues.forEach((value, key) => { + if (!query) { + query = ''; + } + + const prefix = (index++ === 0) ? '' : '&'; + query += `${prefix}${key}=${encodeURIComponent(value)}`; + }); + } + + return URI.parse(window.location.href).with({ path, query }); + } +} diff --git a/src/vs/code/browser/workbench/workbench-dev.html b/src/vs/code/browser/workbench/workbench-dev.html new file mode 100644 index 00000000000..a7769b8cd64 --- /dev/null +++ b/src/vs/code/browser/workbench/workbench-dev.html @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html index 1d9a0b8308d..3388f8a7daf 100644 --- a/src/vs/code/browser/workbench/workbench.html +++ b/src/vs/code/browser/workbench/workbench.html @@ -10,18 +10,19 @@ + manifest-src 'self'; + "> @@ -33,13 +34,39 @@ + + + + + + - + + + diff --git a/src/vs/code/browser/workbench/workbench.js b/src/vs/code/browser/workbench/workbench.js deleted file mode 100644 index 2f09f53e43a..00000000000 --- a/src/vs/code/browser/workbench/workbench.js +++ /dev/null @@ -1,31 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//@ts-check -'use strict'; - -(function () { - - /** @type any */ - const amdLoader = require; - - amdLoader.config({ - baseUrl: `${window.location.origin}/static/out`, - paths: { - 'vscode-textmate': `${window.location.origin}/static/node_modules/vscode-textmate/release/main`, - 'onigasm-umd': `${window.location.origin}/static/node_modules/onigasm-umd/release/main`, - 'xterm': `${window.location.origin}/static/node_modules/xterm/lib/xterm.js`, - 'xterm-addon-search': `${window.location.origin}/static/node_modules/xterm-addon-search/lib/xterm-addon-search.js`, - 'xterm-addon-web-links': `${window.location.origin}/static/node_modules/xterm-addon-web-links/lib/xterm-addon-web-links.js`, - 'semver-umd': `${window.location.origin}/static/node_modules/semver-umd/lib/semver-umd.js`, - '@microsoft/applicationinsights-web': `${window.location.origin}/static/node_modules/@microsoft/applicationinsights-web/dist/applicationinsights-web.js`, - } - }); - - amdLoader(['vs/workbench/workbench.web.api'], function (api) { - const options = JSON.parse(document.getElementById('vscode-workbench-web-configuration').getAttribute('data-settings')); - api.create(document.body, options); - }); -})(); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 7faad37bebc..695877a7e50 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -26,7 +26,7 @@ import { IStateService } from 'vs/platform/state/common/state'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IURLService } from 'vs/platform/url/common/url'; -import { URLHandlerChannelClient, URLServiceChannel } from 'vs/platform/url/node/urlIpc'; +import { URLHandlerChannelClient, URLServiceChannel, URLHandlerRouter } from 'vs/platform/url/common/urlIpc'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService, combinedAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils'; import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc'; @@ -579,7 +579,8 @@ export class CodeApplication extends Disposable { // Create a URL handler which forwards to the last active window const activeWindowManager = new ActiveWindowManager(windowsService); const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id)); - const urlHandlerChannel = electronIpcServer.getChannel('urlHandler', activeWindowRouter); + const urlHandlerRouter = new URLHandlerRouter(activeWindowRouter); + const urlHandlerChannel = electronIpcServer.getChannel('urlHandler', urlHandlerRouter); const multiplexURLHandler = new URLHandlerChannelClient(urlHandlerChannel); // On Mac, Code can be running without any open windows, so we must create a window to handle urls, diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 157300bb64b..6c167b29b50 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -11,7 +11,7 @@ import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, R import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import product from 'vs/platform/product/node/product'; import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState, getTitleBarStyle } from 'vs/platform/windows/common/windows'; import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -574,7 +574,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { windowConfiguration.partsSplashPath = path.join(this.environmentService.userDataPath, 'rapid_render.json'); // Config (combination of process.argv and window configuration) - const environment = parseArgs(process.argv); + const environment = parseArgs(process.argv, OPTIONS); const config = objects.assign(environment, windowConfiguration); for (const key in config) { const configValue = (config as any)[key]; diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index afa7acafa94..b847c638090 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -5,7 +5,7 @@ import { spawn, ChildProcess, SpawnOptions } from 'child_process'; import { assign } from 'vs/base/common/objects'; -import { buildHelpMessage, buildVersionMessage, addArg, createWaitMarkerFile } from 'vs/platform/environment/node/argv'; +import { buildHelpMessage, buildVersionMessage, addArg, createWaitMarkerFile, OPTIONS } from 'vs/platform/environment/node/argv'; import { parseCLIProcessArgv } from 'vs/platform/environment/node/argvHelper'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; import product from 'vs/platform/product/node/product'; @@ -47,7 +47,7 @@ export async function main(argv: string[]): Promise { // Help if (args.help) { const executable = `${product.applicationName}${os.platform() === 'win32' ? '.exe' : ''}`; - console.log(buildHelpMessage(product.nameLong, executable, pkg.version)); + console.log(buildHelpMessage(product.nameLong, executable, pkg.version, OPTIONS)); } // Version Info diff --git a/src/vs/code/test/node/argv.test.ts b/src/vs/code/test/node/argv.test.ts index 6ac49bc9988..59911ebc41e 100644 --- a/src/vs/code/test/node/argv.test.ts +++ b/src/vs/code/test/node/argv.test.ts @@ -4,29 +4,28 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { formatOptions, Option, addArg } from 'vs/platform/environment/node/argv'; -import { ParsedArgs } from 'vs/platform/environment/common/environment'; suite('formatOptions', () => { - function o(id: keyof ParsedArgs, description: string): Option { + function o(description: string): Option { return { - id, description, type: 'string' + description, type: 'string' }; } test('Text should display small columns correctly', () => { assert.deepEqual( - formatOptions([ - o('add', 'bar') - ], 80), + formatOptions({ + 'add': o('bar') + }, 80), [' --add bar'] ); assert.deepEqual( - formatOptions([ - o('add', 'bar'), - o('wait', 'ba'), - o('trace', 'b') - ], 80), + formatOptions({ + 'add': o('bar'), + 'wait': o('ba'), + 'trace': o('b') + }, 80), [ ' --add bar', ' --wait ba', @@ -36,9 +35,9 @@ suite('formatOptions', () => { test('Text should wrap', () => { assert.deepEqual( - formatOptions([ - o('add', ('bar ').repeat(9)) - ], 40), + formatOptions({ + 'add': o(('bar ').repeat(9)) + }, 40), [ ' --add bar bar bar bar bar bar bar bar', ' bar' @@ -47,9 +46,9 @@ suite('formatOptions', () => { test('Text should revert to the condensed view when the terminal is too narrow', () => { assert.deepEqual( - formatOptions([ - o('add', ('bar ').repeat(9)) - ], 30), + formatOptions({ + 'add': o(('bar ').repeat(9)) + }, 30), [ ' --add', ' bar bar bar bar bar bar bar bar bar ' diff --git a/src/vs/editor/browser/config/configuration.ts b/src/vs/editor/browser/config/configuration.ts index cdb50af8be8..9078c4fe7cf 100644 --- a/src/vs/editor/browser/config/configuration.ts +++ b/src/vs/editor/browser/config/configuration.ts @@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform'; import { CharWidthRequest, CharWidthRequestType, readCharWidths } from 'vs/editor/browser/config/charWidthReader'; import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver'; import { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig'; -import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import { IDimension } from 'vs/editor/common/editorCommon'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; @@ -320,7 +320,7 @@ export class Configuration extends CommonEditorConfiguration { this._register(CSSBasedConfiguration.INSTANCE.onDidChange(() => this._onCSSBasedConfigurationChanged())); - if (this._validatedOptions.automaticLayout) { + if (this._validatedOptions.get(EditorOption.automaticLayout)) { this._elementSizeObserver.startObserving(); } diff --git a/src/vs/editor/browser/controller/coreCommands.ts b/src/vs/editor/browser/controller/coreCommands.ts index bbef333e010..94ed9e159cb 100644 --- a/src/vs/editor/browser/controller/coreCommands.ts +++ b/src/vs/editor/browser/controller/coreCommands.ts @@ -343,12 +343,8 @@ export namespace CoreNavigationCommands { const validatedPosition = context.model.validatePosition(args.position); const validatedViewPosition = context.validateViewPosition(new Position(args.viewPosition.lineNumber, args.viewPosition.column), validatedPosition); - let fromViewLineNumber = prevColumnSelectData.fromViewLineNumber; - let fromViewVisualColumn = prevColumnSelectData.fromViewVisualColumn; - if (!prevColumnSelectData.isReal && args.setAnchorIfNotSet) { - fromViewLineNumber = validatedViewPosition.lineNumber; - fromViewVisualColumn = args.mouseColumn - 1; - } + let fromViewLineNumber = args.doColumnSelect ? prevColumnSelectData.fromViewLineNumber : validatedViewPosition.lineNumber; + let fromViewVisualColumn = args.doColumnSelect ? prevColumnSelectData.fromViewVisualColumn : args.mouseColumn - 1; return ColumnSelection.columnSelect(context.config, context.viewModel, fromViewLineNumber, fromViewVisualColumn, validatedViewPosition.lineNumber, args.mouseColumn - 1); } }); diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index 418e8ebee98..dd8979daabc 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -21,6 +21,8 @@ import { HorizontalRange } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + /** * Merges mouse events when mouse move events are throttled @@ -111,7 +113,7 @@ export class MouseHandler extends ViewEventHandler { const onMouseWheel = (browserEvent: IMouseWheelEvent) => { this.viewController.emitMouseWheel(browserEvent); - if (!this._context.configuration.editor.viewInfo.mouseWheelZoom) { + if (!this._context.configuration.options.get(EditorOption.mouseWheelZoom)) { return; } const e = new StandardWheelEvent(browserEvent); @@ -216,7 +218,7 @@ export class MouseHandler extends ViewEventHandler { const targetIsContent = (t.type === editorBrowser.MouseTargetType.CONTENT_TEXT || t.type === editorBrowser.MouseTargetType.CONTENT_EMPTY); const targetIsGutter = (t.type === editorBrowser.MouseTargetType.GUTTER_GLYPH_MARGIN || t.type === editorBrowser.MouseTargetType.GUTTER_LINE_NUMBERS || t.type === editorBrowser.MouseTargetType.GUTTER_LINE_DECORATIONS); const targetIsLineNumbers = (t.type === editorBrowser.MouseTargetType.GUTTER_LINE_NUMBERS); - const selectOnLineNumbers = this._context.configuration.editor.viewInfo.selectOnLineNumbers; + const selectOnLineNumbers = this._context.configuration.options.get(EditorOption.selectOnLineNumbers); const targetIsViewZone = (t.type === editorBrowser.MouseTargetType.CONTENT_VIEW_ZONE || t.type === editorBrowser.MouseTargetType.GUTTER_VIEW_ZONE); const targetIsWidget = (t.type === editorBrowser.MouseTargetType.CONTENT_WIDGET); @@ -351,8 +353,10 @@ class MouseDownOperation extends Disposable { // Overwrite the detail of the MouseEvent, as it will be sent out in an event and contributions might rely on it. e.detail = this._mouseState.count; - if (!this._context.configuration.editor.readOnly - && this._context.configuration.editor.dragAndDrop + const options = this._context.configuration.options; + + if (!options.get(EditorOption.readOnly) + && options.get(EditorOption.dragAndDrop) && !this._mouseState.altKey // we don't support multiple mouse && e.detail < 2 // only single click on a selection can work && !this._isActive // the mouse is not down yet diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index f510e0f6f82..c025c958a0f 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -10,7 +10,7 @@ import { ClientCoordinates, EditorMouseEvent, EditorPagePosition, PageCoordinate import { PartFingerprint, PartFingerprints } from 'vs/editor/browser/view/viewPart'; import { ViewLine } from 'vs/editor/browser/viewParts/lines/viewLine'; import { IViewCursorRenderData } from 'vs/editor/browser/viewParts/viewCursors/viewCursor'; -import { EditorLayoutInfo } from 'vs/editor/common/config/editorOptions'; +import { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range as EditorRange } from 'vs/editor/common/core/range'; import { HorizontalRange } from 'vs/editor/common/view/renderingContext'; @@ -239,10 +239,11 @@ export class HitTestContext { constructor(context: ViewContext, viewHelper: IPointerHandlerHelper, lastViewCursorsRenderData: IViewCursorRenderData[]) { this.model = context.model; - this.layoutInfo = context.configuration.editor.layoutInfo; + const options = context.configuration.options; + this.layoutInfo = options.get(EditorOption.layoutInfo); this.viewDomNode = viewHelper.viewDomNode; - this.lineHeight = context.configuration.editor.lineHeight; - this.typicalHalfwidthCharacterWidth = context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; + this.lineHeight = options.get(EditorOption.lineHeight); + this.typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; this.lastViewCursorsRenderData = lastViewCursorsRenderData; this._context = context; this._viewHelper = viewHelper; @@ -713,9 +714,10 @@ export class MouseTargetFactory { } public getMouseColumn(editorPos: EditorPagePosition, pos: PageCoordinates): number { - const layoutInfo = this._context.configuration.editor.layoutInfo; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); const mouseContentHorizontalOffset = this._context.viewLayout.getCurrentScrollLeft() + pos.x - editorPos.x - layoutInfo.contentLeft; - return MouseTargetFactory._getMouseColumn(mouseContentHorizontalOffset, this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth); + return MouseTargetFactory._getMouseColumn(mouseContentHorizontalOffset, options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth); } public static _getMouseColumn(mouseContentHorizontalOffset: number, typicalHalfwidthCharacterWidth: number): number { diff --git a/src/vs/editor/browser/controller/textAreaHandler.ts b/src/vs/editor/browser/controller/textAreaHandler.ts index 97efaf60eda..57f3ec804be 100644 --- a/src/vs/editor/browser/controller/textAreaHandler.ts +++ b/src/vs/editor/browser/controller/textAreaHandler.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./textAreaHandler'; +import * as nls from 'vs/nls'; import * as browser from 'vs/base/browser/browser'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -16,7 +17,7 @@ import { ViewController } from 'vs/editor/browser/view/viewController'; import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart'; import { LineNumbersOverlay } from 'vs/editor/browser/viewParts/lineNumbers/lineNumbers'; import { Margin } from 'vs/editor/browser/viewParts/margin/margin'; -import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions'; +import { RenderLineNumbersType, EditorOption, IComputedEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { WordCharacterClass, getMapForWordSeparators } from 'vs/editor/common/controller/wordCharacterClassifier'; import { Position } from 'vs/editor/common/core/position'; @@ -91,12 +92,13 @@ export class TextAreaHandler extends ViewPart { private readonly _viewController: ViewController; private readonly _viewHelper: ITextAreaHandlerHelper; + private _scrollLeft: number; + private _scrollTop: number; + private _accessibilitySupport: AccessibilitySupport; private _contentLeft: number; private _contentWidth: number; private _contentHeight: number; - private _scrollLeft: number; - private _scrollTop: number; private _fontInfo: BareFontInfo; private _lineHeight: number; private _emptySelectionClipboard: boolean; @@ -117,19 +119,20 @@ export class TextAreaHandler extends ViewPart { this._viewController = viewController; this._viewHelper = viewHelper; - - const conf = this._context.configuration.editor; - - this._accessibilitySupport = conf.accessibilitySupport; - this._contentLeft = conf.layoutInfo.contentLeft; - this._contentWidth = conf.layoutInfo.contentWidth; - this._contentHeight = conf.layoutInfo.contentHeight; this._scrollLeft = 0; this._scrollTop = 0; - this._fontInfo = conf.fontInfo; - this._lineHeight = conf.lineHeight; - this._emptySelectionClipboard = conf.emptySelectionClipboard; - this._copyWithSyntaxHighlighting = conf.copyWithSyntaxHighlighting; + + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._accessibilitySupport = options.get(EditorOption.accessibilitySupport); + this._contentLeft = layoutInfo.contentLeft; + this._contentWidth = layoutInfo.contentWidth; + this._contentHeight = layoutInfo.contentHeight; + this._fontInfo = options.get(EditorOption.fontInfo); + this._lineHeight = options.get(EditorOption.lineHeight); + this._emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard); + this._copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting); this._visibleTextArea = null; this._selections = [new Selection(1, 1, 1, 1)]; @@ -143,7 +146,7 @@ export class TextAreaHandler extends ViewPart { this.textArea.setAttribute('autocapitalize', 'off'); this.textArea.setAttribute('autocomplete', 'off'); this.textArea.setAttribute('spellcheck', 'false'); - this.textArea.setAttribute('aria-label', conf.viewInfo.ariaLabel); + this.textArea.setAttribute('aria-label', this._getAriaLabel(options)); this.textArea.setAttribute('role', 'textbox'); this.textArea.setAttribute('aria-multiline', 'true'); this.textArea.setAttribute('aria-haspopup', 'false'); @@ -341,7 +344,7 @@ export class TextAreaHandler extends ViewPart { private _getWordBeforePosition(position: Position): string { const lineContent = this._context.model.getLineContent(position.lineNumber); - const wordSeparators = getMapForWordSeparators(this._context.configuration.editor.wordSeparators); + const wordSeparators = getMapForWordSeparators(this._context.configuration.options.get(EditorOption.wordSeparators)); let column = position.column; let distance = 0; @@ -368,35 +371,33 @@ export class TextAreaHandler extends ViewPart { return ''; } + private _getAriaLabel(options: IComputedEditorOptions): string { + const accessibilitySupport = options.get(EditorOption.accessibilitySupport); + if (accessibilitySupport === AccessibilitySupport.Disabled) { + return nls.localize('accessibilityOffAriaLabel', "The editor is not accessible at this time. Press Alt+F1 for options."); + } + return options.get(EditorOption.ariaLabel); + } + // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - const conf = this._context.configuration.editor; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); - if (e.fontInfo) { - this._fontInfo = conf.fontInfo; - } - if (e.viewInfo) { - this.textArea.setAttribute('aria-label', conf.viewInfo.ariaLabel); - } - if (e.layoutInfo) { - this._contentLeft = conf.layoutInfo.contentLeft; - this._contentWidth = conf.layoutInfo.contentWidth; - this._contentHeight = conf.layoutInfo.contentHeight; - } - if (e.lineHeight) { - this._lineHeight = conf.lineHeight; - } - if (e.accessibilitySupport) { - this._accessibilitySupport = conf.accessibilitySupport; + this._accessibilitySupport = options.get(EditorOption.accessibilitySupport); + this._contentLeft = layoutInfo.contentLeft; + this._contentWidth = layoutInfo.contentWidth; + this._contentHeight = layoutInfo.contentHeight; + this._fontInfo = options.get(EditorOption.fontInfo); + this._lineHeight = options.get(EditorOption.lineHeight); + this._emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard); + this._copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting); + this.textArea.setAttribute('aria-label', this._getAriaLabel(options)); + + if (e.hasChanged(EditorOption.accessibilitySupport)) { this._textAreaInput.writeScreenReaderContent('strategy changed'); } - if (e.emptySelectionClipboard) { - this._emptySelectionClipboard = conf.emptySelectionClipboard; - } - if (e.copyWithSyntaxHighlighting) { - this._copyWithSyntaxHighlighting = conf.copyWithSyntaxHighlighting; - } return true; } @@ -545,10 +546,12 @@ export class TextAreaHandler extends ViewPart { tac.setWidth(1); tac.setHeight(1); - if (this._context.configuration.editor.viewInfo.glyphMargin) { + const options = this._context.configuration.options; + + if (options.get(EditorOption.glyphMargin)) { tac.setClassName('monaco-editor-background textAreaCover ' + Margin.OUTER_CLASS_NAME); } else { - if (this._context.configuration.editor.viewInfo.renderLineNumbers !== RenderLineNumbersType.Off) { + if (options.get(EditorOption.lineNumbers).renderType !== RenderLineNumbersType.Off) { tac.setClassName('monaco-editor-background textAreaCover ' + LineNumbersOverlay.CLASS_NAME); } else { tac.setClassName('monaco-editor-background textAreaCover'); diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index a5e31344d3c..3a05cd5c8f4 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -6,7 +6,7 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IMouseEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; import { IDisposable } from 'vs/base/common/lifecycle'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { OverviewRulerPosition, ConfigurationChangedEvent, EditorLayoutInfo, IComputedEditorOptions, EditorOption, FindComputedEditorOptionValueById, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { ICursors } from 'vs/editor/common/controller/cursorCommon'; import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { IPosition, Position } from 'vs/editor/common/core/position'; @@ -315,7 +315,7 @@ export interface IOverviewRuler { getDomNode(): HTMLElement; dispose(): void; setZones(zones: OverviewRulerZone[]): void; - setLayout(position: editorOptions.OverviewRulerPosition): void; + setLayout(position: OverviewRulerPosition): void; } /** @@ -351,7 +351,7 @@ export interface ICodeEditor extends editorCommon.IEditor { * An event emitted when the configuration of the editor has changed. (e.g. `editor.updateOptions()`) * @event */ - onDidChangeConfiguration(listener: (e: editorOptions.IConfigurationChangedEvent) => void): IDisposable; + onDidChangeConfiguration(listener: (e: ConfigurationChangedEvent) => void): IDisposable; /** * An event emitted when the cursor position has changed. * @event @@ -481,7 +481,7 @@ export interface ICodeEditor extends editorCommon.IEditor { * An event emitted when the layout of the editor has changed. * @event */ - onDidLayoutChange(listener: (e: editorOptions.EditorLayoutInfo) => void): IDisposable; + onDidLayoutChange(listener: (e: EditorLayoutInfo) => void): IDisposable; /** * An event emitted when the scroll in the editor has changed. * @event @@ -532,15 +532,19 @@ export interface ICodeEditor extends editorCommon.IEditor { setModel(model: ITextModel | null): void; /** - * Returns the current editor's configuration - */ - getConfiguration(): editorOptions.InternalEditorOptions; - - /** - * Returns the 'raw' editor's configuration (without any validation or defaults). * @internal */ - getRawConfiguration(): editorOptions.IEditorOptions; + getOptions(): IComputedEditorOptions; + + /** + * @internal + */ + getOption(id: T): FindComputedEditorOptionValueById; + + /** + * Returns the editor's configuration (without any validation or defaults). + */ + getRawOptions(): IEditorOptions; /** * Get value of the current model attached to this editor. @@ -655,7 +659,7 @@ export interface ICodeEditor extends editorCommon.IEditor { /** * Get the layout info for the editor. */ - getLayoutInfo(): editorOptions.EditorLayoutInfo; + getLayoutInfo(): EditorLayoutInfo; /** * Returns the ranges that are currently visible. diff --git a/src/vs/editor/browser/view/viewController.ts b/src/vs/editor/browser/view/viewController.ts index 10fb2e1aa6b..3cbd1cc286f 100644 --- a/src/vs/editor/browser/view/viewController.ts +++ b/src/vs/editor/browser/view/viewController.ts @@ -12,6 +12,7 @@ import { Selection } from 'vs/editor/common/core/selection'; import { IConfiguration } from 'vs/editor/common/editorCommon'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface IMouseDispatchData { position: Position; @@ -107,7 +108,7 @@ export class ViewController { } private _hasMulticursorModifier(data: IMouseDispatchData): boolean { - switch (this.configuration.editor.multiCursorModifier) { + switch (this.configuration.options.get(EditorOption.multiCursorModifier)) { case 'altKey': return data.altKey; case 'ctrlKey': @@ -119,7 +120,7 @@ export class ViewController { } private _hasNonMulticursorModifier(data: IMouseDispatchData): boolean { - switch (this.configuration.editor.multiCursorModifier) { + switch (this.configuration.options.get(EditorOption.multiCursorModifier)) { case 'altKey': return data.ctrlKey || data.metaKey; case 'ctrlKey': @@ -132,11 +133,7 @@ export class ViewController { public dispatchMouse(data: IMouseDispatchData): void { if (data.middleButton) { - if (data.inSelectionMode) { - this._columnSelect(data.position, data.mouseColumn, true); - } else { - this.moveTo(data.position); - } + this._columnSelect(data.position, data.mouseColumn, data.inSelectionMode); } else if (data.startedOnLineNumbers) { // If the dragging started on the gutter, then have operations work on the entire line if (this._hasMulticursorModifier(data)) { @@ -182,7 +179,7 @@ export class ViewController { if (this._hasMulticursorModifier(data)) { if (!this._hasNonMulticursorModifier(data)) { if (data.shiftKey) { - this._columnSelect(data.position, data.mouseColumn, false); + this._columnSelect(data.position, data.mouseColumn, true); } else { // Do multi-cursor operations only when purely alt is pressed if (data.inSelectionMode) { @@ -222,13 +219,13 @@ export class ViewController { this._execMouseCommand(CoreNavigationCommands.MoveToSelect, this._usualArgs(viewPosition)); } - private _columnSelect(viewPosition: Position, mouseColumn: number, setAnchorIfNotSet: boolean): void { + private _columnSelect(viewPosition: Position, mouseColumn: number, doColumnSelect: boolean): void { viewPosition = this._validateViewColumn(viewPosition); this._execMouseCommand(CoreNavigationCommands.ColumnSelect, { position: this._convertViewToModelPosition(viewPosition), viewPosition: viewPosition, mouseColumn: mouseColumn, - setAnchorIfNotSet: setAnchorIfNotSet + doColumnSelect: doColumnSelect }); } diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index 45c711cecef..9f2e96a1a38 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -48,6 +48,8 @@ import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData' import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; import { IThemeService, getThemeTypeSelector } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export interface IContentWidgetData { widget: editorBrowser.IContentWidget; @@ -218,7 +220,7 @@ export class View extends ViewEventHandler { this.domNode.appendChild(this.overflowGuardContainer); this.domNode.appendChild(this.contentWidgets.overflowingContentWidgetsDomNode); - this._setLayout(); + this._applyLayout(); // Pointer handler this.pointerHandler = this._register(new PointerHandler(this._context, viewController, this.createPointerHandlerHelper())); @@ -280,8 +282,10 @@ export class View extends ViewEventHandler { }; } - private _setLayout(): void { - const layoutInfo = this._context.configuration.editor.layoutInfo; + private _applyLayout(): void { + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this.domNode.setWidth(layoutInfo.width); this.domNode.setHeight(layoutInfo.height); @@ -290,23 +294,18 @@ export class View extends ViewEventHandler { this.linesContent.setWidth(1000000); this.linesContent.setHeight(1000000); - } private getEditorClassName() { const focused = this._textAreaHandler.isFocused() ? ' focused' : ''; - return this._context.configuration.editor.editorClassName + ' ' + getThemeTypeSelector(this._context.theme.type) + focused; + return this._context.configuration.options.get(EditorOption.editorClassName) + ' ' + getThemeTypeSelector(this._context.theme.type) + focused; } // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.editorClassName) { - this.domNode.setClassName(this.getEditorClassName()); - } - if (e.layoutInfo) { - this._setLayout(); - } + this.domNode.setClassName(this.getEditorClassName()); + this._applyLayout(); return false; } public onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean { diff --git a/src/vs/editor/browser/view/viewLayer.ts b/src/vs/editor/browser/view/viewLayer.ts index ecdd665be73..eec48240c90 100644 --- a/src/vs/editor/browser/view/viewLayer.ts +++ b/src/vs/editor/browser/view/viewLayer.ts @@ -7,6 +7,7 @@ import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { IStringBuilder, createStringBuilder } from 'vs/editor/common/core/stringBuilder'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; /** * Represents a visible line @@ -269,7 +270,10 @@ export class VisibleLinesCollection { // ---- begin view event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - return e.layoutInfo; + if (e.hasChanged(EditorOption.layoutInfo)) { + return true; + } + return false; } public onFlushed(e: viewEvents.ViewFlushedEvent): boolean { diff --git a/src/vs/editor/browser/view/viewOverlays.ts b/src/vs/editor/browser/view/viewOverlays.ts index bc75a6b4cef..130f1f09fae 100644 --- a/src/vs/editor/browser/view/viewOverlays.ts +++ b/src/vs/editor/browser/view/viewOverlays.ts @@ -14,6 +14,8 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class ViewOverlays extends ViewPart implements IVisibleLinesHost { @@ -147,7 +149,7 @@ export class ViewOverlayLine implements IVisibleLine { constructor(configuration: IConfiguration, dynamicOverlays: DynamicViewOverlay[]) { this._configuration = configuration; - this._lineHeight = this._configuration.editor.lineHeight; + this._lineHeight = this._configuration.options.get(EditorOption.lineHeight); this._dynamicOverlays = dynamicOverlays; this._domNode = null; @@ -171,9 +173,7 @@ export class ViewOverlayLine implements IVisibleLine { // Nothing } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): void { - if (e.lineHeight) { - this._lineHeight = this._configuration.editor.lineHeight; - } + this._lineHeight = this._configuration.options.get(EditorOption.lineHeight); } public renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: IStringBuilder): boolean { @@ -215,8 +215,9 @@ export class ContentViewOverlays extends ViewOverlays { constructor(context: ViewContext) { super(context); - - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this._contentWidth = layoutInfo.contentWidth; this.domNode.setHeight(0); } @@ -224,10 +225,10 @@ export class ContentViewOverlays extends ViewOverlays { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.layoutInfo) { - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; - } - return super.onConfigurationChanged(e); + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this._contentWidth = layoutInfo.contentWidth; + return super.onConfigurationChanged(e) || true; } public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { return super.onScrollChanged(e) || e.scrollWidthChanged; @@ -249,25 +250,22 @@ export class MarginViewOverlays extends ViewOverlays { constructor(context: ViewContext) { super(context); - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this._contentLeft = layoutInfo.contentLeft; this.domNode.setClassName('margin-view-overlays'); this.domNode.setWidth(1); - Configuration.applyFontInfo(this.domNode, this._context.configuration.editor.fontInfo); + Configuration.applyFontInfo(this.domNode, options.get(EditorOption.fontInfo)); } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - let shouldRender = false; - if (e.fontInfo) { - Configuration.applyFontInfo(this.domNode, this._context.configuration.editor.fontInfo); - shouldRender = true; - } - if (e.layoutInfo) { - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; - shouldRender = true; - } - return super.onConfigurationChanged(e) || shouldRender; + const options = this._context.configuration.options; + Configuration.applyFontInfo(this.domNode, options.get(EditorOption.fontInfo)); + const layoutInfo = options.get(EditorOption.layoutInfo); + this._contentLeft = layoutInfo.contentLeft; + return super.onConfigurationChanged(e) || true; } public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index cae3be1ed16..3a962f22ea2 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -14,6 +14,8 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + class Coordinate { _coordinateBrand: void; @@ -207,10 +209,13 @@ class Widget { this.allowEditorOverflow = this._actual.allowEditorOverflow || false; this.suppressMouseDown = this._actual.suppressMouseDown || false; - this._fixedOverflowWidgets = this._context.configuration.editor.viewInfo.fixedOverflowWidgets; - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; - this._lineHeight = this._context.configuration.editor.lineHeight; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._fixedOverflowWidgets = options.get(EditorOption.fixedOverflowWidgets); + this._contentWidth = layoutInfo.contentWidth; + this._contentLeft = layoutInfo.contentLeft; + this._lineHeight = options.get(EditorOption.lineHeight); this._position = null; this._range = null; @@ -230,12 +235,12 @@ class Widget { } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): void { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.layoutInfo) { - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; + const options = this._context.configuration.options; + this._lineHeight = options.get(EditorOption.lineHeight); + if (e.hasChanged(EditorOption.layoutInfo)) { + const layoutInfo = options.get(EditorOption.layoutInfo); + this._contentLeft = layoutInfo.contentLeft; + this._contentWidth = layoutInfo.contentWidth; this._maxWidth = this._getMaxWidth(); } } diff --git a/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts b/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts index d707bbad7c5..820b7c30e29 100644 --- a/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts +++ b/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts @@ -10,26 +10,33 @@ import { RenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class CurrentLineHighlightOverlay extends DynamicViewOverlay { private readonly _context: ViewContext; private _lineHeight: number; private _renderLineHighlight: 'none' | 'gutter' | 'line' | 'all'; + private _contentWidth: number; private _selectionIsEmpty: boolean; private _primaryCursorLineNumber: number; private _scrollWidth: number; - private _contentWidth: number; constructor(context: ViewContext) { super(); this._context = context; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._renderLineHighlight = this._context.configuration.editor.viewInfo.renderLineHighlight; + + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._renderLineHighlight = options.get(EditorOption.renderLineHighlight); + this._contentWidth = layoutInfo.contentWidth; this._selectionIsEmpty = true; this._primaryCursorLineNumber = 1; this._scrollWidth = 0; - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; + this._context.addEventHandler(this); } @@ -42,15 +49,12 @@ export class CurrentLineHighlightOverlay extends DynamicViewOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.viewInfo) { - this._renderLineHighlight = this._context.configuration.editor.viewInfo.renderLineHighlight; - } - if (e.layoutInfo) { - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; - } + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._renderLineHighlight = options.get(EditorOption.renderLineHighlight); + this._contentWidth = layoutInfo.contentWidth; return true; } public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { diff --git a/src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.ts b/src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.ts index 55145073655..f07b024aca1 100644 --- a/src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.ts +++ b/src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.ts @@ -10,24 +10,30 @@ import { RenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay { private readonly _context: ViewContext; private _lineHeight: number; private _renderLineHighlight: 'none' | 'gutter' | 'line' | 'all'; + private _contentLeft: number; private _selectionIsEmpty: boolean; private _primaryCursorLineNumber: number; - private _contentLeft: number; constructor(context: ViewContext) { super(); this._context = context; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._renderLineHighlight = this._context.configuration.editor.viewInfo.renderLineHighlight; + + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._renderLineHighlight = options.get(EditorOption.renderLineHighlight); + this._contentLeft = layoutInfo.contentLeft; this._selectionIsEmpty = true; this._primaryCursorLineNumber = 1; - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; this._context.addEventHandler(this); } @@ -40,15 +46,12 @@ export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.viewInfo) { - this._renderLineHighlight = this._context.configuration.editor.viewInfo.renderLineHighlight; - } - if (e.layoutInfo) { - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; - } + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._renderLineHighlight = options.get(EditorOption.renderLineHighlight); + this._contentLeft = layoutInfo.contentLeft; return true; } public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { diff --git a/src/vs/editor/browser/viewParts/decorations/decorations.ts b/src/vs/editor/browser/viewParts/decorations/decorations.ts index 0716cc3b4e1..7ba28975519 100644 --- a/src/vs/editor/browser/viewParts/decorations/decorations.ts +++ b/src/vs/editor/browser/viewParts/decorations/decorations.ts @@ -10,6 +10,7 @@ import { HorizontalRange, RenderingContext } from 'vs/editor/common/view/renderi import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class DecorationsOverlay extends DynamicViewOverlay { @@ -21,8 +22,9 @@ export class DecorationsOverlay extends DynamicViewOverlay { constructor(context: ViewContext) { super(); this._context = context; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; + const options = this._context.configuration.options; + this._lineHeight = options.get(EditorOption.lineHeight); + this._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; this._renderResult = null; this._context.addEventHandler(this); @@ -37,12 +39,9 @@ export class DecorationsOverlay extends DynamicViewOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.fontInfo) { - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; - } + const options = this._context.configuration.options; + this._lineHeight = options.get(EditorOption.lineHeight); + this._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; return true; } public onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean { diff --git a/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts b/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts index d9b8c4dfd8f..d816f1265e8 100644 --- a/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts +++ b/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts @@ -14,6 +14,7 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { getThemeTypeSelector } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class EditorScrollbar extends ViewPart { @@ -28,8 +29,11 @@ export class EditorScrollbar extends ViewPart { ) { super(context); - const editor = this._context.configuration.editor; - const configScrollbarOpts = editor.viewInfo.scrollbar; + + const options = this._context.configuration.options; + const scrollbar = options.get(EditorOption.scrollbar); + const mouseWheelScrollSensitivity = options.get(EditorOption.mouseWheelScrollSensitivity); + const fastScrollSensitivity = options.get(EditorOption.fastScrollSensitivity); const scrollbarOptions: ScrollableElementCreationOptions = { listenOnDomNode: viewDomNode.domNode, @@ -37,18 +41,18 @@ export class EditorScrollbar extends ViewPart { useShadows: false, lazyRender: true, - vertical: configScrollbarOpts.vertical, - horizontal: configScrollbarOpts.horizontal, - verticalHasArrows: configScrollbarOpts.verticalHasArrows, - horizontalHasArrows: configScrollbarOpts.horizontalHasArrows, - verticalScrollbarSize: configScrollbarOpts.verticalScrollbarSize, - verticalSliderSize: configScrollbarOpts.verticalSliderSize, - horizontalScrollbarSize: configScrollbarOpts.horizontalScrollbarSize, - horizontalSliderSize: configScrollbarOpts.horizontalSliderSize, - handleMouseWheel: configScrollbarOpts.handleMouseWheel, - arrowSize: configScrollbarOpts.arrowSize, - mouseWheelScrollSensitivity: configScrollbarOpts.mouseWheelScrollSensitivity, - fastScrollSensitivity: configScrollbarOpts.fastScrollSensitivity, + vertical: scrollbar.vertical, + horizontal: scrollbar.horizontal, + verticalHasArrows: scrollbar.verticalHasArrows, + horizontalHasArrows: scrollbar.horizontalHasArrows, + verticalScrollbarSize: scrollbar.verticalScrollbarSize, + verticalSliderSize: scrollbar.verticalSliderSize, + horizontalScrollbarSize: scrollbar.horizontalScrollbarSize, + horizontalSliderSize: scrollbar.horizontalSliderSize, + handleMouseWheel: scrollbar.handleMouseWheel, + arrowSize: scrollbar.arrowSize, + mouseWheelScrollSensitivity: mouseWheelScrollSensitivity, + fastScrollSensitivity: fastScrollSensitivity, }; this.scrollbar = this._register(new SmoothScrollableElement(linesContent.domNode, scrollbarOptions, this._context.viewLayout.scrollable)); @@ -96,11 +100,13 @@ export class EditorScrollbar extends ViewPart { } private _setLayout(): void { - const layoutInfo = this._context.configuration.editor.layoutInfo; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); this.scrollbarDomNode.setLeft(layoutInfo.contentLeft); - const side = this._context.configuration.editor.viewInfo.minimap.side; + const minimap = options.get(EditorOption.minimap); + const side = minimap.side; if (side === 'right') { this.scrollbarDomNode.setWidth(layoutInfo.contentWidth + layoutInfo.minimapWidth); } else { @@ -124,16 +130,23 @@ export class EditorScrollbar extends ViewPart { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.viewInfo) { - const editor = this._context.configuration.editor; + if ( + e.hasChanged(EditorOption.scrollbar) + || e.hasChanged(EditorOption.mouseWheelScrollSensitivity) + || e.hasChanged(EditorOption.fastScrollSensitivity) + ) { + const options = this._context.configuration.options; + const scrollbar = options.get(EditorOption.scrollbar); + const mouseWheelScrollSensitivity = options.get(EditorOption.mouseWheelScrollSensitivity); + const fastScrollSensitivity = options.get(EditorOption.fastScrollSensitivity); const newOpts: ScrollableElementChangeOptions = { - handleMouseWheel: editor.viewInfo.scrollbar.handleMouseWheel, - mouseWheelScrollSensitivity: editor.viewInfo.scrollbar.mouseWheelScrollSensitivity, - fastScrollSensitivity: editor.viewInfo.scrollbar.fastScrollSensitivity + handleMouseWheel: scrollbar.handleMouseWheel, + mouseWheelScrollSensitivity: mouseWheelScrollSensitivity, + fastScrollSensitivity: fastScrollSensitivity }; this.scrollbar.updateOptions(newOpts); } - if (e.layoutInfo) { + if (e.hasChanged(EditorOption.layoutInfo)) { this._setLayout(); } return true; diff --git a/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts index 60c18790d0c..494b7d7ca23 100644 --- a/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts +++ b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts @@ -8,6 +8,8 @@ import { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay'; import { RenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class DecorationToRender { _decorationToRenderBrand: void; @@ -84,10 +86,14 @@ export class GlyphMarginOverlay extends DedupOverlay { constructor(context: ViewContext) { super(); this._context = context; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._glyphMargin = this._context.configuration.editor.viewInfo.glyphMargin; - this._glyphMarginLeft = this._context.configuration.editor.layoutInfo.glyphMarginLeft; - this._glyphMarginWidth = this._context.configuration.editor.layoutInfo.glyphMarginWidth; + + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._glyphMargin = options.get(EditorOption.glyphMargin); + this._glyphMarginLeft = layoutInfo.glyphMarginLeft; + this._glyphMarginWidth = layoutInfo.glyphMarginWidth; this._renderResult = null; this._context.addEventHandler(this); } @@ -101,16 +107,13 @@ export class GlyphMarginOverlay extends DedupOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.viewInfo) { - this._glyphMargin = this._context.configuration.editor.viewInfo.glyphMargin; - } - if (e.layoutInfo) { - this._glyphMarginLeft = this._context.configuration.editor.layoutInfo.glyphMarginLeft; - this._glyphMarginWidth = this._context.configuration.editor.layoutInfo.glyphMarginWidth; - } + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._glyphMargin = options.get(EditorOption.glyphMargin); + this._glyphMarginLeft = layoutInfo.glyphMarginLeft; + this._glyphMarginWidth = layoutInfo.glyphMarginWidth; return true; } public onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean { diff --git a/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts b/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts index ea713746e0d..6af61888a62 100644 --- a/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts +++ b/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts @@ -11,6 +11,8 @@ import { RenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class IndentGuidesOverlay extends DynamicViewOverlay { @@ -27,12 +29,16 @@ export class IndentGuidesOverlay extends DynamicViewOverlay { super(); this._context = context; this._primaryLineNumber = 0; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._spaceWidth = this._context.configuration.editor.fontInfo.spaceWidth; - this._enabled = this._context.configuration.editor.viewInfo.renderIndentGuides; - this._activeIndentEnabled = this._context.configuration.editor.viewInfo.highlightActiveIndentGuide; - const wrappingColumn = this._context.configuration.editor.wrappingInfo.wrappingColumn; - this._maxIndentLeft = wrappingColumn === -1 ? -1 : (wrappingColumn * this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth); + + const options = this._context.configuration.options; + const wrappingInfo = options.get(EditorOption.wrappingInfo); + const fontInfo = options.get(EditorOption.fontInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._spaceWidth = fontInfo.spaceWidth; + this._enabled = options.get(EditorOption.renderIndentGuides); + this._activeIndentEnabled = options.get(EditorOption.highlightActiveIndentGuide); + this._maxIndentLeft = wrappingInfo.wrappingColumn === -1 ? -1 : (wrappingInfo.wrappingColumn * fontInfo.typicalHalfwidthCharacterWidth); this._renderResult = null; @@ -48,20 +54,15 @@ export class IndentGuidesOverlay extends DynamicViewOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.fontInfo) { - this._spaceWidth = this._context.configuration.editor.fontInfo.spaceWidth; - } - if (e.viewInfo) { - this._enabled = this._context.configuration.editor.viewInfo.renderIndentGuides; - this._activeIndentEnabled = this._context.configuration.editor.viewInfo.highlightActiveIndentGuide; - } - if (e.wrappingInfo || e.fontInfo) { - const wrappingColumn = this._context.configuration.editor.wrappingInfo.wrappingColumn; - this._maxIndentLeft = wrappingColumn === -1 ? -1 : (wrappingColumn * this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth); - } + const options = this._context.configuration.options; + const wrappingInfo = options.get(EditorOption.wrappingInfo); + const fontInfo = options.get(EditorOption.fontInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._spaceWidth = fontInfo.spaceWidth; + this._enabled = options.get(EditorOption.renderIndentGuides); + this._activeIndentEnabled = options.get(EditorOption.highlightActiveIndentGuide); + this._maxIndentLeft = wrappingInfo.wrappingColumn === -1 ? -1 : (wrappingInfo.wrappingColumn * fontInfo.typicalHalfwidthCharacterWidth); return true; } public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { diff --git a/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts b/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts index 3e9b2d6c68b..ccf43d5b694 100644 --- a/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts +++ b/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts @@ -6,7 +6,7 @@ import 'vs/css!./lineNumbers'; import * as platform from 'vs/base/common/platform'; import { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay'; -import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions'; +import { RenderLineNumbersType, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { editorActiveLineNumber, editorLineNumbers } from 'vs/editor/common/view/editorColorRegistry'; import { RenderingContext } from 'vs/editor/common/view/renderingContext'; @@ -41,13 +41,15 @@ export class LineNumbersOverlay extends DynamicViewOverlay { } private _readConfig(): void { - const config = this._context.configuration.editor; - this._lineHeight = config.lineHeight; - this._renderLineNumbers = config.viewInfo.renderLineNumbers; - this._renderCustomLineNumbers = config.viewInfo.renderCustomLineNumbers; - this._renderFinalNewline = config.viewInfo.renderFinalNewline; - this._lineNumbersLeft = config.layoutInfo.lineNumbersLeft; - this._lineNumbersWidth = config.layoutInfo.lineNumbersWidth; + const options = this._context.configuration.options; + this._lineHeight = options.get(EditorOption.lineHeight); + const lineNumbers = options.get(EditorOption.lineNumbers); + this._renderLineNumbers = lineNumbers.renderType; + this._renderCustomLineNumbers = lineNumbers.renderFn; + this._renderFinalNewline = options.get(EditorOption.renderFinalNewline); + const layoutInfo = options.get(EditorOption.layoutInfo); + this._lineNumbersLeft = layoutInfo.lineNumbersLeft; + this._lineNumbersWidth = layoutInfo.lineNumbersWidth; } public dispose(): void { diff --git a/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts index 00b684e7ef4..4e0016d5fac 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLine.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLine.ts @@ -16,6 +16,7 @@ import { CharacterMapping, ForeignElementType, RenderLineInput, renderViewLine, import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel'; import { HIGH_CONTRAST, ThemeType } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const canUseFastRenderedViewLine = (function () { if (platform.isNative) { @@ -80,17 +81,20 @@ export class ViewLineOptions { constructor(config: IConfiguration, themeType: ThemeType) { this.themeType = themeType; - this.renderWhitespace = config.editor.viewInfo.renderWhitespace; - this.renderControlCharacters = config.editor.viewInfo.renderControlCharacters; - this.spaceWidth = config.editor.fontInfo.spaceWidth; + const options = config.options; + const fontInfo = options.get(EditorOption.fontInfo); + this.renderWhitespace = options.get(EditorOption.renderWhitespace); + this.renderControlCharacters = options.get(EditorOption.renderControlCharacters); + this.spaceWidth = fontInfo.spaceWidth; this.useMonospaceOptimizations = ( - config.editor.fontInfo.isMonospace - && !config.editor.viewInfo.disableMonospaceOptimizations + fontInfo.isMonospace + && !options.get(EditorOption.disableMonospaceOptimizations) + && !options.get(EditorOption.fontLigatures) ); - this.canUseHalfwidthRightwardsArrow = config.editor.fontInfo.canUseHalfwidthRightwardsArrow; - this.lineHeight = config.editor.lineHeight; - this.stopRenderingLineAfter = config.editor.viewInfo.stopRenderingLineAfter; - this.fontLigatures = config.editor.viewInfo.fontLigatures; + this.canUseHalfwidthRightwardsArrow = fontInfo.canUseHalfwidthRightwardsArrow; + this.lineHeight = options.get(EditorOption.lineHeight); + this.stopRenderingLineAfter = options.get(EditorOption.stopRenderingLineAfter); + this.fontLigatures = options.get(EditorOption.fontLigatures); } public equals(other: ViewLineOptions): boolean { diff --git a/src/vs/editor/browser/viewParts/lines/viewLines.ts b/src/vs/editor/browser/viewParts/lines/viewLines.ts index 64e82241b4d..eb524a41b69 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLines.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLines.ts @@ -19,6 +19,7 @@ import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { Viewport } from 'vs/editor/common/viewModel/viewModel'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; class LastRenderedData { @@ -73,7 +74,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, private _isViewportWrapping: boolean; private _revealHorizontalRightPadding: number; private _selections: Selection[]; - private _scrollOff: number; + private _cursorSurroundingLines: number; private _canUseLayerHinting: boolean; private _viewLineOptions: ViewLineOptions; @@ -92,19 +93,22 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, this.domNode = this._visibleLines.domNode; const conf = this._context.configuration; + const options = this._context.configuration.options; + const fontInfo = options.get(EditorOption.fontInfo); + const wrappingInfo = options.get(EditorOption.wrappingInfo); - this._lineHeight = conf.editor.lineHeight; - this._typicalHalfwidthCharacterWidth = conf.editor.fontInfo.typicalHalfwidthCharacterWidth; - this._isViewportWrapping = conf.editor.wrappingInfo.isViewportWrapping; - this._revealHorizontalRightPadding = conf.editor.viewInfo.revealHorizontalRightPadding; - this._scrollOff = conf.editor.viewInfo.cursorSurroundingLines; - this._canUseLayerHinting = conf.editor.canUseLayerHinting; + this._lineHeight = options.get(EditorOption.lineHeight); + this._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; + this._isViewportWrapping = wrappingInfo.isViewportWrapping; + this._revealHorizontalRightPadding = options.get(EditorOption.revealHorizontalRightPadding); + this._cursorSurroundingLines = options.get(EditorOption.cursorSurroundingLines); + this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting); this._viewLineOptions = new ViewLineOptions(conf, this._context.theme.type); this._selections = []; PartFingerprints.write(this.domNode, PartFingerprint.ViewLines); this.domNode.setClassName('view-lines'); - Configuration.applyFontInfo(this.domNode, conf.editor.fontInfo); + Configuration.applyFontInfo(this.domNode, fontInfo); // --- width & height this._maxLineWidth = 0; @@ -138,35 +142,25 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { this._visibleLines.onConfigurationChanged(e); - if (e.wrappingInfo) { + if (e.hasChanged(EditorOption.wrappingInfo)) { this._maxLineWidth = 0; } - const conf = this._context.configuration; + const options = this._context.configuration.options; + const fontInfo = options.get(EditorOption.fontInfo); + const wrappingInfo = options.get(EditorOption.wrappingInfo); - if (e.lineHeight) { - this._lineHeight = conf.editor.lineHeight; - } - if (e.fontInfo) { - this._typicalHalfwidthCharacterWidth = conf.editor.fontInfo.typicalHalfwidthCharacterWidth; - } - if (e.wrappingInfo) { - this._isViewportWrapping = conf.editor.wrappingInfo.isViewportWrapping; - } - if (e.viewInfo) { - this._revealHorizontalRightPadding = conf.editor.viewInfo.revealHorizontalRightPadding; - this._scrollOff = conf.editor.viewInfo.cursorSurroundingLines; - } - if (e.canUseLayerHinting) { - this._canUseLayerHinting = conf.editor.canUseLayerHinting; - } - if (e.fontInfo) { - Configuration.applyFontInfo(this.domNode, conf.editor.fontInfo); - } + this._lineHeight = options.get(EditorOption.lineHeight); + this._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; + this._isViewportWrapping = wrappingInfo.isViewportWrapping; + this._revealHorizontalRightPadding = options.get(EditorOption.revealHorizontalRightPadding); + this._cursorSurroundingLines = options.get(EditorOption.cursorSurroundingLines); + this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting); + Configuration.applyFontInfo(this.domNode, fontInfo); this._onOptionsMaybeChanged(); - if (e.layoutInfo) { + if (e.hasChanged(EditorOption.layoutInfo)) { this._maxLineWidth = 0; } @@ -610,7 +604,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, ); if (!shouldIgnoreScrollOff) { - const context = Math.min((viewportHeight / this._lineHeight) / 2, this._scrollOff); + const context = Math.min((viewportHeight / this._lineHeight) / 2, this._cursorSurroundingLines); boxStartY -= context * this._lineHeight; boxEndY += Math.max(0, (context - 1)) * this._lineHeight; } diff --git a/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts index fe764290bad..fc6a255eb83 100644 --- a/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts +++ b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts @@ -8,6 +8,8 @@ import { DecorationToRender, DedupOverlay } from 'vs/editor/browser/viewParts/gl import { RenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class LinesDecorationsOverlay extends DedupOverlay { @@ -20,8 +22,10 @@ export class LinesDecorationsOverlay extends DedupOverlay { constructor(context: ViewContext) { super(); this._context = context; - this._decorationsLeft = this._context.configuration.editor.layoutInfo.decorationsLeft; - this._decorationsWidth = this._context.configuration.editor.layoutInfo.decorationsWidth; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this._decorationsLeft = layoutInfo.decorationsLeft; + this._decorationsWidth = layoutInfo.decorationsWidth; this._renderResult = null; this._context.addEventHandler(this); } @@ -35,10 +39,10 @@ export class LinesDecorationsOverlay extends DedupOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.layoutInfo) { - this._decorationsLeft = this._context.configuration.editor.layoutInfo.decorationsLeft; - this._decorationsWidth = this._context.configuration.editor.layoutInfo.decorationsWidth; - } + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this._decorationsLeft = layoutInfo.decorationsLeft; + this._decorationsWidth = layoutInfo.decorationsWidth; return true; } public onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean { @@ -107,4 +111,4 @@ export class LinesDecorationsOverlay extends DedupOverlay { } return this._renderResult[lineNumber - startLineNumber]; } -} \ No newline at end of file +} diff --git a/src/vs/editor/browser/viewParts/margin/margin.ts b/src/vs/editor/browser/viewParts/margin/margin.ts index ab4f24c7bf3..1208e3c56c9 100644 --- a/src/vs/editor/browser/viewParts/margin/margin.ts +++ b/src/vs/editor/browser/viewParts/margin/margin.ts @@ -8,6 +8,8 @@ import { ViewPart } from 'vs/editor/browser/view/viewPart'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class Margin extends ViewPart { @@ -23,10 +25,13 @@ export class Margin extends ViewPart { constructor(context: ViewContext) { super(context); - this._canUseLayerHinting = this._context.configuration.editor.canUseLayerHinting; - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; - this._glyphMarginLeft = this._context.configuration.editor.layoutInfo.glyphMarginLeft; - this._glyphMarginWidth = this._context.configuration.editor.layoutInfo.glyphMarginWidth; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting); + this._contentLeft = layoutInfo.contentLeft; + this._glyphMarginLeft = layoutInfo.glyphMarginLeft; + this._glyphMarginWidth = layoutInfo.glyphMarginWidth; this._domNode = createFastDomNode(document.createElement('div')); this._domNode.setClassName(Margin.OUTER_CLASS_NAME); @@ -51,15 +56,13 @@ export class Margin extends ViewPart { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.canUseLayerHinting) { - this._canUseLayerHinting = this._context.configuration.editor.canUseLayerHinting; - } + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); - if (e.layoutInfo) { - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; - this._glyphMarginLeft = this._context.configuration.editor.layoutInfo.glyphMarginLeft; - this._glyphMarginWidth = this._context.configuration.editor.layoutInfo.glyphMarginWidth; - } + this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting); + this._contentLeft = layoutInfo.contentLeft; + this._glyphMarginLeft = layoutInfo.glyphMarginLeft; + this._glyphMarginWidth = layoutInfo.glyphMarginWidth; return true; } diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 1ef327eaee0..d7fb6e54408 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -13,7 +13,7 @@ import * as platform from 'vs/base/common/platform'; import * as strings from 'vs/base/common/strings'; import { ILine, RenderedLinesCollection } from 'vs/editor/browser/view/viewLayer'; import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart'; -import { RenderMinimap } from 'vs/editor/common/config/editorOptions'; +import { RenderMinimap, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Range } from 'vs/editor/common/core/range'; import { RGBA8 } from 'vs/editor/common/core/rgba'; import { IConfiguration, ScrollType } from 'vs/editor/common/editorCommon'; @@ -107,17 +107,18 @@ class MinimapOptions { public readonly canvasOuterHeight: number; constructor(configuration: IConfiguration) { - const pixelRatio = configuration.editor.pixelRatio; - const layoutInfo = configuration.editor.layoutInfo; - const viewInfo = configuration.editor.viewInfo; - const fontInfo = configuration.editor.fontInfo; + const options = configuration.options; + const pixelRatio = options.get(EditorOption.pixelRatio); + const layoutInfo = options.get(EditorOption.layoutInfo); + const fontInfo = options.get(EditorOption.fontInfo); this.renderMinimap = layoutInfo.renderMinimap | 0; - this.scrollBeyondLastLine = viewInfo.scrollBeyondLastLine; - this.showSlider = viewInfo.minimap.showSlider; + this.scrollBeyondLastLine = options.get(EditorOption.scrollBeyondLastLine); + const minimapOpts = options.get(EditorOption.minimap); + this.showSlider = minimapOpts.showSlider; this.pixelRatio = pixelRatio; this.typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; - this.lineHeight = configuration.editor.lineHeight; + this.lineHeight = options.get(EditorOption.lineHeight); this.minimapLeft = layoutInfo.minimapLeft; this.minimapWidth = layoutInfo.minimapWidth; this.minimapHeight = layoutInfo.height; diff --git a/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts b/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts index 87a35ca24f2..925ed44d28a 100644 --- a/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts +++ b/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts @@ -10,6 +10,8 @@ import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/v import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + interface IWidgetData { widget: IOverlayWidget; @@ -35,12 +37,15 @@ export class ViewOverlayWidgets extends ViewPart { constructor(context: ViewContext) { super(context); + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + this._widgets = {}; - this._verticalScrollbarWidth = this._context.configuration.editor.layoutInfo.verticalScrollbarWidth; - this._minimapWidth = this._context.configuration.editor.layoutInfo.minimapWidth; - this._horizontalScrollbarHeight = this._context.configuration.editor.layoutInfo.horizontalScrollbarHeight; - this._editorHeight = this._context.configuration.editor.layoutInfo.height; - this._editorWidth = this._context.configuration.editor.layoutInfo.width; + this._verticalScrollbarWidth = layoutInfo.verticalScrollbarWidth; + this._minimapWidth = layoutInfo.minimapWidth; + this._horizontalScrollbarHeight = layoutInfo.horizontalScrollbarHeight; + this._editorHeight = layoutInfo.height; + this._editorWidth = layoutInfo.width; this._domNode = createFastDomNode(document.createElement('div')); PartFingerprints.write(this._domNode, PartFingerprint.OverlayWidgets); @@ -59,15 +64,15 @@ export class ViewOverlayWidgets extends ViewPart { // ---- begin view event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.layoutInfo) { - this._verticalScrollbarWidth = this._context.configuration.editor.layoutInfo.verticalScrollbarWidth; - this._minimapWidth = this._context.configuration.editor.layoutInfo.minimapWidth; - this._horizontalScrollbarHeight = this._context.configuration.editor.layoutInfo.horizontalScrollbarHeight; - this._editorHeight = this._context.configuration.editor.layoutInfo.height; - this._editorWidth = this._context.configuration.editor.layoutInfo.width; - return true; - } - return false; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._verticalScrollbarWidth = layoutInfo.verticalScrollbarWidth; + this._minimapWidth = layoutInfo.minimapWidth; + this._horizontalScrollbarHeight = layoutInfo.horizontalScrollbarHeight; + this._editorHeight = layoutInfo.height; + this._editorWidth = layoutInfo.width; + return true; } // ---- end view event handlers diff --git a/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts b/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts index c186568ad8f..a4e988745cb 100644 --- a/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts +++ b/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts @@ -15,6 +15,7 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ITheme } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; class Settings { @@ -42,22 +43,24 @@ class Settings { public readonly w: number[]; constructor(config: IConfiguration, theme: ITheme) { - this.lineHeight = config.editor.lineHeight; - this.pixelRatio = config.editor.pixelRatio; - this.overviewRulerLanes = config.editor.viewInfo.overviewRulerLanes; + const options = config.options; + this.lineHeight = options.get(EditorOption.lineHeight); + this.pixelRatio = options.get(EditorOption.pixelRatio); + this.overviewRulerLanes = options.get(EditorOption.overviewRulerLanes); - this.renderBorder = config.editor.viewInfo.overviewRulerBorder; + this.renderBorder = options.get(EditorOption.overviewRulerBorder); const borderColor = theme.getColor(editorOverviewRulerBorder); this.borderColor = borderColor ? borderColor.toString() : null; - this.hideCursor = config.editor.viewInfo.hideCursorInOverviewRuler; + this.hideCursor = options.get(EditorOption.hideCursorInOverviewRuler); const cursorColor = theme.getColor(editorCursorForeground); this.cursorColor = cursorColor ? cursorColor.transparent(0.7).toString() : null; this.themeType = theme.type; - const minimapEnabled = config.editor.viewInfo.minimap.enabled; - const minimapSide = config.editor.viewInfo.minimap.side; + const minimapOpts = options.get(EditorOption.minimap); + const minimapEnabled = minimapOpts.enabled; + const minimapSide = minimapOpts.side; const backgroundColor = (minimapEnabled ? TokenizationRegistry.getDefaultBackground() : null); if (backgroundColor === null || minimapSide === 'left') { this.backgroundColor = null; @@ -65,7 +68,8 @@ class Settings { this.backgroundColor = Color.Format.CSS.formatHex(backgroundColor); } - const position = config.editor.layoutInfo.overviewRuler; + const layoutInfo = options.get(EditorOption.layoutInfo); + const position = layoutInfo.overviewRuler; this.top = position.top; this.right = position.right; this.domWidth = position.width; diff --git a/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts b/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts index 4b164f01c6b..7b9ef090d2a 100644 --- a/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts +++ b/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts @@ -5,7 +5,7 @@ import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { IOverviewRuler } from 'vs/editor/browser/editorBrowser'; -import { OverviewRulerPosition } from 'vs/editor/common/config/editorOptions'; +import { OverviewRulerPosition, EditorOption } from 'vs/editor/common/config/editorOptions'; import { ColorZone, OverviewRulerZone, OverviewZoneManager } from 'vs/editor/common/view/overviewZoneManager'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; @@ -20,6 +20,7 @@ export class OverviewRuler extends ViewEventHandler implements IOverviewRuler { constructor(context: ViewContext, cssClassName: string) { super(); this._context = context; + const options = this._context.configuration.options; this._domNode = createFastDomNode(document.createElement('canvas')); this._domNode.setClassName(cssClassName); @@ -30,9 +31,9 @@ export class OverviewRuler extends ViewEventHandler implements IOverviewRuler { this._zoneManager.setDOMWidth(0); this._zoneManager.setDOMHeight(0); this._zoneManager.setOuterHeight(this._context.viewLayout.getScrollHeight()); - this._zoneManager.setLineHeight(this._context.configuration.editor.lineHeight); + this._zoneManager.setLineHeight(options.get(EditorOption.lineHeight)); - this._zoneManager.setPixelRatio(this._context.configuration.editor.pixelRatio); + this._zoneManager.setPixelRatio(options.get(EditorOption.pixelRatio)); this._context.addEventHandler(this); } @@ -45,13 +46,15 @@ export class OverviewRuler extends ViewEventHandler implements IOverviewRuler { // ---- begin view event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._zoneManager.setLineHeight(this._context.configuration.editor.lineHeight); + const options = this._context.configuration.options; + + if (e.hasChanged(EditorOption.lineHeight)) { + this._zoneManager.setLineHeight(options.get(EditorOption.lineHeight)); this._render(); } - if (e.pixelRatio) { - this._zoneManager.setPixelRatio(this._context.configuration.editor.pixelRatio); + if (e.hasChanged(EditorOption.pixelRatio)) { + this._zoneManager.setPixelRatio(options.get(EditorOption.pixelRatio)); this._domNode.setWidth(this._zoneManager.getDOMWidth()); this._domNode.setHeight(this._zoneManager.getDOMHeight()); this._domNode.domNode.width = this._zoneManager.getCanvasWidth(); diff --git a/src/vs/editor/browser/viewParts/rulers/rulers.ts b/src/vs/editor/browser/viewParts/rulers/rulers.ts index 7d4d402d24e..0f22de06a73 100644 --- a/src/vs/editor/browser/viewParts/rulers/rulers.ts +++ b/src/vs/editor/browser/viewParts/rulers/rulers.ts @@ -11,6 +11,7 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class Rulers extends ViewPart { @@ -26,8 +27,9 @@ export class Rulers extends ViewPart { this.domNode.setAttribute('aria-hidden', 'true'); this.domNode.setClassName('view-rulers'); this._renderedRulers = []; - this._rulers = this._context.configuration.editor.viewInfo.rulers; - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; + const options = this._context.configuration.options; + this._rulers = options.get(EditorOption.rulers); + this._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; } public dispose(): void { @@ -37,12 +39,10 @@ export class Rulers extends ViewPart { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.viewInfo || e.layoutInfo || e.fontInfo) { - this._rulers = this._context.configuration.editor.viewInfo.rulers; - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; - return true; - } - return false; + const options = this._context.configuration.options; + this._rulers = options.get(EditorOption.rulers); + this._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; + return true; } public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { return e.scrollHeightChanged; diff --git a/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts b/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts index 2ae336437e4..8adefd837dd 100644 --- a/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts +++ b/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts @@ -11,6 +11,8 @@ import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { scrollbarShadow } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export class ScrollDecorationViewPart extends ViewPart { @@ -27,7 +29,9 @@ export class ScrollDecorationViewPart extends ViewPart { this._width = 0; this._updateWidth(); this._shouldShow = false; - this._useShadows = this._context.configuration.editor.viewInfo.scrollbar.useShadows; + const options = this._context.configuration.options; + const scrollbar = options.get(EditorOption.scrollbar); + this._useShadows = scrollbar.useShadows; this._domNode = createFastDomNode(document.createElement('div')); this._domNode.setAttribute('role', 'presentation'); this._domNode.setAttribute('aria-hidden', 'true'); @@ -50,32 +54,26 @@ export class ScrollDecorationViewPart extends ViewPart { return this._domNode; } - private _updateWidth(): boolean { - const layoutInfo = this._context.configuration.editor.layoutInfo; - let newWidth = 0; + private _updateWidth(): void { + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + if (layoutInfo.renderMinimap === 0 || (layoutInfo.minimapWidth > 0 && layoutInfo.minimapLeft === 0)) { - newWidth = layoutInfo.width; + this._width = layoutInfo.width; } else { - newWidth = layoutInfo.width - layoutInfo.minimapWidth - layoutInfo.verticalScrollbarWidth; + this._width = layoutInfo.width - layoutInfo.minimapWidth - layoutInfo.verticalScrollbarWidth; } - if (this._width !== newWidth) { - this._width = newWidth; - return true; - } - return false; } // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - let shouldRender = false; - if (e.viewInfo) { - this._useShadows = this._context.configuration.editor.viewInfo.scrollbar.useShadows; - } - if (e.layoutInfo) { - shouldRender = this._updateWidth(); - } - return this._updateShouldShow() || shouldRender; + const options = this._context.configuration.options; + const scrollbar = options.get(EditorOption.scrollbar); + this._useShadows = scrollbar.useShadows; + this._updateWidth(); + this._updateShouldShow(); + return true; } public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { this._scrollTop = e.scrollTop; @@ -99,4 +97,4 @@ registerThemingParticipant((theme, collector) => { if (shadow) { collector.addRule(`.monaco-editor .scroll-decoration { box-shadow: ${shadow} 0 6px 6px -6px inset; }`); } -}); \ No newline at end of file +}); diff --git a/src/vs/editor/browser/viewParts/selections/selections.ts b/src/vs/editor/browser/viewParts/selections/selections.ts index 3ee089a3d94..f059e95dbb1 100644 --- a/src/vs/editor/browser/viewParts/selections/selections.ts +++ b/src/vs/editor/browser/viewParts/selections/selections.ts @@ -12,6 +12,7 @@ import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { editorInactiveSelection, editorSelectionBackground, editorSelectionForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const enum CornerStyle { EXTERN, @@ -83,9 +84,10 @@ export class SelectionsOverlay extends DynamicViewOverlay { constructor(context: ViewContext) { super(); this._context = context; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._roundedSelection = this._context.configuration.editor.viewInfo.roundedSelection; - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; + const options = this._context.configuration.options; + this._lineHeight = options.get(EditorOption.lineHeight); + this._roundedSelection = options.get(EditorOption.roundedSelection); + this._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; this._selections = []; this._renderResult = null; this._context.addEventHandler(this); @@ -100,15 +102,10 @@ export class SelectionsOverlay extends DynamicViewOverlay { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.viewInfo) { - this._roundedSelection = this._context.configuration.editor.viewInfo.roundedSelection; - } - if (e.fontInfo) { - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; - } + const options = this._context.configuration.options; + this._lineHeight = options.get(EditorOption.lineHeight); + this._roundedSelection = options.get(EditorOption.roundedSelection); + this._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; return true; } public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { @@ -420,4 +417,4 @@ registerThemingParticipant((theme, collector) => { function abs(n: number): number { return n < 0 ? -n : n; -} \ No newline at end of file +} diff --git a/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts b/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts index 37105276557..09648af24a8 100644 --- a/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts +++ b/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts @@ -7,7 +7,7 @@ import * as dom from 'vs/base/browser/dom'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import * as strings from 'vs/base/common/strings'; import { Configuration } from 'vs/editor/browser/config/configuration'; -import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions'; +import { TextEditorCursorStyle, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; @@ -51,11 +51,13 @@ export class ViewCursor { constructor(context: ViewContext) { this._context = context; + const options = this._context.configuration.options; + const fontInfo = options.get(EditorOption.fontInfo); - this._cursorStyle = this._context.configuration.editor.viewInfo.cursorStyle; - this._lineHeight = this._context.configuration.editor.lineHeight; - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; - this._lineCursorWidth = Math.min(this._context.configuration.editor.viewInfo.cursorWidth, this._typicalHalfwidthCharacterWidth); + this._cursorStyle = options.get(EditorOption.cursorStyle); + this._lineHeight = options.get(EditorOption.lineHeight); + this._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; + this._lineCursorWidth = Math.min(options.get(EditorOption.cursorWidth), this._typicalHalfwidthCharacterWidth); this._isVisible = true; @@ -65,7 +67,7 @@ export class ViewCursor { this._domNode.setHeight(this._lineHeight); this._domNode.setTop(0); this._domNode.setLeft(0); - Configuration.applyFontInfo(this._domNode, this._context.configuration.editor.fontInfo); + Configuration.applyFontInfo(this._domNode, fontInfo); this._domNode.setDisplay('none'); this._position = new Position(1, 1); @@ -97,17 +99,14 @@ export class ViewCursor { } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - } - if (e.fontInfo) { - Configuration.applyFontInfo(this._domNode, this._context.configuration.editor.fontInfo); - this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; - } - if (e.viewInfo) { - this._cursorStyle = this._context.configuration.editor.viewInfo.cursorStyle; - this._lineCursorWidth = Math.min(this._context.configuration.editor.viewInfo.cursorWidth, this._typicalHalfwidthCharacterWidth); - } + const options = this._context.configuration.options; + const fontInfo = options.get(EditorOption.fontInfo); + + this._cursorStyle = options.get(EditorOption.cursorStyle); + this._lineHeight = options.get(EditorOption.lineHeight); + this._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; + this._lineCursorWidth = Math.min(options.get(EditorOption.cursorWidth), this._typicalHalfwidthCharacterWidth); + Configuration.applyFontInfo(this._domNode, fontInfo); return true; } diff --git a/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts b/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts index 023e031dd02..c60e020b56f 100644 --- a/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts +++ b/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts @@ -8,7 +8,7 @@ import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { IntervalTimer, TimeoutTimer } from 'vs/base/common/async'; import { ViewPart } from 'vs/editor/browser/view/viewPart'; import { IViewCursorRenderData, ViewCursor } from 'vs/editor/browser/viewParts/viewCursors/viewCursor'; -import { TextEditorCursorBlinkingStyle, TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions'; +import { TextEditorCursorBlinkingStyle, TextEditorCursorStyle, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { editorCursorBackground, editorCursorForeground } from 'vs/editor/common/view/editorColorRegistry'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; @@ -43,10 +43,11 @@ export class ViewCursors extends ViewPart { constructor(context: ViewContext) { super(context); - this._readOnly = this._context.configuration.editor.readOnly; - this._cursorBlinking = this._context.configuration.editor.viewInfo.cursorBlinking; - this._cursorStyle = this._context.configuration.editor.viewInfo.cursorStyle; - this._cursorSmoothCaretAnimation = this._context.configuration.editor.viewInfo.cursorSmoothCaretAnimation; + const options = this._context.configuration.options; + this._readOnly = options.get(EditorOption.readOnly); + this._cursorBlinking = options.get(EditorOption.cursorBlinking); + this._cursorStyle = options.get(EditorOption.cursorStyle); + this._cursorSmoothCaretAnimation = options.get(EditorOption.cursorSmoothCaretAnimation); this._selectionIsEmpty = true; this._isVisible = false; @@ -84,21 +85,17 @@ export class ViewCursors extends ViewPart { // --- begin event handlers public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { + const options = this._context.configuration.options; - if (e.readOnly) { - this._readOnly = this._context.configuration.editor.readOnly; - } - if (e.viewInfo) { - this._cursorBlinking = this._context.configuration.editor.viewInfo.cursorBlinking; - this._cursorStyle = this._context.configuration.editor.viewInfo.cursorStyle; - this._cursorSmoothCaretAnimation = this._context.configuration.editor.viewInfo.cursorSmoothCaretAnimation; - } + this._readOnly = options.get(EditorOption.readOnly); + this._cursorBlinking = options.get(EditorOption.cursorBlinking); + this._cursorStyle = options.get(EditorOption.cursorStyle); + this._cursorSmoothCaretAnimation = options.get(EditorOption.cursorSmoothCaretAnimation); + + this._updateBlinking(); + this._updateDomClassName(); this._primaryCursor.onConfigurationChanged(e); - this._updateBlinking(); - if (e.viewInfo) { - this._updateDomClassName(); - } for (let i = 0, len = this._secondaryCursors.length; i < len; i++) { this._secondaryCursors[i].onConfigurationChanged(e); } diff --git a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts index 6c01df4e0b6..6d7e1473089 100644 --- a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts +++ b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts @@ -12,6 +12,8 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + export interface IMyViewZone { whitespaceId: string; @@ -40,9 +42,12 @@ export class ViewZones extends ViewPart { constructor(context: ViewContext) { super(context); - this._lineHeight = this._context.configuration.editor.lineHeight; - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._lineHeight = options.get(EditorOption.lineHeight); + this._contentWidth = layoutInfo.contentWidth; + this._contentLeft = layoutInfo.contentLeft; this.domNode = createFastDomNode(document.createElement('div')); this.domNode.setClassName('view-zones'); @@ -84,15 +89,15 @@ export class ViewZones extends ViewPart { } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { + const options = this._context.configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); - if (e.lineHeight) { - this._lineHeight = this._context.configuration.editor.lineHeight; - return this._recomputeWhitespacesProps(); - } + this._lineHeight = options.get(EditorOption.lineHeight); + this._contentWidth = layoutInfo.contentWidth; + this._contentLeft = layoutInfo.contentLeft; - if (e.layoutInfo) { - this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; - this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; + if (e.hasChanged(EditorOption.lineHeight)) { + this._recomputeWhitespacesProps(); } return true; diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 55a23e500c0..4b7a1c37acc 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -23,7 +23,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService import { ICommandDelegate } from 'vs/editor/browser/view/viewController'; import { IContentWidgetData, IOverlayWidgetData, View } from 'vs/editor/browser/view/viewImpl'; import { ViewOutgoingEvents } from 'vs/editor/browser/view/viewOutgoingEvents'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById } from 'vs/editor/common/config/editorOptions'; import { Cursor, CursorStateChangedEvent } from 'vs/editor/common/controller/cursor'; import { CursorColumns, ICursors } from 'vs/editor/common/controller/cursorCommon'; import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -125,8 +125,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE private readonly _onDidChangeModelDecorations: Emitter = this._register(new Emitter()); public readonly onDidChangeModelDecorations: Event = this._onDidChangeModelDecorations.event; - private readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); - public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; + private readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); + public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; protected readonly _onDidChangeModel: Emitter = this._register(new Emitter()); public readonly onDidChangeModel: Event = this._onDidChangeModel.event; @@ -140,8 +140,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE private readonly _onDidAttemptReadOnlyEdit: Emitter = this._register(new Emitter()); public readonly onDidAttemptReadOnlyEdit: Event = this._onDidAttemptReadOnlyEdit.event; - private readonly _onDidLayoutChange: Emitter = this._register(new Emitter()); - public readonly onDidLayoutChange: Event = this._onDidLayoutChange.event; + private readonly _onDidLayoutChange: Emitter = this._register(new Emitter()); + public readonly onDidLayoutChange: Event = this._onDidLayoutChange.event; private readonly _editorTextFocus: BooleanEventEmitter = this._register(new BooleanEventEmitter()); public readonly onDidFocusEditorText: Event = this._editorTextFocus.onDidChangeToTrue; @@ -236,7 +236,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE constructor( domElement: HTMLElement, - options: editorOptions.IEditorOptions, + options: IEditorOptions, codeEditorWidgetOptions: ICodeEditorWidgetOptions, @IInstantiationService instantiationService: IInstantiationService, @ICodeEditorService codeEditorService: ICodeEditorService, @@ -259,10 +259,12 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._register(this._configuration.onDidChange((e) => { this._onDidChangeConfiguration.fire(e); - if (e.layoutInfo) { - this._onDidLayoutChange.fire(this._configuration.editor.layoutInfo); + const options = this._configuration.options; + if (e.hasChanged(EditorOption.layoutInfo)) { + const layoutInfo = options.get(EditorOption.layoutInfo); + this._onDidLayoutChange.fire(layoutInfo); } - if (this._configuration.editor.showUnused) { + if (options.get(EditorOption.showUnused)) { this._domElement.classList.add(SHOW_UNUSED_ENABLED_CLASS); } else { this._domElement.classList.remove(SHOW_UNUSED_ENABLED_CLASS); @@ -327,7 +329,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._codeEditorService.addCodeEditor(this); } - protected _createConfiguration(options: editorOptions.IEditorOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration { + protected _createConfiguration(options: IEditorOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration { return new Configuration(this.isSimpleWidget, options, this._domElement, accessibilityService); } @@ -362,15 +364,19 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return this._instantiationService.invokeFunction(fn); } - public updateOptions(newOptions: editorOptions.IEditorOptions): void { + public updateOptions(newOptions: IEditorOptions): void { this._configuration.updateOptions(newOptions); } - public getConfiguration(): editorOptions.InternalEditorOptions { - return this._configuration.editor; + public getOptions(): IComputedEditorOptions { + return this._configuration.options; } - public getRawConfiguration(): editorOptions.IEditorOptions { + public getOption(id: T): FindComputedEditorOptionValueById { + return this._configuration.options.get(id); + } + + public getRawOptions(): IEditorOptions { return this._configuration.getRawOptions(); } @@ -972,7 +978,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE if (!this._modelData) { return false; } - if (this._configuration.editor.readOnly) { + if (this._configuration.options.get(EditorOption.readOnly)) { // read only editor => sorry! return false; } @@ -984,7 +990,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE if (!this._modelData) { return false; } - if (this._configuration.editor.readOnly) { + if (this._configuration.options.get(EditorOption.readOnly)) { // read only editor => sorry! return false; } @@ -1028,7 +1034,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE if (!this._modelData) { return null; } - return this._modelData.model.getLineDecorations(lineNumber, this._id, this._configuration.editor.readOnly); + return this._modelData.model.getLineDecorations(lineNumber, this._id, this._configuration.options.get(EditorOption.readOnly)); } public deltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[] { @@ -1119,8 +1125,10 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } } - public getLayoutInfo(): editorOptions.EditorLayoutInfo { - return this._configuration.editor.layoutInfo; + public getLayoutInfo(): EditorLayoutInfo { + const options = this._configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + return layoutInfo; } public createOverviewRuler(cssClassName: string): editorBrowser.IOverviewRuler | null { @@ -1268,7 +1276,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } const position = this._modelData.model.validatePosition(rawPosition); - const layoutInfo = this._configuration.editor.layoutInfo; + const options = this._configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); const top = CodeEditorWidget._getVerticalOffsetForPosition(this._modelData, position.lineNumber, position.column) - this.getScrollTop(); const left = this._modelData.view.getOffsetForColumn(position.lineNumber, position.column) + layoutInfo.glyphMarginWidth + layoutInfo.lineNumbersWidth + layoutInfo.decorationsWidth - this.getScrollLeft(); @@ -1276,7 +1285,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return { top: top, left: left, - height: this._configuration.editor.lineHeight + height: options.get(EditorOption.lineHeight) }; } @@ -1295,7 +1304,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } public applyFontInfo(target: HTMLElement): void { - Configuration.applyFontInfoSlow(target, this._configuration.editor.fontInfo); + Configuration.applyFontInfoSlow(target, this._configuration.options.get(EditorOption.fontInfo)); } protected _attachModel(model: ITextModel | null): void { @@ -1601,10 +1610,10 @@ class EditorContextKeysManager extends Disposable { } private _updateFromConfig(): void { - const config = this._editor.getConfiguration(); + const options = this._editor.getOptions(); - this._editorTabMovesFocus.set(config.tabFocusMode); - this._editorReadonly.set(config.readOnly); + this._editorTabMovesFocus.set(options.get(EditorOption.tabFocusMode)); + this._editorReadonly.set(options.get(EditorOption.readOnly)); } private _updateFromSelection(): void { diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index 4a7bc112044..3762f7e0b13 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -20,7 +20,7 @@ import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffReview } from 'vs/editor/browser/widget/diffReview'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { IDiffEditorOptions, IEditorOptions, EditorLayoutInfo, IComputedEditorOptions, EditorOption, EditorOptions } from 'vs/editor/common/config/editorOptions'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; @@ -213,7 +213,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE constructor( domElement: HTMLElement, - options: editorOptions.IDiffEditorOptions, + options: IDiffEditorOptions, clipboardService: IClipboardService | null, @IEditorWorkerService editorWorkerService: IEditorWorkerService, @IContextKeyService contextKeyService: IContextKeyService, @@ -422,7 +422,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this._layoutOverviewRulers(); } - private _createLeftHandSideEditor(options: editorOptions.IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget { + private _createLeftHandSideEditor(options: IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget { const editor = this._createInnerEditor(instantiationService, this._originalDomNode, this._adjustOptionsForLeftHandSide(options, this._originalIsEditable)); this._register(editor.onDidScrollChange((e) => { @@ -455,7 +455,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return editor; } - private _createRightHandSideEditor(options: editorOptions.IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget { + private _createRightHandSideEditor(options: IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget { const editor = this._createInnerEditor(instantiationService, this._modifiedDomNode, this._adjustOptionsForRightHandSide(options)); this._register(editor.onDidScrollChange((e) => { @@ -480,7 +480,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE })); this._register(editor.onDidChangeConfiguration((e) => { - if (e.fontInfo && editor.getModel()) { + if (e.hasChanged(EditorOption.fontInfo) && editor.getModel()) { this._onViewZonesChanged(); } })); @@ -494,7 +494,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return editor; } - protected _createInnerEditor(instantiationService: IInstantiationService, container: HTMLElement, options: editorOptions.IEditorOptions): CodeEditorWidget { + protected _createInnerEditor(instantiationService: IInstantiationService, container: HTMLElement, options: IEditorOptions): CodeEditorWidget { return instantiationService.createInstance(CodeEditorWidget, container, options, {}); } @@ -568,7 +568,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return this.modifiedEditor; } - public updateOptions(newOptions: editorOptions.IDiffEditorOptions): void { + public updateOptions(newOptions: IDiffEditorOptions): void { // Handle side by side let renderSideBySideChanged = false; @@ -967,8 +967,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE } } - private _adjustOptionsForSubEditor(options: editorOptions.IDiffEditorOptions): editorOptions.IDiffEditorOptions { - let clonedOptions: editorOptions.IDiffEditorOptions = objects.deepClone(options || {}); + private _adjustOptionsForSubEditor(options: IDiffEditorOptions): IDiffEditorOptions { + let clonedOptions: IDiffEditorOptions = objects.deepClone(options || {}); clonedOptions.inDiffEditor = true; clonedOptions.wordWrap = 'off'; clonedOptions.wordWrapMinified = false; @@ -986,7 +986,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return clonedOptions; } - private _adjustOptionsForLeftHandSide(options: editorOptions.IDiffEditorOptions, isEditable: boolean): editorOptions.IEditorOptions { + private _adjustOptionsForLeftHandSide(options: IDiffEditorOptions, isEditable: boolean): IEditorOptions { let result = this._adjustOptionsForSubEditor(options); result.readOnly = !isEditable; result.overviewRulerLanes = 1; @@ -994,9 +994,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return result; } - private _adjustOptionsForRightHandSide(options: editorOptions.IDiffEditorOptions): editorOptions.IEditorOptions { + private _adjustOptionsForRightHandSide(options: IDiffEditorOptions): IEditorOptions { let result = this._adjustOptionsForSubEditor(options); - result.revealHorizontalRightPadding = editorOptions.EDITOR_DEFAULTS.viewInfo.revealHorizontalRightPadding + DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH; + result.revealHorizontalRightPadding = EditorOptions.revealHorizontalRightPadding.defaultValue + DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH; result.scrollbar!.verticalHasArrows = false; result.extraEditorClassName = 'modified-in-monaco-diff-editor'; return result; @@ -1830,7 +1830,7 @@ class DiffEditorWidgetInline extends DiffEditorWidgetStyle implements IDiffEdito this.decorationsLeft = dataSource.getOriginalEditor().getLayoutInfo().decorationsLeft; - this._register(dataSource.getOriginalEditor().onDidLayoutChange((layoutInfo: editorOptions.EditorLayoutInfo) => { + this._register(dataSource.getOriginalEditor().onDidLayoutChange((layoutInfo: EditorLayoutInfo) => { if (this.decorationsLeft !== layoutInfo.decorationsLeft) { this.decorationsLeft = layoutInfo.decorationsLeft; dataSource.relayoutEditors(); @@ -1946,14 +1946,14 @@ class DiffEditorWidgetInline extends DiffEditorWidgetStyle implements IDiffEdito class InlineViewZonesComputer extends ViewZonesComputer { private readonly originalModel: ITextModel; - private readonly modifiedEditorConfiguration: editorOptions.InternalEditorOptions; + private readonly modifiedEditorOptions: IComputedEditorOptions; private readonly modifiedEditorTabSize: number; private readonly renderIndicators: boolean; constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean) { super(lineChanges, originalForeignVZ, modifiedForeignVZ); this.originalModel = originalEditor.getModel()!; - this.modifiedEditorConfiguration = modifiedEditor.getConfiguration(); + this.modifiedEditorOptions = modifiedEditor.getOptions(); this.modifiedEditorTabSize = modifiedEditor.getModel()!.getOptions().tabSize; this.renderIndicators = renderIndicators; } @@ -1993,13 +1993,16 @@ class InlineViewZonesComputer extends ViewZonesComputer { let sb = createStringBuilder(10000); let marginHTML: string[] = []; - let lineDecorationsWidth = this.modifiedEditorConfiguration.layoutInfo.decorationsWidth; - let lineHeight = this.modifiedEditorConfiguration.lineHeight; - const typicalHalfwidthCharacterWidth = this.modifiedEditorConfiguration.fontInfo.typicalHalfwidthCharacterWidth; + const layoutInfo = this.modifiedEditorOptions.get(EditorOption.layoutInfo); + const fontInfo = this.modifiedEditorOptions.get(EditorOption.fontInfo); + const lineDecorationsWidth = layoutInfo.decorationsWidth; + + let lineHeight = this.modifiedEditorOptions.get(EditorOption.lineHeight); + const typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; let maxCharsPerLine = 0; const originalContent: string[] = []; for (let lineNumber = lineChange.originalStartLineNumber; lineNumber <= lineChange.originalEndLineNumber; lineNumber++) { - maxCharsPerLine = Math.max(maxCharsPerLine, this._renderOriginalLine(lineNumber - lineChange.originalStartLineNumber, this.originalModel, this.modifiedEditorConfiguration, this.modifiedEditorTabSize, lineNumber, decorations, sb)); + maxCharsPerLine = Math.max(maxCharsPerLine, this._renderOriginalLine(lineNumber - lineChange.originalStartLineNumber, this.originalModel, this.modifiedEditorOptions, this.modifiedEditorTabSize, lineNumber, decorations, sb)); originalContent.push(this.originalModel.getLineContent(lineNumber)); if (this.renderIndicators) { @@ -2009,17 +2012,17 @@ class InlineViewZonesComputer extends ViewZonesComputer { ]); } } - maxCharsPerLine += this.modifiedEditorConfiguration.viewInfo.scrollBeyondLastColumn; + maxCharsPerLine += this.modifiedEditorOptions.get(EditorOption.scrollBeyondLastColumn); let domNode = document.createElement('div'); domNode.className = 'view-lines line-delete'; domNode.innerHTML = sb.build(); - Configuration.applyFontInfoSlow(domNode, this.modifiedEditorConfiguration.fontInfo); + Configuration.applyFontInfoSlow(domNode, fontInfo); let marginDomNode = document.createElement('div'); marginDomNode.className = 'inline-deleted-margin-view-zone'; marginDomNode.innerHTML = marginHTML.join(''); - Configuration.applyFontInfoSlow(marginDomNode, this.modifiedEditorConfiguration.fontInfo); + Configuration.applyFontInfoSlow(marginDomNode, fontInfo); return { shouldNotShrink: true, @@ -2038,9 +2041,10 @@ class InlineViewZonesComputer extends ViewZonesComputer { }; } - private _renderOriginalLine(count: number, originalModel: ITextModel, config: editorOptions.InternalEditorOptions, tabSize: number, lineNumber: number, decorations: InlineDecoration[], sb: IStringBuilder): number { + private _renderOriginalLine(count: number, originalModel: ITextModel, options: IComputedEditorOptions, tabSize: number, lineNumber: number, decorations: InlineDecoration[], sb: IStringBuilder): number { const lineTokens = originalModel.getLineTokens(lineNumber); const lineContent = lineTokens.getLineContent(); + const fontInfo = options.get(EditorOption.fontInfo); const actualDecorations = LineDecoration.filter(decorations, lineNumber, 1, lineContent.length + 1); @@ -2050,14 +2054,14 @@ class InlineViewZonesComputer extends ViewZonesComputer { sb.appendASCIIString(' char-delete'); } sb.appendASCIIString('" style="top:'); - sb.appendASCIIString(String(count * config.lineHeight)); + sb.appendASCIIString(String(count * options.get(EditorOption.lineHeight))); sb.appendASCIIString('px;width:1000000px;">'); const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, originalModel.mightContainNonBasicASCII()); const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, originalModel.mightContainRTL()); const output = renderViewLine(new RenderLineInput( - (config.fontInfo.isMonospace && !config.viewInfo.disableMonospaceOptimizations), - config.fontInfo.canUseHalfwidthRightwardsArrow, + (fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations) && !options.get(EditorOption.fontLigatures)), + fontInfo.canUseHalfwidthRightwardsArrow, lineContent, false, isBasicASCII, @@ -2066,11 +2070,11 @@ class InlineViewZonesComputer extends ViewZonesComputer { lineTokens, actualDecorations, tabSize, - config.fontInfo.spaceWidth, - config.viewInfo.stopRenderingLineAfter, - config.viewInfo.renderWhitespace, - config.viewInfo.renderControlCharacters, - config.viewInfo.fontLigatures, + fontInfo.spaceWidth, + options.get(EditorOption.stopRenderingLineAfter), + options.get(EditorOption.renderWhitespace), + options.get(EditorOption.renderControlCharacters), + options.get(EditorOption.fontLigatures), null // Send no selections, original line cannot be selected ), sb); diff --git a/src/vs/editor/browser/widget/diffReview.ts b/src/vs/editor/browser/widget/diffReview.ts index 037883dd530..0f71723805c 100644 --- a/src/vs/editor/browser/widget/diffReview.ts +++ b/src/vs/editor/browser/widget/diffReview.ts @@ -17,7 +17,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { IComputedEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; import { Position } from 'vs/editor/common/core/position'; import { ILineChange, ScrollType } from 'vs/editor/common/editorCommon'; @@ -524,8 +524,8 @@ export class DiffReview extends Disposable { private _render(): void { - const originalOpts = this._diffEditor.getOriginalEditor().getConfiguration(); - const modifiedOpts = this._diffEditor.getModifiedEditor().getConfiguration(); + const originalOptions = this._diffEditor.getOriginalEditor().getOptions(); + const modifiedOptions = this._diffEditor.getModifiedEditor().getOptions(); const originalModel = this._diffEditor.getOriginalEditor().getModel(); const modifiedModel = this._diffEditor.getModifiedEditor().getModel(); @@ -551,7 +551,7 @@ export class DiffReview extends Disposable { let container = document.createElement('div'); container.className = 'diff-review-table'; container.setAttribute('role', 'list'); - Configuration.applyFontInfoSlow(container, modifiedOpts.fontInfo); + Configuration.applyFontInfoSlow(container, modifiedOptions.get(EditorOption.fontInfo)); let minOriginalLine = 0; let maxOriginalLine = 0; @@ -620,7 +620,7 @@ export class DiffReview extends Disposable { let modLine = minModifiedLine; for (let i = 0, len = diffs.length; i < len; i++) { const diffEntry = diffs[i]; - DiffReview._renderSection(container, diffEntry, modLine, this._width, originalOpts, originalModel, originalModelOpts, modifiedOpts, modifiedModel, modifiedModelOpts); + DiffReview._renderSection(container, diffEntry, modLine, this._width, originalOptions, originalModel, originalModelOpts, modifiedOptions, modifiedModel, modifiedModelOpts); if (diffEntry.modifiedLineStart !== 0) { modLine = diffEntry.modifiedLineEnd; } @@ -633,8 +633,8 @@ export class DiffReview extends Disposable { private static _renderSection( dest: HTMLElement, diffEntry: DiffEntry, modLine: number, width: number, - originalOpts: editorOptions.InternalEditorOptions, originalModel: ITextModel, originalModelOpts: TextModelResolvedOptions, - modifiedOpts: editorOptions.InternalEditorOptions, modifiedModel: ITextModel, modifiedModelOpts: TextModelResolvedOptions + originalOptions: IComputedEditorOptions, originalModel: ITextModel, originalModelOpts: TextModelResolvedOptions, + modifiedOptions: IComputedEditorOptions, modifiedModel: ITextModel, modifiedModelOpts: TextModelResolvedOptions ): void { const type = diffEntry.getType(); @@ -665,8 +665,11 @@ export class DiffReview extends Disposable { originalLineEnd - originalLineStart ); - const originalLineNumbersWidth = originalOpts.layoutInfo.glyphMarginWidth + originalOpts.layoutInfo.lineNumbersWidth; - const modifiedLineNumbersWidth = 10 + modifiedOpts.layoutInfo.glyphMarginWidth + modifiedOpts.layoutInfo.lineNumbersWidth; + const originalLayoutInfo = originalOptions.get(EditorOption.layoutInfo); + const originalLineNumbersWidth = originalLayoutInfo.glyphMarginWidth + originalLayoutInfo.lineNumbersWidth; + + const modifiedLayoutInfo = modifiedOptions.get(EditorOption.layoutInfo); + const modifiedLineNumbersWidth = 10 + modifiedLayoutInfo.glyphMarginWidth + modifiedLayoutInfo.lineNumbersWidth; for (let i = 0; i <= cnt; i++) { const originalLine = (originalLineStart === 0 ? 0 : originalLineStart + i); @@ -716,12 +719,12 @@ export class DiffReview extends Disposable { let lineContent: string; if (modifiedLine !== 0) { cell.insertAdjacentHTML('beforeend', - this._renderLine(modifiedModel, modifiedOpts, modifiedModelOpts.tabSize, modifiedLine) + this._renderLine(modifiedModel, modifiedOptions, modifiedModelOpts.tabSize, modifiedLine) ); lineContent = modifiedModel.getLineContent(modifiedLine); } else { cell.insertAdjacentHTML('beforeend', - this._renderLine(originalModel, originalOpts, originalModelOpts.tabSize, originalLine) + this._renderLine(originalModel, originalOptions, originalModelOpts.tabSize, originalLine) ); lineContent = originalModel.getLineContent(originalLine); } @@ -748,8 +751,9 @@ export class DiffReview extends Disposable { } } - private static _renderLine(model: ITextModel, config: editorOptions.InternalEditorOptions, tabSize: number, lineNumber: number): string { + private static _renderLine(model: ITextModel, options: IComputedEditorOptions, tabSize: number, lineNumber: number): string { const lineContent = model.getLineContent(lineNumber); + const fontInfo = options.get(EditorOption.fontInfo); const defaultMetadata = ( (FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET) @@ -766,8 +770,8 @@ export class DiffReview extends Disposable { const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, model.mightContainNonBasicASCII()); const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, model.mightContainRTL()); const r = renderViewLine(new RenderLineInput( - (config.fontInfo.isMonospace && !config.viewInfo.disableMonospaceOptimizations), - config.fontInfo.canUseHalfwidthRightwardsArrow, + (fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations) && !options.get(EditorOption.fontLigatures)), + fontInfo.canUseHalfwidthRightwardsArrow, lineContent, false, isBasicASCII, @@ -776,11 +780,11 @@ export class DiffReview extends Disposable { lineTokens, [], tabSize, - config.fontInfo.spaceWidth, - config.viewInfo.stopRenderingLineAfter, - config.viewInfo.renderWhitespace, - config.viewInfo.renderControlCharacters, - config.viewInfo.fontLigatures, + fontInfo.spaceWidth, + options.get(EditorOption.stopRenderingLineAfter), + options.get(EditorOption.renderWhitespace), + options.get(EditorOption.renderControlCharacters), + options.get(EditorOption.fontLigatures), null )); diff --git a/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts b/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts index ffa6ca519cd..ef5e39e306e 100644 --- a/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts +++ b/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts @@ -8,7 +8,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; -import { IConfigurationChangedEvent, IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -36,7 +36,7 @@ export class EmbeddedCodeEditorWidget extends CodeEditorWidget { @INotificationService notificationService: INotificationService, @IAccessibilityService accessibilityService: IAccessibilityService ) { - super(domElement, parentEditor.getRawConfiguration(), {}, instantiationService, codeEditorService, commandService, contextKeyService, themeService, notificationService, accessibilityService); + super(domElement, parentEditor.getRawOptions(), {}, instantiationService, codeEditorService, commandService, contextKeyService, themeService, notificationService, accessibilityService); this._parentEditor = parentEditor; this._overwriteOptions = options; @@ -44,15 +44,15 @@ export class EmbeddedCodeEditorWidget extends CodeEditorWidget { // Overwrite parent's options super.updateOptions(this._overwriteOptions); - this._register(parentEditor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => this._onParentConfigurationChanged(e))); + this._register(parentEditor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => this._onParentConfigurationChanged(e))); } getParentEditor(): ICodeEditor { return this._parentEditor; } - private _onParentConfigurationChanged(e: IConfigurationChangedEvent): void { - super.updateOptions(this._parentEditor.getRawConfiguration()); + private _onParentConfigurationChanged(e: ConfigurationChangedEvent): void { + super.updateOptions(this._parentEditor.getRawOptions()); super.updateOptions(this._overwriteOptions); } @@ -80,7 +80,7 @@ export class EmbeddedDiffEditorWidget extends DiffEditorWidget { @IContextMenuService contextMenuService: IContextMenuService, @IClipboardService clipboardService: IClipboardService ) { - super(domElement, parentEditor.getRawConfiguration(), clipboardService, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService); + super(domElement, parentEditor.getRawOptions(), clipboardService, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService); this._parentEditor = parentEditor; this._overwriteOptions = options; @@ -95,8 +95,8 @@ export class EmbeddedDiffEditorWidget extends DiffEditorWidget { return this._parentEditor; } - private _onParentConfigurationChanged(e: IConfigurationChangedEvent): void { - super.updateOptions(this._parentEditor.getRawConfiguration()); + private _onParentConfigurationChanged(e: ConfigurationChangedEvent): void { + super.updateOptions(this._parentEditor.getRawOptions()); super.updateOptions(this._overwriteOptions); } diff --git a/src/vs/editor/browser/widget/inlineDiffMargin.ts b/src/vs/editor/browser/widget/inlineDiffMargin.ts index a911a6b4c50..90bb8d9165a 100644 --- a/src/vs/editor/browser/widget/inlineDiffMargin.ts +++ b/src/vs/editor/browser/widget/inlineDiffMargin.ts @@ -12,6 +12,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { Range } from 'vs/editor/common/core/range'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface IDiffLinesChange { readonly originalStartLineNumber: number; @@ -58,7 +59,7 @@ export class InlineDiffMargin extends Disposable { this._diffActions = document.createElement('div'); this._diffActions.className = 'lightbulb-glyph'; this._diffActions.style.position = 'absolute'; - const lineHeight = editor.getConfiguration().lineHeight; + const lineHeight = editor.getOption(EditorOption.lineHeight); const lineFeed = editor.getModel()!.getEOL(); this._diffActions.style.right = '0px'; this._diffActions.style.visibility = 'hidden'; @@ -97,7 +98,7 @@ export class InlineDiffMargin extends Disposable { actions.push(copyLineAction); } - const readOnly = editor.getConfiguration().readOnly; + const readOnly = editor.getOption(EditorOption.readOnly); if (!readOnly) { actions.push(new Action('diff.inline.revertChange', nls.localize('diff.inline.revertChange.label', "Revert this change"), undefined, true, async () => { if (diff.modifiedEndLineNumber === 0) { diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index 1fd0db269f4..af4f2074ea8 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -7,16 +7,13 @@ import * as nls from 'vs/nls'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; -import * as platform from 'vs/base/common/platform'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import * as arrays from 'vs/base/common/arrays'; +import { IEditorOptions, editorOptionsRegistry, ValidatedEditorOptions, IEnvironmentalOptions, IComputedEditorOptions, ConfigurationChangedEvent, EDITOR_MODEL_DEFAULTS, EditorOption, FindComputedEditorOptionValueById } from 'vs/editor/common/config/editorOptions'; import { EditorZoom } from 'vs/editor/common/config/editorZoom'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationRegistry, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; -import EDITOR_DEFAULTS = editorOptions.EDITOR_DEFAULTS; -import EDITOR_FONT_DEFAULTS = editorOptions.EDITOR_FONT_DEFAULTS; -import EDITOR_MODEL_DEFAULTS = editorOptions.EDITOR_MODEL_DEFAULTS; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; /** @@ -63,35 +60,187 @@ export interface IEnvConfiguration { const hasOwnProperty = Object.hasOwnProperty; +export class ComputedEditorOptions implements IComputedEditorOptions { + private readonly _values: any[] = []; + public _read(id: EditorOption): T { + return this._values[id]; + } + public get(id: T): FindComputedEditorOptionValueById { + return this._values[id]; + } + public _write(id: EditorOption, value: T): void { + this._values[id] = value; + } +} + +class RawEditorOptions { + private readonly _values: any[] = []; + public _read(id: EditorOption): T | undefined { + return this._values[id]; + } + public _write(id: EditorOption, value: T | undefined): void { + this._values[id] = value; + } +} + +class EditorConfiguration2 { + public static readOptions(_options: IEditorOptions): RawEditorOptions { + const options: { [key: string]: any; } = _options; + const result = new RawEditorOptions(); + for (const editorOption of editorOptionsRegistry) { + const value = (editorOption.name === '_never_' ? undefined : options[editorOption.name]); + result._write(editorOption.id, value); + } + return result; + } + + public static validateOptions(options: RawEditorOptions): ValidatedEditorOptions { + const result = new ValidatedEditorOptions(); + for (const editorOption of editorOptionsRegistry) { + result._write(editorOption.id, editorOption.validate(options._read(editorOption.id))); + } + return result; + } + + public static computeOptions(options: ValidatedEditorOptions, env: IEnvironmentalOptions): ComputedEditorOptions { + const result = new ComputedEditorOptions(); + for (const editorOption of editorOptionsRegistry) { + result._write(editorOption.id, editorOption.compute(env, result, options._read(editorOption.id))); + } + return result; + } + + private static _deepEquals(a: T, b: T): boolean { + if (typeof a !== 'object' || typeof b !== 'object') { + return (a === b); + } + if (Array.isArray(a) || Array.isArray(b)) { + return (Array.isArray(a) && Array.isArray(b) ? arrays.equals(a, b) : false); + } + for (let key in a) { + if (!EditorConfiguration2._deepEquals(a[key], b[key])) { + return false; + } + } + return true; + } + + public static checkEquals(a: ComputedEditorOptions, b: ComputedEditorOptions): ConfigurationChangedEvent | null { + const result: boolean[] = []; + let somethingChanged = false; + for (const editorOption of editorOptionsRegistry) { + const changed = !EditorConfiguration2._deepEquals(a._read(editorOption.id), b._read(editorOption.id)); + result[editorOption.id] = changed; + if (changed) { + somethingChanged = true; + } + } + return (somethingChanged ? new ConfigurationChangedEvent(result) : null); + } +} + +/** + * Compatibility with old options + */ +function migrateOptions(options: IEditorOptions): void { + const wordWrap = options.wordWrap; + if (wordWrap === true) { + options.wordWrap = 'on'; + } else if (wordWrap === false) { + options.wordWrap = 'off'; + } + + const lineNumbers = options.lineNumbers; + if (lineNumbers === true) { + options.lineNumbers = 'on'; + } else if (lineNumbers === false) { + options.lineNumbers = 'off'; + } + + const autoClosingBrackets = options.autoClosingBrackets; + if (autoClosingBrackets === false) { + options.autoClosingBrackets = 'never'; + options.autoClosingQuotes = 'never'; + options.autoSurround = 'never'; + } + + const cursorBlinking = options.cursorBlinking; + if (cursorBlinking === 'visible') { + options.cursorBlinking = 'solid'; + } + + const renderWhitespace = options.renderWhitespace; + if (renderWhitespace === true) { + options.renderWhitespace = 'boundary'; + } else if (renderWhitespace === false) { + options.renderWhitespace = 'none'; + } + + const renderLineHighlight = options.renderLineHighlight; + if (renderLineHighlight === true) { + options.renderLineHighlight = 'line'; + } else if (renderLineHighlight === false) { + options.renderLineHighlight = 'none'; + } + + const acceptSuggestionOnEnter = options.acceptSuggestionOnEnter; + if (acceptSuggestionOnEnter === true) { + options.acceptSuggestionOnEnter = 'on'; + } else if (acceptSuggestionOnEnter === false) { + options.acceptSuggestionOnEnter = 'off'; + } + + const tabCompletion = options.tabCompletion; + if (tabCompletion === false) { + options.tabCompletion = 'off'; + } else if (tabCompletion === true) { + options.tabCompletion = 'onlySnippets'; + } + + const hover = options.hover; + if (hover === true) { + options.hover = { + enabled: true + }; + } else if (hover === false) { + options.hover = { + enabled: false + }; + } +} + +function deepCloneAndMigrateOptions(_options: IEditorOptions): IEditorOptions { + const options = objects.deepClone(_options); + migrateOptions(options); + return options; +} + export abstract class CommonEditorConfiguration extends Disposable implements editorCommon.IConfiguration { + private _onDidChange = this._register(new Emitter()); + public readonly onDidChange: Event = this._onDidChange.event; + public readonly isSimpleWidget: boolean; - protected _rawOptions: editorOptions.IEditorOptions; - protected _validatedOptions: editorOptions.IValidatedEditorOptions; - public editor!: editorOptions.InternalEditorOptions; + public options!: ComputedEditorOptions; + private _isDominatedByLongLines: boolean; private _lineNumbersDigitCount: number; - private _onDidChange = this._register(new Emitter()); - public readonly onDidChange: Event = this._onDidChange.event; + private _rawOptions: IEditorOptions; + private _readOptions: RawEditorOptions; + protected _validatedOptions: ValidatedEditorOptions; - constructor(isSimpleWidget: boolean, options: editorOptions.IEditorOptions) { + constructor(isSimpleWidget: boolean, _options: IEditorOptions) { super(); - this.isSimpleWidget = isSimpleWidget; - // Do a "deep clone of sorts" on the incoming options - this._rawOptions = objects.mixin({}, options || {}); - this._rawOptions.scrollbar = objects.mixin({}, this._rawOptions.scrollbar || {}); - this._rawOptions.minimap = objects.mixin({}, this._rawOptions.minimap || {}); - this._rawOptions.find = objects.mixin({}, this._rawOptions.find || {}); - this._rawOptions.hover = objects.mixin({}, this._rawOptions.hover || {}); - this._rawOptions.parameterHints = objects.mixin({}, this._rawOptions.parameterHints || {}); - - this._validatedOptions = editorOptions.EditorOptionsValidator.validate(this._rawOptions, EDITOR_DEFAULTS); this._isDominatedByLongLines = false; this._lineNumbersDigitCount = 1; + this._rawOptions = deepCloneAndMigrateOptions(_options); + this._readOptions = EditorConfiguration2.readOptions(this._rawOptions); + this._validatedOptions = EditorConfiguration2.validateOptions(this._readOptions); + this._register(EditorZoom.onDidChangeZoomLevel(_ => this._recomputeOptions())); this._register(TabFocus.onDidChangeTabFocus(_ => this._recomputeOptions())); } @@ -104,29 +253,32 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed } protected _recomputeOptions(): void { - const oldOptions = this.editor; + const oldOptions = this.options; const newOptions = this._computeInternalOptions(); - if (oldOptions && oldOptions.equals(newOptions)) { - return; - } + if (!oldOptions) { + this.options = newOptions; + } else { + const changeEvent = EditorConfiguration2.checkEquals(oldOptions, newOptions); - this.editor = newOptions; + if (changeEvent === null) { + // nothing changed! + return; + } - if (oldOptions) { - this._onDidChange.fire(oldOptions.createChangeEvent(newOptions)); + this.options = newOptions; + this._onDidChange.fire(changeEvent); } } - public getRawOptions(): editorOptions.IEditorOptions { + public getRawOptions(): IEditorOptions { return this._rawOptions; } - private _computeInternalOptions(): editorOptions.InternalEditorOptions { - const opts = this._validatedOptions; + private _computeInternalOptions(): ComputedEditorOptions { const partialEnv = this._getEnvConfiguration(); - const bareFontInfo = BareFontInfo.createFromRawSettings(this._rawOptions, partialEnv.zoomLevel, this.isSimpleWidget); - const env: editorOptions.IEnvironmentalOptions = { + const bareFontInfo = BareFontInfo.createFromValidatedSettings(this._validatedOptions, partialEnv.zoomLevel, this.isSimpleWidget); + const env: IEnvironmentalOptions = { outerWidth: partialEnv.outerWidth, outerHeight: partialEnv.outerHeight, fontInfo: this.readConfiguration(bareFontInfo), @@ -138,7 +290,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed tabFocusMode: TabFocus.getTabFocusMode(), accessibilitySupport: partialEnv.accessibilitySupport }; - return editorOptions.InternalEditorOptionsFactory.createInternalEditorOptions(env, opts); + return EditorConfiguration2.computeOptions(this._validatedOptions, env); } private static _primitiveArrayEquals(a: any[], b: any[]): boolean { @@ -181,15 +333,18 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed return true; } - public updateOptions(newOptions: editorOptions.IEditorOptions): void { - if (typeof newOptions === 'undefined') { + public updateOptions(_newOptions: IEditorOptions): void { + if (typeof _newOptions === 'undefined') { return; } + const newOptions = deepCloneAndMigrateOptions(_newOptions); if (CommonEditorConfiguration._subsetEquals(this._rawOptions, newOptions)) { return; } this._rawOptions = objects.mixin(this._rawOptions, newOptions || {}); - this._validatedOptions = editorOptions.EditorOptionsValidator.validate(this._rawOptions, EDITOR_DEFAULTS); + this._readOptions = EditorConfiguration2.readOptions(this._rawOptions); + this._validatedOptions = EditorConfiguration2.validateOptions(this._readOptions); + this._recomputeOptions(); } @@ -223,877 +378,130 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed const configurationRegistry = Registry.as(Extensions.Configuration); const editorConfiguration: IConfigurationNode = { - 'id': 'editor', - 'order': 5, - 'type': 'object', - 'title': nls.localize('editorConfigurationTitle', "Editor"), - 'overridable': true, - 'scope': ConfigurationScope.RESOURCE, - 'properties': { - 'editor.fontFamily': { - 'type': 'string', - 'default': EDITOR_FONT_DEFAULTS.fontFamily, - 'description': nls.localize('fontFamily', "Controls the font family.") - }, - 'editor.fontWeight': { - 'type': 'string', - 'enum': ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'], - 'default': EDITOR_FONT_DEFAULTS.fontWeight, - 'description': nls.localize('fontWeight', "Controls the font weight.") - }, - 'editor.fontSize': { - 'type': 'number', - 'default': EDITOR_FONT_DEFAULTS.fontSize, - 'description': nls.localize('fontSize', "Controls the font size in pixels.") - }, - 'editor.lineHeight': { - 'type': 'number', - 'default': EDITOR_FONT_DEFAULTS.lineHeight, - 'description': nls.localize('lineHeight', "Controls the line height. Use 0 to compute the line height from the font size.") - }, - 'editor.letterSpacing': { - 'type': 'number', - 'default': EDITOR_FONT_DEFAULTS.letterSpacing, - 'description': nls.localize('letterSpacing', "Controls the letter spacing in pixels.") - }, - 'editor.lineNumbers': { - 'type': 'string', - 'enum': ['off', 'on', 'relative', 'interval'], - 'enumDescriptions': [ - nls.localize('lineNumbers.off', "Line numbers are not rendered."), - nls.localize('lineNumbers.on', "Line numbers are rendered as absolute number."), - nls.localize('lineNumbers.relative', "Line numbers are rendered as distance in lines to cursor position."), - nls.localize('lineNumbers.interval', "Line numbers are rendered every 10 lines.") - ], - 'default': 'on', - 'description': nls.localize('lineNumbers', "Controls the display of line numbers.") - }, - 'editor.cursorSurroundingLines': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.viewInfo.cursorSurroundingLines, - 'description': nls.localize('cursorSurroundingLines', "Controls the minimal number of visible leading and trailing lines surrounding the cursor. Known as 'scrollOff' or `scrollOffset` in some other editors.") - }, - 'editor.renderFinalNewline': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.renderFinalNewline, - 'description': nls.localize('renderFinalNewline', "Render last line number when the file ends with a newline.") - }, - 'editor.rulers': { - 'type': 'array', - 'items': { - 'type': 'number' - }, - 'default': EDITOR_DEFAULTS.viewInfo.rulers, - 'description': nls.localize('rulers', "Render vertical rulers after a certain number of monospace characters. Use multiple values for multiple rulers. No rulers are drawn if array is empty.") - }, - 'editor.wordSeparators': { - 'type': 'string', - 'default': EDITOR_DEFAULTS.wordSeparators, - 'description': nls.localize('wordSeparators', "Characters that will be used as word separators when doing word related navigations or operations.") - }, + id: 'editor', + order: 5, + type: 'object', + title: nls.localize('editorConfigurationTitle', "Editor"), + overridable: true, + scope: ConfigurationScope.RESOURCE, + properties: { 'editor.tabSize': { - 'type': 'number', - 'default': EDITOR_MODEL_DEFAULTS.tabSize, - 'minimum': 1, - 'markdownDescription': nls.localize('tabSize', "The number of spaces a tab is equal to. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") + type: 'number', + default: EDITOR_MODEL_DEFAULTS.tabSize, + minimum: 1, + markdownDescription: nls.localize('tabSize', "The number of spaces a tab is equal to. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") }, // 'editor.indentSize': { // 'anyOf': [ // { - // 'type': 'string', - // 'enum': ['tabSize'] + // type: 'string', + // enum: ['tabSize'] // }, // { - // 'type': 'number', - // 'minimum': 1 + // type: 'number', + // minimum: 1 // } // ], - // 'default': 'tabSize', - // 'markdownDescription': nls.localize('indentSize', "The number of spaces used for indentation or 'tabSize' to use the value from `#editor.tabSize#`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") + // default: 'tabSize', + // markdownDescription: nls.localize('indentSize', "The number of spaces used for indentation or 'tabSize' to use the value from `#editor.tabSize#`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") // }, 'editor.insertSpaces': { - 'type': 'boolean', - 'default': EDITOR_MODEL_DEFAULTS.insertSpaces, - 'markdownDescription': nls.localize('insertSpaces', "Insert spaces when pressing `Tab`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") + type: 'boolean', + default: EDITOR_MODEL_DEFAULTS.insertSpaces, + markdownDescription: nls.localize('insertSpaces', "Insert spaces when pressing `Tab`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") }, 'editor.detectIndentation': { - 'type': 'boolean', - 'default': EDITOR_MODEL_DEFAULTS.detectIndentation, - 'markdownDescription': nls.localize('detectIndentation', "Controls whether `#editor.tabSize#` and `#editor.insertSpaces#` will be automatically detected when a file is opened based on the file contents.") - }, - 'editor.roundedSelection': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.roundedSelection, - 'description': nls.localize('roundedSelection', "Controls whether selections should have rounded corners.") - }, - 'editor.scrollBeyondLastLine': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.scrollBeyondLastLine, - 'description': nls.localize('scrollBeyondLastLine', "Controls whether the editor will scroll beyond the last line.") - }, - 'editor.scrollBeyondLastColumn': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.viewInfo.scrollBeyondLastColumn, - 'description': nls.localize('scrollBeyondLastColumn', "Controls the number of extra characters beyond which the editor will scroll horizontally.") - }, - 'editor.smoothScrolling': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.smoothScrolling, - 'description': nls.localize('smoothScrolling', "Controls whether the editor will scroll using an animation.") - }, - 'editor.minimap.enabled': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.minimap.enabled, - 'description': nls.localize('minimap.enabled', "Controls whether the minimap is shown.") - }, - 'editor.minimap.side': { - 'type': 'string', - 'enum': ['left', 'right'], - 'default': EDITOR_DEFAULTS.viewInfo.minimap.side, - 'description': nls.localize('minimap.side', "Controls the side where to render the minimap.") - }, - 'editor.minimap.showSlider': { - 'type': 'string', - 'enum': ['always', 'mouseover'], - 'default': EDITOR_DEFAULTS.viewInfo.minimap.showSlider, - 'description': nls.localize('minimap.showSlider', "Controls whether the minimap slider is automatically hidden.") - }, - 'editor.minimap.renderCharacters': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.minimap.renderCharacters, - 'description': nls.localize('minimap.renderCharacters', "Render the actual characters on a line as opposed to color blocks.") - }, - 'editor.minimap.maxColumn': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.viewInfo.minimap.maxColumn, - 'description': nls.localize('minimap.maxColumn', "Limit the width of the minimap to render at most a certain number of columns.") - }, - 'editor.hover.enabled': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.hover.enabled, - 'description': nls.localize('hover.enabled', "Controls whether the hover is shown.") - }, - 'editor.hover.delay': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.contribInfo.hover.delay, - 'description': nls.localize('hover.delay', "Controls the delay in milliseconds after which the hover is shown.") - }, - 'editor.hover.sticky': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.hover.sticky, - 'description': nls.localize('hover.sticky', "Controls whether the hover should remain visible when mouse is moved over it.") - }, - 'editor.find.seedSearchStringFromSelection': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.find.seedSearchStringFromSelection, - 'description': nls.localize('find.seedSearchStringFromSelection', "Controls whether the search string in the Find Widget is seeded from the editor selection.") - }, - 'editor.find.autoFindInSelection': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.find.autoFindInSelection, - 'description': nls.localize('find.autoFindInSelection', "Controls whether the find operation is carried out on selected text or the entire file in the editor.") - }, - 'editor.find.globalFindClipboard': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.find.globalFindClipboard, - 'description': nls.localize('find.globalFindClipboard', "Controls whether the Find Widget should read or modify the shared find clipboard on macOS."), - 'included': platform.isMacintosh - }, - 'editor.find.addExtraSpaceOnTop': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('find.addExtraSpaceOnTop', "Controls whether the Find Widget should add extra lines on top of the editor. When true, you can scroll beyond the first line when the Find Widget is visible.") - }, - 'editor.wordWrap': { - 'type': 'string', - 'enum': ['off', 'on', 'wordWrapColumn', 'bounded'], - 'markdownEnumDescriptions': [ - nls.localize('wordWrap.off', "Lines will never wrap."), - nls.localize('wordWrap.on', "Lines will wrap at the viewport width."), - nls.localize({ - key: 'wordWrap.wordWrapColumn', - comment: [ - '- `editor.wordWrapColumn` refers to a different setting and should not be localized.' - ] - }, "Lines will wrap at `#editor.wordWrapColumn#`."), - nls.localize({ - key: 'wordWrap.bounded', - comment: [ - '- viewport means the edge of the visible window size.', - '- `editor.wordWrapColumn` refers to a different setting and should not be localized.' - ] - }, "Lines will wrap at the minimum of viewport and `#editor.wordWrapColumn#`."), - ], - 'default': EDITOR_DEFAULTS.wordWrap, - 'description': nls.localize({ - key: 'wordWrap', - comment: [ - '- \'off\', \'on\', \'wordWrapColumn\' and \'bounded\' refer to values the setting can take and should not be localized.', - '- `editor.wordWrapColumn` refers to a different setting and should not be localized.' - ] - }, "Controls how lines should wrap.") - }, - 'editor.wordWrapColumn': { - 'type': 'integer', - 'default': EDITOR_DEFAULTS.wordWrapColumn, - 'minimum': 1, - 'markdownDescription': nls.localize({ - key: 'wordWrapColumn', - comment: [ - '- `editor.wordWrap` refers to a different setting and should not be localized.', - '- \'wordWrapColumn\' and \'bounded\' refer to values the different setting can take and should not be localized.' - ] - }, "Controls the wrapping column of the editor when `#editor.wordWrap#` is `wordWrapColumn` or `bounded`.") - }, - 'editor.wrappingIndent': { - 'type': 'string', - 'enum': ['none', 'same', 'indent', 'deepIndent'], - enumDescriptions: [ - nls.localize('wrappingIndent.none', "No indentation. Wrapped lines begin at column 1."), - nls.localize('wrappingIndent.same', "Wrapped lines get the same indentation as the parent."), - nls.localize('wrappingIndent.indent', "Wrapped lines get +1 indentation toward the parent."), - nls.localize('wrappingIndent.deepIndent', "Wrapped lines get +2 indentation toward the parent."), - ], - 'default': 'same', - 'description': nls.localize('wrappingIndent', "Controls the indentation of wrapped lines."), - }, - 'editor.mouseWheelScrollSensitivity': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.viewInfo.scrollbar.mouseWheelScrollSensitivity, - 'markdownDescription': nls.localize('mouseWheelScrollSensitivity', "A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.") - }, - 'editor.fastScrollSensitivity': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.viewInfo.scrollbar.fastScrollSensitivity, - 'markdownDescription': nls.localize('fastScrollSensitivity', "Scrolling speed multiplier when pressing `Alt`.") - }, - 'editor.multiCursorModifier': { - 'type': 'string', - 'enum': ['ctrlCmd', 'alt'], - 'markdownEnumDescriptions': [ - nls.localize('multiCursorModifier.ctrlCmd', "Maps to `Control` on Windows and Linux and to `Command` on macOS."), - nls.localize('multiCursorModifier.alt', "Maps to `Alt` on Windows and Linux and to `Option` on macOS.") - ], - 'default': 'alt', - 'markdownDescription': nls.localize({ - key: 'multiCursorModifier', - comment: [ - '- `ctrlCmd` refers to a value the setting can take and should not be localized.', - '- `Control` and `Command` refer to the modifier keys Ctrl or Cmd on the keyboard and can be localized.' - ] - }, "The modifier to be used to add multiple cursors with the mouse. The Go To Definition and Open Link mouse gestures will adapt such that they do not conflict with the multicursor modifier. [Read more](https://code.visualstudio.com/docs/editor/codebasics#_multicursor-modifier).") - }, - 'editor.multiCursorMergeOverlapping': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.multiCursorMergeOverlapping, - 'description': nls.localize('multiCursorMergeOverlapping', "Merge multiple cursors when they are overlapping.") - }, - 'editor.quickSuggestions': { - 'anyOf': [ - { - type: 'boolean', - }, - { - type: 'object', - properties: { - strings: { - type: 'boolean', - default: false, - description: nls.localize('quickSuggestions.strings', "Enable quick suggestions inside strings.") - }, - comments: { - type: 'boolean', - default: false, - description: nls.localize('quickSuggestions.comments', "Enable quick suggestions inside comments.") - }, - other: { - type: 'boolean', - default: true, - description: nls.localize('quickSuggestions.other', "Enable quick suggestions outside of strings and comments.") - }, - } - } - ], - 'default': EDITOR_DEFAULTS.contribInfo.quickSuggestions, - 'description': nls.localize('quickSuggestions', "Controls whether suggestions should automatically show up while typing.") - }, - 'editor.quickSuggestionsDelay': { - 'type': 'integer', - 'default': EDITOR_DEFAULTS.contribInfo.quickSuggestionsDelay, - 'minimum': 0, - 'description': nls.localize('quickSuggestionsDelay', "Controls the delay in milliseconds after which quick suggestions will show up.") - }, - 'editor.parameterHints.enabled': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.parameterHints.enabled, - 'description': nls.localize('parameterHints.enabled', "Enables a pop-up that shows parameter documentation and type information as you type.") - }, - 'editor.parameterHints.cycle': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.parameterHints.cycle, - 'description': nls.localize('parameterHints.cycle', "Controls whether the parameter hints menu cycles or closes when reaching the end of the list.") - }, - 'editor.autoClosingBrackets': { - type: 'string', - enum: ['always', 'languageDefined', 'beforeWhitespace', 'never'], - enumDescriptions: [ - '', - nls.localize('editor.autoClosingBrackets.languageDefined', "Use language configurations to determine when to autoclose brackets."), - nls.localize('editor.autoClosingBrackets.beforeWhitespace', "Autoclose brackets only when the cursor is to the left of whitespace."), - '', - - ], - 'default': EDITOR_DEFAULTS.autoClosingBrackets, - 'description': nls.localize('autoClosingBrackets', "Controls whether the editor should automatically close brackets after the user adds an opening bracket.") - }, - 'editor.autoClosingQuotes': { - type: 'string', - enum: ['always', 'languageDefined', 'beforeWhitespace', 'never'], - enumDescriptions: [ - '', - nls.localize('editor.autoClosingQuotes.languageDefined', "Use language configurations to determine when to autoclose quotes."), - nls.localize('editor.autoClosingQuotes.beforeWhitespace', "Autoclose quotes only when the cursor is to the left of whitespace."), - '', - ], - 'default': EDITOR_DEFAULTS.autoClosingQuotes, - 'description': nls.localize('autoClosingQuotes', "Controls whether the editor should automatically close quotes after the user adds an opening quote.") - }, - 'editor.autoClosingOvertype': { - type: 'string', - enum: ['always', 'auto', 'never'], - enumDescriptions: [ - nls.localize('editor.autoClosingOvertype.always', "Always type over closing quotes or brackets."), - nls.localize('editor.autoClosingOvertype.auto', "Type over closing quotes or brackets only if they were automatically inserted."), - nls.localize('editor.autoClosingOvertype.never', "Never type over closing quotes or brackets."), - ], - 'default': EDITOR_DEFAULTS.autoClosingOvertype, - 'description': nls.localize('autoClosingOvertype', "Controls whether the editor should type over closing quotes or brackets.") - }, - 'editor.autoSurround': { - type: 'string', - enum: ['languageDefined', 'brackets', 'quotes', 'never'], - enumDescriptions: [ - nls.localize('editor.autoSurround.languageDefined', "Use language configurations to determine when to automatically surround selections."), - nls.localize('editor.autoSurround.brackets', "Surround with brackets but not quotes."), - nls.localize('editor.autoSurround.quotes', "Surround with quotes but not brackets."), - '' - ], - 'default': EDITOR_DEFAULTS.autoSurround, - 'description': nls.localize('autoSurround', "Controls whether the editor should automatically surround selections.") - }, - 'editor.formatOnType': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.formatOnType, - 'description': nls.localize('formatOnType', "Controls whether the editor should automatically format the line after typing.") - }, - 'editor.formatOnPaste': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.formatOnPaste, - 'description': nls.localize('formatOnPaste', "Controls whether the editor should automatically format the pasted content. A formatter must be available and the formatter should be able to format a range in a document.") - }, - 'editor.autoIndent': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.autoIndent, - 'description': nls.localize('autoIndent', "Controls whether the editor should automatically adjust the indentation when users type, paste or move lines. Extensions with indentation rules of the language must be available.") - }, - 'editor.suggestOnTriggerCharacters': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.suggestOnTriggerCharacters, - 'description': nls.localize('suggestOnTriggerCharacters', "Controls whether suggestions should automatically show up when typing trigger characters.") - }, - 'editor.acceptSuggestionOnEnter': { - 'type': 'string', - 'enum': ['on', 'smart', 'off'], - 'default': EDITOR_DEFAULTS.contribInfo.acceptSuggestionOnEnter, - 'markdownEnumDescriptions': [ - '', - nls.localize('acceptSuggestionOnEnterSmart', "Only accept a suggestion with `Enter` when it makes a textual change."), - '' - ], - 'markdownDescription': nls.localize('acceptSuggestionOnEnter', "Controls whether suggestions should be accepted on `Enter`, in addition to `Tab`. Helps to avoid ambiguity between inserting new lines or accepting suggestions.") - }, - 'editor.acceptSuggestionOnCommitCharacter': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.acceptSuggestionOnCommitCharacter, - 'markdownDescription': nls.localize('acceptSuggestionOnCommitCharacter', "Controls whether suggestions should be accepted on commit characters. For example, in JavaScript, the semi-colon (`;`) can be a commit character that accepts a suggestion and types that character.") - }, - 'editor.snippetSuggestions': { - 'type': 'string', - 'enum': ['top', 'bottom', 'inline', 'none'], - 'enumDescriptions': [ - nls.localize('snippetSuggestions.top', "Show snippet suggestions on top of other suggestions."), - nls.localize('snippetSuggestions.bottom', "Show snippet suggestions below other suggestions."), - nls.localize('snippetSuggestions.inline', "Show snippets suggestions with other suggestions."), - nls.localize('snippetSuggestions.none', "Do not show snippet suggestions."), - ], - 'default': EDITOR_DEFAULTS.contribInfo.suggest.snippets, - 'description': nls.localize('snippetSuggestions', "Controls whether snippets are shown with other suggestions and how they are sorted.") - }, - 'editor.emptySelectionClipboard': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.emptySelectionClipboard, - 'description': nls.localize('emptySelectionClipboard', "Controls whether copying without a selection copies the current line.") - }, - 'editor.copyWithSyntaxHighlighting': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.copyWithSyntaxHighlighting, - 'description': nls.localize('copyWithSyntaxHighlighting', "Controls whether syntax highlighting should be copied into the clipboard.") - }, - 'editor.wordBasedSuggestions': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.wordBasedSuggestions, - 'description': nls.localize('wordBasedSuggestions', "Controls whether completions should be computed based on words in the document.") - }, - 'editor.suggestSelection': { - 'type': 'string', - 'enum': ['first', 'recentlyUsed', 'recentlyUsedByPrefix'], - 'markdownEnumDescriptions': [ - nls.localize('suggestSelection.first', "Always select the first suggestion."), - nls.localize('suggestSelection.recentlyUsed', "Select recent suggestions unless further typing selects one, e.g. `console.| -> console.log` because `log` has been completed recently."), - nls.localize('suggestSelection.recentlyUsedByPrefix', "Select suggestions based on previous prefixes that have completed those suggestions, e.g. `co -> console` and `con -> const`."), - ], - 'default': 'recentlyUsed', - 'description': nls.localize('suggestSelection', "Controls how suggestions are pre-selected when showing the suggest list.") - }, - 'editor.suggestFontSize': { - 'type': 'integer', - 'default': 0, - 'minimum': 0, - 'markdownDescription': nls.localize('suggestFontSize', "Font size for the suggest widget. When set to `0`, the value of `#editor.fontSize#` is used.") - }, - 'editor.suggestLineHeight': { - 'type': 'integer', - 'default': 0, - 'minimum': 0, - 'markdownDescription': nls.localize('suggestLineHeight', "Line height for the suggest widget. When set to `0`, the value of `#editor.lineHeight#` is used.") - }, - 'editor.tabCompletion': { - type: 'string', - default: 'off', - enum: ['on', 'off', 'onlySnippets'], - enumDescriptions: [ - nls.localize('tabCompletion.on', "Tab complete will insert the best matching suggestion when pressing tab."), - nls.localize('tabCompletion.off', "Disable tab completions."), - nls.localize('tabCompletion.onlySnippets', "Tab complete snippets when their prefix match. Works best when 'quickSuggestions' aren't enabled."), - ], - description: nls.localize('tabCompletion', "Enables tab completions.") - }, - 'editor.suggest.filterGraceful': { type: 'boolean', - default: true, - description: nls.localize('suggest.filterGraceful', "Controls whether filtering and sorting suggestions accounts for small typos.") - }, - 'editor.suggest.localityBonus': { - type: 'boolean', - default: false, - description: nls.localize('suggest.localityBonus', "Controls whether sorting favours words that appear close to the cursor.") - }, - 'editor.suggest.shareSuggestSelections': { - type: 'boolean', - default: false, - markdownDescription: nls.localize('suggest.shareSuggestSelections', "Controls whether remembered suggestion selections are shared between multiple workspaces and windows (needs `#editor.suggestSelection#`).") - }, - 'editor.suggest.snippetsPreventQuickSuggestions': { - type: 'boolean', - default: true, - description: nls.localize('suggest.snippetsPreventQuickSuggestions', "Control whether an active snippet prevents quick suggestions.") - }, - 'editor.suggest.showIcons': { - type: 'boolean', - default: EDITOR_DEFAULTS.contribInfo.suggest.showIcons, - description: nls.localize('suggest.showIcons', "Controls whether to show or hide icons in suggestions.") - }, - 'editor.suggest.maxVisibleSuggestions': { - type: 'number', - default: EDITOR_DEFAULTS.contribInfo.suggest.maxVisibleSuggestions, - minimum: 1, - maximum: 15, - description: nls.localize('suggest.maxVisibleSuggestions', "Controls how many suggestions IntelliSense will show before showing a scrollbar (maximum 15).") - }, - 'editor.suggest.filteredTypes': { - type: 'object', - default: { keyword: true, snippet: true }, - markdownDescription: nls.localize('suggest.filtered', "Controls whether some suggestion types should be filtered from IntelliSense. A list of suggestion types can be found here: https://code.visualstudio.com/docs/editor/intellisense#_types-of-completions."), - properties: { - method: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.method', "When set to `false` IntelliSense never shows `method` suggestions.") - }, - function: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.function', "When set to `false` IntelliSense never shows `function` suggestions.") - }, - constructor: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.constructor', "When set to `false` IntelliSense never shows `constructor` suggestions.") - }, - field: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.field', "When set to `false` IntelliSense never shows `field` suggestions.") - }, - variable: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.variable', "When set to `false` IntelliSense never shows `variable` suggestions.") - }, - class: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.class', "When set to `false` IntelliSense never shows `class` suggestions.") - }, - struct: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.struct', "When set to `false` IntelliSense never shows `struct` suggestions.") - }, - interface: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.interface', "When set to `false` IntelliSense never shows `interface` suggestions.") - }, - module: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.module', "When set to `false` IntelliSense never shows `module` suggestions.") - }, - property: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.property', "When set to `false` IntelliSense never shows `property` suggestions.") - }, - event: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.event', "When set to `false` IntelliSense never shows `event` suggestions.") - }, - operator: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.operator', "When set to `false` IntelliSense never shows `operator` suggestions.") - }, - unit: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.unit', "When set to `false` IntelliSense never shows `unit` suggestions.") - }, - value: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.value', "When set to `false` IntelliSense never shows `value` suggestions.") - }, - constant: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.constant', "When set to `false` IntelliSense never shows `constant` suggestions.") - }, - enum: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.enum', "When set to `false` IntelliSense never shows `enum` suggestions.") - }, - enumMember: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.enumMember', "When set to `false` IntelliSense never shows `enumMember` suggestions.") - }, - keyword: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.keyword', "When set to `false` IntelliSense never shows `keyword` suggestions.") - }, - text: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.text', "When set to `false` IntelliSense never shows `text` suggestions.") - }, - color: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.color', "When set to `false` IntelliSense never shows `color` suggestions.") - }, - file: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.file', "When set to `false` IntelliSense never shows `file` suggestions.") - }, - reference: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.reference', "When set to `false` IntelliSense never shows `reference` suggestions.") - }, - customcolor: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.customcolor', "When set to `false` IntelliSense never shows `customcolor` suggestions.") - }, - folder: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.folder', "When set to `false` IntelliSense never shows `folder` suggestions.") - }, - typeParameter: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.typeParameter', "When set to `false` IntelliSense never shows `typeParameter` suggestions.") - }, - snippet: { - type: 'boolean', - default: true, - markdownDescription: nls.localize('suggest.filtered.snippet', "When set to `false` IntelliSense never shows `snippet` suggestions.") - }, - } - }, - 'editor.gotoLocation.multiple': { - description: nls.localize('editor.gotoLocation.multiple', "Controls the behavior of 'Go To' commands, like Go To Definition, when multiple target locations exist."), - type: 'string', - enum: ['peek', 'gotoAndPeek', 'goto'], - default: EDITOR_DEFAULTS.contribInfo.gotoLocation.multiple, - enumDescriptions: [ - nls.localize('editor.gotoLocation.multiple.peek', 'Show peek view of the results (default)'), - nls.localize('editor.gotoLocation.multiple.gotoAndPeek', 'Go to the primary result and show a peek view'), - nls.localize('editor.gotoLocation.multiple.goto', 'Go to the primary result and enable peek-less navigation to others') - ] - }, - 'editor.selectionHighlight': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.selectionHighlight, - 'description': nls.localize('selectionHighlight', "Controls whether the editor should highlight matches similar to the selection.") - }, - 'editor.occurrencesHighlight': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.occurrencesHighlight, - 'description': nls.localize('occurrencesHighlight', "Controls whether the editor should highlight semantic symbol occurrences.") - }, - 'editor.overviewRulerLanes': { - 'type': 'integer', - 'default': 3, - 'description': nls.localize('overviewRulerLanes', "Controls the number of decorations that can show up at the same position in the overview ruler.") - }, - 'editor.overviewRulerBorder': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.overviewRulerBorder, - 'description': nls.localize('overviewRulerBorder', "Controls whether a border should be drawn around the overview ruler.") - }, - 'editor.cursorBlinking': { - 'type': 'string', - 'enum': ['blink', 'smooth', 'phase', 'expand', 'solid'], - 'default': editorOptions.blinkingStyleToString(EDITOR_DEFAULTS.viewInfo.cursorBlinking), - 'description': nls.localize('cursorBlinking', "Control the cursor animation style.") - }, - 'editor.mouseWheelZoom': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.mouseWheelZoom, - 'markdownDescription': nls.localize('mouseWheelZoom', "Zoom the font of the editor when using mouse wheel and holding `Ctrl`.") - }, - 'editor.cursorSmoothCaretAnimation': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.cursorSmoothCaretAnimation, - 'description': nls.localize('cursorSmoothCaretAnimation', "Controls whether the smooth caret animation should be enabled.") - }, - 'editor.cursorStyle': { - 'type': 'string', - 'enum': ['block', 'block-outline', 'line', 'line-thin', 'underline', 'underline-thin'], - 'default': editorOptions.cursorStyleToString(EDITOR_DEFAULTS.viewInfo.cursorStyle), - 'description': nls.localize('cursorStyle', "Controls the cursor style.") - }, - 'editor.cursorWidth': { - 'type': 'integer', - 'default': EDITOR_DEFAULTS.viewInfo.cursorWidth, - 'markdownDescription': nls.localize('cursorWidth', "Controls the width of the cursor when `#editor.cursorStyle#` is set to `line`.") - }, - 'editor.fontLigatures': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.fontLigatures, - 'description': nls.localize('fontLigatures', "Enables/Disables font ligatures.") - }, - 'editor.hideCursorInOverviewRuler': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.hideCursorInOverviewRuler, - 'description': nls.localize('hideCursorInOverviewRuler', "Controls whether the cursor should be hidden in the overview ruler.") - }, - 'editor.renderWhitespace': { - 'type': 'string', - 'enum': ['none', 'boundary', 'selection', 'all'], - 'enumDescriptions': [ - '', - nls.localize('renderWhitespace.boundary', "Render whitespace characters except for single spaces between words."), - nls.localize('renderWhitespace.selection', "Render whitespace characters only on selected text."), - '' - ], - default: EDITOR_DEFAULTS.viewInfo.renderWhitespace, - description: nls.localize('renderWhitespace', "Controls how the editor should render whitespace characters.") - }, - 'editor.renderControlCharacters': { - 'type': 'boolean', - default: EDITOR_DEFAULTS.viewInfo.renderControlCharacters, - description: nls.localize('renderControlCharacters', "Controls whether the editor should render control characters.") - }, - 'editor.renderIndentGuides': { - 'type': 'boolean', - default: EDITOR_DEFAULTS.viewInfo.renderIndentGuides, - description: nls.localize('renderIndentGuides', "Controls whether the editor should render indent guides.") - }, - 'editor.highlightActiveIndentGuide': { - 'type': 'boolean', - default: EDITOR_DEFAULTS.viewInfo.highlightActiveIndentGuide, - description: nls.localize('highlightActiveIndentGuide', "Controls whether the editor should highlight the active indent guide.") - }, - 'editor.renderLineHighlight': { - 'type': 'string', - 'enum': ['none', 'gutter', 'line', 'all'], - 'enumDescriptions': [ - '', - '', - '', - nls.localize('renderLineHighlight.all', "Highlights both the gutter and the current line."), - ], - default: EDITOR_DEFAULTS.viewInfo.renderLineHighlight, - description: nls.localize('renderLineHighlight', "Controls how the editor should render the current line highlight.") - }, - 'editor.codeLens': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.codeLens, - 'description': nls.localize('codeLens', "Controls whether the editor shows CodeLens.") - }, - 'editor.folding': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.folding, - 'description': nls.localize('folding', "Controls whether the editor has code folding enabled.") - }, - 'editor.foldingStrategy': { - 'type': 'string', - 'enum': ['auto', 'indentation'], - 'default': EDITOR_DEFAULTS.contribInfo.foldingStrategy, - 'markdownDescription': nls.localize('foldingStrategy', "Controls the strategy for computing folding ranges. `auto` uses a language specific folding strategy, if available. `indentation` uses the indentation based folding strategy.") - }, - 'editor.showFoldingControls': { - 'type': 'string', - 'enum': ['always', 'mouseover'], - 'default': EDITOR_DEFAULTS.contribInfo.showFoldingControls, - 'description': nls.localize('showFoldingControls', "Controls whether the fold controls on the gutter are automatically hidden.") - }, - 'editor.matchBrackets': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.matchBrackets, - 'description': nls.localize('matchBrackets', "Highlight matching brackets when one of them is selected.") - }, - 'editor.glyphMargin': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.viewInfo.glyphMargin, - 'description': nls.localize('glyphMargin', "Controls whether the editor should render the vertical glyph margin. Glyph margin is mostly used for debugging.") - }, - 'editor.useTabStops': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.useTabStops, - 'description': nls.localize('useTabStops', "Inserting and deleting whitespace follows tab stops.") + default: EDITOR_MODEL_DEFAULTS.detectIndentation, + markdownDescription: nls.localize('detectIndentation', "Controls whether `#editor.tabSize#` and `#editor.insertSpaces#` will be automatically detected when a file is opened based on the file contents.") }, 'editor.trimAutoWhitespace': { - 'type': 'boolean', - 'default': EDITOR_MODEL_DEFAULTS.trimAutoWhitespace, - 'description': nls.localize('trimAutoWhitespace', "Remove trailing auto inserted whitespace.") + type: 'boolean', + default: EDITOR_MODEL_DEFAULTS.trimAutoWhitespace, + description: nls.localize('trimAutoWhitespace', "Remove trailing auto inserted whitespace.") + }, + 'editor.largeFileOptimizations': { + type: 'boolean', + default: EDITOR_MODEL_DEFAULTS.largeFileOptimizations, + description: nls.localize('largeFileOptimizations', "Special handling for large files to disable certain memory intensive features.") + }, + 'editor.wordBasedSuggestions': { + type: 'boolean', + default: true, + description: nls.localize('wordBasedSuggestions', "Controls whether completions should be computed based on words in the document.") }, 'editor.stablePeek': { - 'type': 'boolean', - 'default': false, - 'markdownDescription': nls.localize('stablePeek', "Keep peek editors open even when double clicking their content or when hitting `Escape`.") - }, - 'editor.dragAndDrop': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.dragAndDrop, - 'description': nls.localize('dragAndDrop', "Controls whether the editor should allow moving selections via drag and drop.") - }, - 'editor.accessibilitySupport': { - 'type': 'string', - 'enum': ['auto', 'on', 'off'], - 'enumDescriptions': [ - nls.localize('accessibilitySupport.auto', "The editor will use platform APIs to detect when a Screen Reader is attached."), - nls.localize('accessibilitySupport.on', "The editor will be permanently optimized for usage with a Screen Reader."), - nls.localize('accessibilitySupport.off', "The editor will never be optimized for usage with a Screen Reader."), - ], - 'default': EDITOR_DEFAULTS.accessibilitySupport, - 'description': nls.localize('accessibilitySupport', "Controls whether the editor should run in a mode where it is optimized for screen readers.") - }, - 'editor.showUnused': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.showUnused, - 'description': nls.localize('showUnused', "Controls fading out of unused code.") - }, - 'editor.links': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.links, - 'description': nls.localize('links', "Controls whether the editor should detect links and make them clickable.") - }, - 'editor.colorDecorators': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.colorDecorators, - 'description': nls.localize('colorDecorators', "Controls whether the editor should render the inline color decorators and color picker.") - }, - 'editor.lightbulb.enabled': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.lightbulbEnabled, - 'description': nls.localize('codeActions', "Enables the code action lightbulb in the editor.") + type: 'boolean', + default: false, + markdownDescription: nls.localize('stablePeek', "Keep peek editors open even when double clicking their content or when hitting `Escape`.") }, 'editor.maxTokenizationLineLength': { - 'type': 'integer', - 'default': 20_000, - 'description': nls.localize('maxTokenizationLineLength', "Lines above this length will not be tokenized for performance reasons") + type: 'integer', + default: 20_000, + description: nls.localize('maxTokenizationLineLength', "Lines above this length will not be tokenized for performance reasons") }, 'editor.codeActionsOnSave': { - 'type': 'object', - 'properties': { + type: 'object', + properties: { 'source.organizeImports': { - 'type': 'boolean', - 'description': nls.localize('codeActionsOnSave.organizeImports', "Controls whether organize imports action should be run on file save.") + type: 'boolean', + description: nls.localize('codeActionsOnSave.organizeImports', "Controls whether organize imports action should be run on file save.") }, 'source.fixAll': { - 'type': 'boolean', - 'description': nls.localize('codeActionsOnSave.fixAll', "Controls whether auto fix action should be run on file save.") + type: 'boolean', + description: nls.localize('codeActionsOnSave.fixAll', "Controls whether auto fix action should be run on file save.") } }, 'additionalProperties': { - 'type': 'boolean' + type: 'boolean' }, - 'default': EDITOR_DEFAULTS.contribInfo.codeActionsOnSave, - 'description': nls.localize('codeActionsOnSave', "Code action kinds to be run on save.") + default: {}, + description: nls.localize('codeActionsOnSave', "Code action kinds to be run on save.") }, 'editor.codeActionsOnSaveTimeout': { - 'type': 'number', - 'default': EDITOR_DEFAULTS.contribInfo.codeActionsOnSaveTimeout, - 'description': nls.localize('codeActionsOnSaveTimeout', "Timeout in milliseconds after which the code actions that are run on save are cancelled.") - }, - 'editor.selectionClipboard': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.selectionClipboard, - 'description': nls.localize('selectionClipboard', "Controls whether the Linux primary clipboard should be supported."), - 'included': platform.isLinux + type: 'number', + default: 750, + description: nls.localize('codeActionsOnSaveTimeout', "Timeout in milliseconds after which the code actions that are run on save are cancelled.") }, 'diffEditor.renderSideBySide': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('sideBySide', "Controls whether the diff editor shows the diff side by side or inline.") + type: 'boolean', + default: true, + description: nls.localize('sideBySide', "Controls whether the diff editor shows the diff side by side or inline.") }, 'diffEditor.ignoreTrimWhitespace': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('ignoreTrimWhitespace', "Controls whether the diff editor shows changes in leading or trailing whitespace as diffs.") - }, - 'editor.largeFileOptimizations': { - 'type': 'boolean', - 'default': EDITOR_MODEL_DEFAULTS.largeFileOptimizations, - 'description': nls.localize('largeFileOptimizations', "Special handling for large files to disable certain memory intensive features.") + type: 'boolean', + default: true, + description: nls.localize('ignoreTrimWhitespace', "Controls whether the diff editor shows changes in leading or trailing whitespace as diffs.") }, 'diffEditor.renderIndicators': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('renderIndicators', "Controls whether the diff editor shows +/- indicators for added/removed changes.") + type: 'boolean', + default: true, + description: nls.localize('renderIndicators', "Controls whether the diff editor shows +/- indicators for added/removed changes.") } } }; +function isConfigurationPropertySchema(x: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; }): x is IConfigurationPropertySchema { + return (typeof x.type !== 'undefined' || typeof x.anyOf !== 'undefined'); +} + +// Add properties from the Editor Option Registry +for (const editorOption of editorOptionsRegistry) { + const schema = editorOption.schema; + if (typeof schema !== 'undefined') { + if (isConfigurationPropertySchema(schema)) { + // This is a single schema contribution + editorConfiguration.properties![`editor.${editorOption.name}`] = schema; + } else { + for (let key in schema) { + if (hasOwnProperty.call(schema, key)) { + editorConfiguration.properties![key] = schema[key]; + } + } + } + } +} + let cachedEditorConfigurationKeys: { [key: string]: boolean; } | null = null; function getEditorConfigurationKeys(): { [key: string]: boolean; } { if (cachedEditorConfigurationKeys === null) { diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 43c568a191f..4b9206e1cdd 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import * as arrays from 'vs/base/common/arrays'; -import * as objects from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { FontInfo } from 'vs/editor/common/config/fontInfo'; @@ -13,90 +11,9 @@ import { Constants } from 'vs/editor/common/core/uint'; import { USUAL_WORD_SEPARATORS } from 'vs/editor/common/model/wordHelper'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { isObject } from 'vs/base/common/types'; +import { IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry'; -/** - * Configuration options for editor scrollbars - */ -export interface IEditorScrollbarOptions { - /** - * The size of arrows (if displayed). - * Defaults to 11. - */ - arrowSize?: number; - /** - * Render vertical scrollbar. - * Defaults to 'auto'. - */ - vertical?: 'auto' | 'visible' | 'hidden'; - /** - * Render horizontal scrollbar. - * Defaults to 'auto'. - */ - horizontal?: 'auto' | 'visible' | 'hidden'; - /** - * Cast horizontal and vertical shadows when the content is scrolled. - * Defaults to true. - */ - useShadows?: boolean; - /** - * Render arrows at the top and bottom of the vertical scrollbar. - * Defaults to false. - */ - verticalHasArrows?: boolean; - /** - * Render arrows at the left and right of the horizontal scrollbar. - * Defaults to false. - */ - horizontalHasArrows?: boolean; - /** - * Listen to mouse wheel events and react to them by scrolling. - * Defaults to true. - */ - handleMouseWheel?: boolean; - /** - * Height in pixels for the horizontal scrollbar. - * Defaults to 10 (px). - */ - horizontalScrollbarSize?: number; - /** - * Width in pixels for the vertical scrollbar. - * Defaults to 10 (px). - */ - verticalScrollbarSize?: number; - /** - * Width in pixels for the vertical slider. - * Defaults to `verticalScrollbarSize`. - */ - verticalSliderSize?: number; - /** - * Height in pixels for the horizontal slider. - * Defaults to `horizontalScrollbarSize`. - */ - horizontalSliderSize?: number; -} - -/** - * Configuration options for editor find widget - */ -export interface IEditorFindOptions { - /** - * Controls if we seed search string in the Find Widget with editor selection. - */ - seedSearchStringFromSelection?: boolean; - /** - * Controls if Find in Selection flag is turned on when multiple lines of text are selected in the editor. - */ - autoFindInSelection: boolean; - /* - * Controls whether the Find Widget should add extra lines on top of the editor. - */ - addExtraSpaceOnTop?: boolean; - /** - * @internal - * Controls if the Find Widget should read or modify the shared find clipboard on macOS - */ - globalFindClipboard: boolean; -} +//#region typed options /** * Configuration options for auto closing quotes and brackets @@ -113,137 +30,12 @@ export type EditorAutoSurroundStrategy = 'languageDefined' | 'quotes' | 'bracket */ export type EditorAutoClosingOvertypeStrategy = 'always' | 'auto' | 'never'; -/** - * Configuration options for editor minimap - */ -export interface IEditorMinimapOptions { - /** - * Enable the rendering of the minimap. - * Defaults to true. - */ - enabled?: boolean; - /** - * Control the side of the minimap in editor. - * Defaults to 'right'. - */ - side?: 'right' | 'left'; - /** - * Control the rendering of the minimap slider. - * Defaults to 'mouseover'. - */ - showSlider?: 'always' | 'mouseover'; - /** - * Render the actual text on a line (as opposed to color blocks). - * Defaults to true. - */ - renderCharacters?: boolean; - /** - * Limit the width of the minimap to render at most a certain number of columns. - * Defaults to 120. - */ - maxColumn?: number; -} - -/** - * Configuration options for editor minimap - */ -export interface IEditorLightbulbOptions { - /** - * Enable the lightbulb code action. - * Defaults to true. - */ - enabled?: boolean; -} - -/** - * Configuration options for editor hover - */ -export interface IEditorHoverOptions { - /** - * Enable the hover. - * Defaults to true. - */ - enabled?: boolean; - /** - * Delay for showing the hover. - * Defaults to 300. - */ - delay?: number; - /** - * Is the hover sticky such that it can be clicked and its contents selected? - * Defaults to true. - */ - sticky?: boolean; -} - -/** - * Configuration options for parameter hints - */ -export interface IEditorParameterHintOptions { - /** - * Enable parameter hints. - * Defaults to true. - */ - enabled?: boolean; - /** - * Enable cycling of parameter hints. - * Defaults to false. - */ - cycle?: boolean; -} - -export interface ISuggestOptions { - /** - * Enable graceful matching. Defaults to true. - */ - filterGraceful?: boolean; - /** - * Prevent quick suggestions when a snippet is active. Defaults to true. - */ - snippetsPreventQuickSuggestions?: boolean; - /** - * Favours words that appear close to the cursor. - */ - localityBonus?: boolean; - /** - * Enable using global storage for remembering suggestions. - */ - shareSuggestSelections?: boolean; - /** - * Enable or disable icons in suggestions. Defaults to true. - */ - showIcons?: boolean; - /** - * Max suggestions to show in suggestions. Defaults to 12. - */ - maxVisibleSuggestions?: boolean; - /** - * Names of suggestion types to filter. - */ - filteredTypes?: Record; -} - -export interface IGotoLocationOptions { - /** - * Control how goto-command work when having multiple results. - */ - multiple?: 'peek' | 'gotoAndPeek' | 'goto'; -} - -/** - * Configuration map for codeActionsOnSave - */ -export interface ICodeActionsOnSaveOptions { - [kind: string]: boolean; -} - /** * Configuration options for the editor. */ export interface IEditorOptions { /** * This editor is used inside a diff editor. - * @internal */ inDiffEditor?: boolean; /** @@ -272,7 +64,7 @@ export interface IEditorOptions { * Otherwise, line numbers will not be rendered. * Defaults to true. */ - lineNumbers?: 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string); + lineNumbers?: LineNumbersType; /** * Controls the minimal number of visible leading and trailing lines surrounding the cursor. * Defaults to 0. @@ -356,7 +148,7 @@ export interface IEditorOptions { * Control the cursor animation style, possible values are 'blink', 'smooth', 'phase', 'expand' and 'solid'. * Defaults to 'blink'. */ - cursorBlinking?: string; + cursorBlinking?: 'blink' | 'smooth' | 'phase' | 'expand' | 'solid'; /** * Zoom the font in the editor when using the mouse wheel in combination with holding Ctrl. * Defaults to false. @@ -365,7 +157,6 @@ export interface IEditorOptions { /** * Control the mouse pointer style, either 'text' or 'default' or 'copy' * Defaults to 'text' - * @internal */ mouseStyle?: 'text' | 'default' | 'copy'; /** @@ -377,7 +168,7 @@ export interface IEditorOptions { * Control the cursor style, either 'block' or 'line'. * Defaults to 'line'. */ - cursorStyle?: string; + cursorStyle?: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin'; /** * Control the width of the cursor when cursorStyle is set to 'line' */ @@ -451,7 +242,7 @@ export interface IEditorOptions { * Control indentation of wrapped lines. Can be: 'none', 'same', 'indent' or 'deepIndent'. * Defaults to 'same' in vscode and to 'none' in monaco-editor. */ - wrappingIndent?: string; + wrappingIndent?: 'none' | 'same' | 'indent' | 'deepIndent'; /** * Configure word wrapping characters. A break will be introduced before these characters. * Defaults to '{([+'. @@ -467,7 +258,6 @@ export interface IEditorOptions { * Defaults to '.'. */ wordWrapBreakObtrusiveCharacters?: string; - /** * Performance guard: Stop rendering a line after x characters. * Defaults to 10000. @@ -512,6 +302,11 @@ export interface IEditorOptions { * Defaults to true */ multiCursorMergeOverlapping?: boolean; + /** + * Configure the behaviour when pasting a text with the line count equal to the cursor count. + * Defaults to 'spread'. + */ + multiCursorPaste?: 'spread' | 'full'; /** * Configure the editor's accessibility support. * Defaults to 'auto'. It is best to leave this to 'auto'. @@ -529,10 +324,10 @@ export interface IEditorOptions { * Enable quick suggestions (shadow suggestions) * Defaults to true. */ - quickSuggestions?: boolean | { other: boolean, comments: boolean, strings: boolean }; + quickSuggestions?: boolean | IQuickSuggestionsOptions; /** * Quick suggestions show delay (in ms) - * Defaults to 500 (ms) + * Defaults to 10 (ms) */ quickSuggestionsDelay?: number; /** @@ -587,7 +382,7 @@ export interface IEditorOptions { * Accept suggestions on ENTER. * Defaults to 'on'. */ - acceptSuggestionOnEnter?: boolean | 'on' | 'smart' | 'off'; + acceptSuggestionOnEnter?: 'on' | 'smart' | 'off'; /** * Accept suggestions on provider defined characters. * Defaults to true. @@ -605,10 +400,6 @@ export interface IEditorOptions { * Syntax highlighting is copied. */ copyWithSyntaxHighlighting?: boolean; - /** - * Enable word based suggestions. Defaults to 'true' - */ - wordBasedSuggestions?: boolean; /** * The history mode for suggestions. */ @@ -626,7 +417,7 @@ export interface IEditorOptions { /** * Enable tab completion. */ - tabCompletion?: boolean | 'on' | 'off' | 'onlySnippets'; + tabCompletion?: 'on' | 'off' | 'onlySnippets'; /** * Enable selection highlight. * Defaults to true. @@ -646,10 +437,6 @@ export interface IEditorOptions { * Control the behavior and rendering of the code action lightbulb. */ lightbulb?: IEditorLightbulbOptions; - /** - * Code action kinds to be run on save. - */ - codeActionsOnSave?: ICodeActionsOnSaveOptions; /** * Timeout for running code actions on save. */ @@ -710,7 +497,7 @@ export interface IEditorOptions { /** * The font weight */ - fontWeight?: 'normal' | 'bold' | 'bolder' | 'lighter' | 'initial' | 'inherit' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; + fontWeight?: string; /** * The font size */ @@ -760,36 +547,389 @@ export interface IDiffEditorOptions extends IEditorOptions { originalEditable?: boolean; } -export const enum RenderMinimap { - None = 0, - Small = 1, - Large = 2, - SmallBlocks = 3, - LargeBlocks = 4, +//#endregion + +/** + * An event describing that the configuration of the editor has changed. + */ +export class ConfigurationChangedEvent { + private readonly _values: boolean[]; + /** + * @internal + */ + constructor(values: boolean[]) { + this._values = values; + } + /** + * @internal + */ + public hasChanged(id: EditorOption): boolean { + return this._values[id]; + } } /** - * Describes how to indent wrapped lines. + * @internal */ -export const enum WrappingIndent { - /** - * No indentation => wrapped lines begin at column 1. - */ - None = 0, - /** - * Same => wrapped lines get the same indentation as the parent. - */ - Same = 1, - /** - * Indent => wrapped lines get +1 indentation toward the parent. - */ - Indent = 2, - /** - * DeepIndent => wrapped lines get +2 indentation toward the parent. - */ - DeepIndent = 3 +export class ValidatedEditorOptions { + private readonly _values: any[] = []; + public _read(option: EditorOption): T { + return this._values[option]; + } + public get(id: T): FindComputedEditorOptionValueById { + return this._values[id]; + } + public _write(option: EditorOption, value: T): void { + this._values[option] = value; + } } +/** + * @internal + */ +export interface IComputedEditorOptions { + get(id: T): FindComputedEditorOptionValueById; +} + +//#region IEditorOption + +/** + * @internal + */ +export interface IEnvironmentalOptions { + readonly outerWidth: number; + readonly outerHeight: number; + readonly fontInfo: FontInfo; + readonly extraEditorClassName: string; + readonly isDominatedByLongLines: boolean; + readonly lineNumbersDigitCount: number; + readonly emptySelectionClipboard: boolean; + readonly pixelRatio: number; + readonly tabFocusMode: boolean; + readonly accessibilitySupport: AccessibilitySupport; +} + +/** + * @internal + */ +export interface IEditorOption { + readonly id: K1; + readonly name: string; + readonly defaultValue: V; + /** + * @internal + */ + readonly schema: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; } | undefined; + /** + * @internal + */ + validate(input: any): V; + /** + * @internal + */ + compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V; +} + +type PossibleKeyName0 = { [K in keyof IEditorOptions]: IEditorOptions[K] extends V | undefined ? K : never }[keyof IEditorOptions]; +type PossibleKeyName = NonNullable>; + +abstract class BaseEditorOption implements IEditorOption { + + public readonly id: K1; + public readonly name: string; + public readonly defaultValue: V; + public readonly schema: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; } | undefined; + + constructor(id: K1, name: string, defaultValue: V, schema?: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; }) { + this.id = id; + this.name = name; + this.defaultValue = defaultValue; + this.schema = schema; + } + + public abstract validate(input: any): V; + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V { + return value; + } +} + +/** + * @internal + */ +abstract class ComputedEditorOption implements IEditorOption { + + public readonly id: K1; + public readonly name: '_never_'; + public readonly defaultValue: V; + public readonly deps: EditorOption[] | null; + public readonly schema: IConfigurationPropertySchema | undefined = undefined; + + constructor(id: K1, deps: EditorOption[] | null = null) { + this.id = id; + this.name = '_never_'; + this.defaultValue = undefined; + this.deps = deps; + } + + public validate(input: any): V { + return this.defaultValue; + } + + public abstract compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V; +} + +class SimpleEditorOption implements IEditorOption { + + public readonly id: K1; + public readonly name: PossibleKeyName; + public readonly defaultValue: V; + public readonly schema: IConfigurationPropertySchema | undefined; + + constructor(id: K1, name: PossibleKeyName, defaultValue: V, schema?: IConfigurationPropertySchema) { + this.id = id; + this.name = name; + this.defaultValue = defaultValue; + this.schema = schema; + } + + public validate(input: any): V { + if (typeof input === 'undefined') { + return this.defaultValue; + } + return input as any; + } + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V { + return value; + } +} + +class EditorBooleanOption extends SimpleEditorOption { + + public static boolean(value: any, defaultValue: boolean): boolean { + if (typeof value === 'undefined') { + return defaultValue; + } + if (value === 'false') { + // treat the string 'false' as false + return false; + } + return Boolean(value); + } + + constructor(id: K1, name: PossibleKeyName, defaultValue: boolean, schema: IConfigurationPropertySchema | undefined = undefined) { + if (typeof schema !== 'undefined') { + schema.type = 'boolean'; + schema.default = defaultValue; + } + super(id, name, defaultValue, schema); + } + + public validate(input: any): boolean { + return EditorBooleanOption.boolean(input, this.defaultValue); + } +} + +class EditorIntOption extends SimpleEditorOption { + + public static clampedInt(value: any, defaultValue: number, minimum: number, maximum: number): number { + let r: number; + if (typeof value === 'undefined') { + r = defaultValue; + } else { + r = parseInt(value, 10); + if (isNaN(r)) { + r = defaultValue; + } + } + r = Math.max(minimum, r); + r = Math.min(maximum, r); + return r | 0; + } + + public readonly minimum: number; + public readonly maximum: number; + + constructor(id: K1, name: PossibleKeyName, defaultValue: number, minimum: number, maximum: number, schema: IConfigurationPropertySchema | undefined = undefined) { + if (typeof schema !== 'undefined') { + schema.type = 'integer'; + schema.default = defaultValue; + schema.minimum = minimum; + schema.maximum = maximum; + } + super(id, name, defaultValue, schema); + this.minimum = minimum; + this.maximum = maximum; + } + + public validate(input: any): number { + return EditorIntOption.clampedInt(input, this.defaultValue, this.minimum, this.maximum); + } +} + +class EditorFloatOption extends SimpleEditorOption { + + public static clamp(n: number, min: number, max: number): number { + if (n < min) { + return min; + } + if (n > max) { + return max; + } + return n; + } + + public static float(value: any, defaultValue: number): number { + if (typeof value === 'number') { + return value; + } + if (typeof value === 'undefined') { + return defaultValue; + } + const r = parseFloat(value); + return (isNaN(r) ? defaultValue : r); + } + + public readonly validationFn: (value: number) => number; + + constructor(id: K1, name: PossibleKeyName, defaultValue: number, validationFn: (value: number) => number, schema?: IConfigurationPropertySchema) { + if (typeof schema !== 'undefined') { + schema.type = 'number'; + schema.default = defaultValue; + } + super(id, name, defaultValue, schema); + this.validationFn = validationFn; + } + + public validate(input: any): number { + return this.validationFn(EditorFloatOption.float(input, this.defaultValue)); + } +} + +class EditorStringOption extends SimpleEditorOption { + + public static string(value: any, defaultValue: string): string { + if (typeof value !== 'string') { + return defaultValue; + } + return value; + } + + constructor(id: K1, name: PossibleKeyName, defaultValue: string, schema: IConfigurationPropertySchema | undefined = undefined) { + if (typeof schema !== 'undefined') { + schema.type = 'string'; + schema.default = defaultValue; + } + super(id, name, defaultValue, schema); + } + + public validate(input: any): string { + return EditorStringOption.string(input, this.defaultValue); + } +} + +class EditorStringEnumOption extends SimpleEditorOption { + + public static stringSet(value: T | undefined, defaultValue: T, allowedValues: ReadonlyArray): T { + if (typeof value !== 'string') { + return defaultValue; + } + if (allowedValues.indexOf(value) === -1) { + return defaultValue; + } + return value; + } + + private readonly _allowedValues: ReadonlyArray; + + constructor(id: K1, name: PossibleKeyName, defaultValue: V, allowedValues: ReadonlyArray, schema: IConfigurationPropertySchema | undefined = undefined) { + if (typeof schema !== 'undefined') { + schema.type = 'string'; + schema.enum = allowedValues; + schema.default = defaultValue; + } + super(id, name, defaultValue, schema); + this._allowedValues = allowedValues; + } + + public validate(input: any): V { + return EditorStringEnumOption.stringSet(input, this.defaultValue, this._allowedValues); + } +} + +class EditorEnumOption extends BaseEditorOption { + + private readonly _allowedValues: T[]; + private readonly _convert: (value: T) => V; + + constructor(id: K1, name: PossibleKeyName, defaultValue: V, defaultStringValue: string, allowedValues: T[], convert: (value: T) => V, schema: IConfigurationPropertySchema | undefined = undefined) { + if (typeof schema !== 'undefined') { + schema.type = 'string'; + schema.enum = allowedValues; + schema.default = defaultStringValue; + } + super(id, name, defaultValue, schema); + this._allowedValues = allowedValues; + this._convert = convert; + } + + public validate(input: any): V { + if (typeof input !== 'string') { + return this.defaultValue; + } + if (this._allowedValues.indexOf(input) === -1) { + return this.defaultValue; + } + return this._convert(input); + } +} + +//#endregion + +//#region accessibilitySupport + +class EditorAccessibilitySupport extends BaseEditorOption { + + constructor() { + super( + EditorOption.accessibilitySupport, 'accessibilitySupport', AccessibilitySupport.Unknown, + { + type: 'string', + enum: ['auto', 'on', 'off'], + enumDescriptions: [ + nls.localize('accessibilitySupport.auto', "The editor will use platform APIs to detect when a Screen Reader is attached."), + nls.localize('accessibilitySupport.on', "The editor will be permanently optimized for usage with a Screen Reader."), + nls.localize('accessibilitySupport.off', "The editor will never be optimized for usage with a Screen Reader."), + ], + default: 'auto', + description: nls.localize('accessibilitySupport', "Controls whether the editor should run in a mode where it is optimized for screen readers.") + } + ); + } + + public validate(input: any): AccessibilitySupport { + switch (input) { + case 'auto': return AccessibilitySupport.Unknown; + case 'off': return AccessibilitySupport.Disabled; + case 'on': return AccessibilitySupport.Enabled; + } + return this.defaultValue; + } + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: AccessibilitySupport): AccessibilitySupport { + if (value === AccessibilitySupport.Unknown) { + // The editor reads the `accessibilitySupport` from the environment + return env.accessibilitySupport; + } + return value; + } +} + +//#endregion + +//#region cursorBlinking + /** * The kind of animation in which the editor's cursor should be rendered. */ @@ -819,25 +959,21 @@ export const enum TextEditorCursorBlinkingStyle { */ Solid = 5 } -/** - * @internal - */ -export function blinkingStyleToString(blinkingStyle: TextEditorCursorBlinkingStyle): string { - if (blinkingStyle === TextEditorCursorBlinkingStyle.Blink) { - return 'blink'; - } else if (blinkingStyle === TextEditorCursorBlinkingStyle.Expand) { - return 'expand'; - } else if (blinkingStyle === TextEditorCursorBlinkingStyle.Phase) { - return 'phase'; - } else if (blinkingStyle === TextEditorCursorBlinkingStyle.Smooth) { - return 'smooth'; - } else if (blinkingStyle === TextEditorCursorBlinkingStyle.Solid) { - return 'solid'; - } else { - throw new Error('blinkingStyleToString: Unknown blinkingStyle'); + +function _cursorBlinkingStyleFromString(cursorBlinkingStyle: 'blink' | 'smooth' | 'phase' | 'expand' | 'solid'): TextEditorCursorBlinkingStyle { + switch (cursorBlinkingStyle) { + case 'blink': return TextEditorCursorBlinkingStyle.Blink; + case 'smooth': return TextEditorCursorBlinkingStyle.Smooth; + case 'phase': return TextEditorCursorBlinkingStyle.Phase; + case 'expand': return TextEditorCursorBlinkingStyle.Expand; + case 'solid': return TextEditorCursorBlinkingStyle.Solid; } } +//#endregion + +//#region cursorStyle + /** * The style in which the editor's cursor should be rendered. */ @@ -871,647 +1007,325 @@ export enum TextEditorCursorStyle { /** * @internal */ -export function cursorStyleToString(cursorStyle: TextEditorCursorStyle): string { - if (cursorStyle === TextEditorCursorStyle.Line) { - return 'line'; - } else if (cursorStyle === TextEditorCursorStyle.Block) { - return 'block'; - } else if (cursorStyle === TextEditorCursorStyle.Underline) { - return 'underline'; - } else if (cursorStyle === TextEditorCursorStyle.LineThin) { - return 'line-thin'; - } else if (cursorStyle === TextEditorCursorStyle.BlockOutline) { - return 'block-outline'; - } else if (cursorStyle === TextEditorCursorStyle.UnderlineThin) { - return 'underline-thin'; - } else { - throw new Error('cursorStyleToString: Unknown cursorStyle'); +export function cursorStyleToString(cursorStyle: TextEditorCursorStyle): 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin' { + switch (cursorStyle) { + case TextEditorCursorStyle.Line: return 'line'; + case TextEditorCursorStyle.Block: return 'block'; + case TextEditorCursorStyle.Underline: return 'underline'; + case TextEditorCursorStyle.LineThin: return 'line-thin'; + case TextEditorCursorStyle.BlockOutline: return 'block-outline'; + case TextEditorCursorStyle.UnderlineThin: return 'underline-thin'; } } -function _cursorStyleFromString(cursorStyle: string | undefined, defaultValue: TextEditorCursorStyle): TextEditorCursorStyle { - if (typeof cursorStyle !== 'string') { - return defaultValue; +function _cursorStyleFromString(cursorStyle: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin'): TextEditorCursorStyle { + switch (cursorStyle) { + case 'line': return TextEditorCursorStyle.Line; + case 'block': return TextEditorCursorStyle.Block; + case 'underline': return TextEditorCursorStyle.Underline; + case 'line-thin': return TextEditorCursorStyle.LineThin; + case 'block-outline': return TextEditorCursorStyle.BlockOutline; + case 'underline-thin': return TextEditorCursorStyle.UnderlineThin; } - if (cursorStyle === 'line') { - return TextEditorCursorStyle.Line; - } else if (cursorStyle === 'block') { - return TextEditorCursorStyle.Block; - } else if (cursorStyle === 'underline') { - return TextEditorCursorStyle.Underline; - } else if (cursorStyle === 'line-thin') { - return TextEditorCursorStyle.LineThin; - } else if (cursorStyle === 'block-outline') { - return TextEditorCursorStyle.BlockOutline; - } else if (cursorStyle === 'underline-thin') { - return TextEditorCursorStyle.UnderlineThin; - } - return TextEditorCursorStyle.Line; } -export interface InternalEditorScrollbarOptions { - readonly arrowSize: number; - readonly vertical: ScrollbarVisibility; - readonly horizontal: ScrollbarVisibility; - readonly useShadows: boolean; - readonly verticalHasArrows: boolean; - readonly horizontalHasArrows: boolean; - readonly handleMouseWheel: boolean; - readonly horizontalScrollbarSize: number; - readonly horizontalSliderSize: number; - readonly verticalScrollbarSize: number; - readonly verticalSliderSize: number; - readonly mouseWheelScrollSensitivity: number; - readonly fastScrollSensitivity: number; -} +//#endregion -export interface InternalEditorMinimapOptions { - readonly enabled: boolean; - readonly side: 'right' | 'left'; - readonly showSlider: 'always' | 'mouseover'; - readonly renderCharacters: boolean; - readonly maxColumn: number; -} +//#region editorClassName -export interface InternalEditorFindOptions { - readonly seedSearchStringFromSelection: boolean; - readonly autoFindInSelection: boolean; - readonly addExtraSpaceOnTop: boolean; - /** - * @internal - */ - readonly globalFindClipboard: boolean; -} +class EditorClassName extends ComputedEditorOption { -export interface InternalEditorHoverOptions { - readonly enabled: boolean; - readonly delay: number; - readonly sticky: boolean; -} - -export interface InternalGoToLocationOptions { - readonly multiple: 'peek' | 'gotoAndPeek' | 'goto'; -} - -export interface InternalSuggestOptions { - readonly filterGraceful: boolean; - readonly snippets: 'top' | 'bottom' | 'inline' | 'none'; - readonly snippetsPreventQuickSuggestions: boolean; - readonly localityBonus: boolean; - readonly shareSuggestSelections: boolean; - readonly showIcons: boolean; - readonly maxVisibleSuggestions: number; - readonly filteredTypes: Record; -} - -export interface InternalParameterHintOptions { - readonly enabled: boolean; - readonly cycle: boolean; -} - -export interface EditorWrappingInfo { - readonly inDiffEditor: boolean; - readonly isDominatedByLongLines: boolean; - readonly isWordWrapMinified: boolean; - readonly isViewportWrapping: boolean; - readonly wrappingColumn: number; - readonly wrappingIndent: WrappingIndent; - readonly wordWrapBreakBeforeCharacters: string; - readonly wordWrapBreakAfterCharacters: string; - readonly wordWrapBreakObtrusiveCharacters: string; -} - -export const enum RenderLineNumbersType { - Off = 0, - On = 1, - Relative = 2, - Interval = 3, - Custom = 4 -} - -export interface InternalEditorViewOptions { - readonly extraEditorClassName: string; - readonly disableMonospaceOptimizations: boolean; - readonly rulers: number[]; - readonly ariaLabel: string; - readonly renderLineNumbers: RenderLineNumbersType; - readonly renderCustomLineNumbers: ((lineNumber: number) => string) | null; - readonly cursorSurroundingLines: number; - readonly renderFinalNewline: boolean; - readonly selectOnLineNumbers: boolean; - readonly glyphMargin: boolean; - readonly revealHorizontalRightPadding: number; - readonly roundedSelection: boolean; - readonly overviewRulerLanes: number; - readonly overviewRulerBorder: boolean; - readonly cursorBlinking: TextEditorCursorBlinkingStyle; - readonly mouseWheelZoom: boolean; - readonly cursorSmoothCaretAnimation: boolean; - readonly cursorStyle: TextEditorCursorStyle; - readonly cursorWidth: number; - readonly hideCursorInOverviewRuler: boolean; - readonly scrollBeyondLastLine: boolean; - readonly scrollBeyondLastColumn: number; - readonly smoothScrolling: boolean; - readonly stopRenderingLineAfter: number; - readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all'; - readonly renderControlCharacters: boolean; - readonly fontLigatures: boolean; - readonly renderIndentGuides: boolean; - readonly highlightActiveIndentGuide: boolean; - readonly renderLineHighlight: 'none' | 'gutter' | 'line' | 'all'; - readonly scrollbar: InternalEditorScrollbarOptions; - readonly minimap: InternalEditorMinimapOptions; - readonly fixedOverflowWidgets: boolean; -} - -export interface EditorContribOptions { - readonly selectionClipboard: boolean; - readonly hover: InternalEditorHoverOptions; - readonly links: boolean; - readonly contextmenu: boolean; - readonly quickSuggestions: boolean | { other: boolean, comments: boolean, strings: boolean }; - readonly quickSuggestionsDelay: number; - readonly parameterHints: InternalParameterHintOptions; - readonly formatOnType: boolean; - readonly formatOnPaste: boolean; - readonly suggestOnTriggerCharacters: boolean; - readonly acceptSuggestionOnEnter: 'on' | 'smart' | 'off'; - readonly acceptSuggestionOnCommitCharacter: boolean; - readonly wordBasedSuggestions: boolean; - readonly suggestSelection: 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix'; - readonly suggestFontSize: number; - readonly suggestLineHeight: number; - readonly tabCompletion: 'on' | 'off' | 'onlySnippets'; - readonly suggest: InternalSuggestOptions; - readonly gotoLocation: InternalGoToLocationOptions; - readonly selectionHighlight: boolean; - readonly occurrencesHighlight: boolean; - readonly codeLens: boolean; - readonly folding: boolean; - readonly foldingStrategy: 'auto' | 'indentation'; - readonly showFoldingControls: 'always' | 'mouseover'; - readonly matchBrackets: boolean; - readonly find: InternalEditorFindOptions; - readonly colorDecorators: boolean; - readonly lightbulbEnabled: boolean; - readonly codeActionsOnSave: ICodeActionsOnSaveOptions; - readonly codeActionsOnSaveTimeout: number; -} - -/** - * Validated configuration options for the editor. - * This is a 1 to 1 validated/parsed version of IEditorOptions merged on top of the defaults. - * @internal - */ -export interface IValidatedEditorOptions { - readonly inDiffEditor: boolean; - readonly wordSeparators: string; - readonly lineNumbersMinChars: number; - readonly lineDecorationsWidth: number | string; - readonly readOnly: boolean; - readonly mouseStyle: 'text' | 'default' | 'copy'; - readonly disableLayerHinting: boolean; - readonly automaticLayout: boolean; - readonly wordWrap: 'off' | 'on' | 'wordWrapColumn' | 'bounded'; - readonly wordWrapColumn: number; - readonly wordWrapMinified: boolean; - readonly wrappingIndent: WrappingIndent; - readonly wordWrapBreakBeforeCharacters: string; - readonly wordWrapBreakAfterCharacters: string; - readonly wordWrapBreakObtrusiveCharacters: string; - readonly autoClosingBrackets: EditorAutoClosingStrategy; - readonly autoClosingQuotes: EditorAutoClosingStrategy; - readonly autoClosingOvertype: EditorAutoClosingOvertypeStrategy; - readonly autoSurround: EditorAutoSurroundStrategy; - readonly autoIndent: boolean; - readonly dragAndDrop: boolean; - readonly emptySelectionClipboard: boolean; - readonly copyWithSyntaxHighlighting: boolean; - readonly useTabStops: boolean; - readonly multiCursorModifier: 'altKey' | 'ctrlKey' | 'metaKey'; - readonly multiCursorMergeOverlapping: boolean; - readonly accessibilitySupport: 'auto' | 'off' | 'on'; - readonly showUnused: boolean; - - readonly viewInfo: InternalEditorViewOptions; - readonly contribInfo: EditorContribOptions; -} - -/** - * Internal configuration options (transformed or computed) for the editor. - */ -export class InternalEditorOptions { - readonly _internalEditorOptionsBrand: void; - - readonly canUseLayerHinting: boolean; - readonly pixelRatio: number; - readonly editorClassName: string; - readonly lineHeight: number; - readonly readOnly: boolean; - /** - * @internal - */ - readonly accessibilitySupport: AccessibilitySupport; - readonly multiCursorModifier: 'altKey' | 'ctrlKey' | 'metaKey'; - readonly multiCursorMergeOverlapping: boolean; - readonly showUnused: boolean; - - // ---- cursor options - readonly wordSeparators: string; - readonly autoClosingBrackets: EditorAutoClosingStrategy; - readonly autoClosingQuotes: EditorAutoClosingStrategy; - readonly autoClosingOvertype: EditorAutoClosingOvertypeStrategy; - readonly autoSurround: EditorAutoSurroundStrategy; - readonly autoIndent: boolean; - readonly useTabStops: boolean; - readonly tabFocusMode: boolean; - readonly dragAndDrop: boolean; - readonly emptySelectionClipboard: boolean; - readonly copyWithSyntaxHighlighting: boolean; - - // ---- grouped options - readonly layoutInfo: EditorLayoutInfo; - readonly fontInfo: FontInfo; - readonly viewInfo: InternalEditorViewOptions; - readonly wrappingInfo: EditorWrappingInfo; - readonly contribInfo: EditorContribOptions; - - /** - * @internal - */ - constructor(source: { - canUseLayerHinting: boolean; - pixelRatio: number; - editorClassName: string; - lineHeight: number; - readOnly: boolean; - accessibilitySupport: AccessibilitySupport; - multiCursorModifier: 'altKey' | 'ctrlKey' | 'metaKey'; - multiCursorMergeOverlapping: boolean; - wordSeparators: string; - autoClosingBrackets: EditorAutoClosingStrategy; - autoClosingQuotes: EditorAutoClosingStrategy; - autoClosingOvertype: EditorAutoClosingOvertypeStrategy; - autoSurround: EditorAutoSurroundStrategy; - autoIndent: boolean; - useTabStops: boolean; - tabFocusMode: boolean; - dragAndDrop: boolean; - emptySelectionClipboard: boolean; - copyWithSyntaxHighlighting: boolean; - layoutInfo: EditorLayoutInfo; - fontInfo: FontInfo; - viewInfo: InternalEditorViewOptions; - wrappingInfo: EditorWrappingInfo; - contribInfo: EditorContribOptions; - showUnused: boolean; - }) { - this.canUseLayerHinting = source.canUseLayerHinting; - this.pixelRatio = source.pixelRatio; - this.editorClassName = source.editorClassName; - this.lineHeight = source.lineHeight | 0; - this.readOnly = source.readOnly; - this.accessibilitySupport = source.accessibilitySupport; - this.multiCursorModifier = source.multiCursorModifier; - this.multiCursorMergeOverlapping = source.multiCursorMergeOverlapping; - this.wordSeparators = source.wordSeparators; - this.autoClosingBrackets = source.autoClosingBrackets; - this.autoClosingQuotes = source.autoClosingQuotes; - this.autoClosingOvertype = source.autoClosingOvertype; - this.autoSurround = source.autoSurround; - this.autoIndent = source.autoIndent; - this.useTabStops = source.useTabStops; - this.tabFocusMode = source.tabFocusMode; - this.dragAndDrop = source.dragAndDrop; - this.emptySelectionClipboard = source.emptySelectionClipboard; - this.copyWithSyntaxHighlighting = source.copyWithSyntaxHighlighting; - this.layoutInfo = source.layoutInfo; - this.fontInfo = source.fontInfo; - this.viewInfo = source.viewInfo; - this.wrappingInfo = source.wrappingInfo; - this.contribInfo = source.contribInfo; - this.showUnused = source.showUnused; + constructor() { + super(EditorOption.editorClassName, [EditorOption.mouseStyle, EditorOption.fontLigatures, EditorOption.extraEditorClassName]); } - /** - * @internal - */ - public equals(other: InternalEditorOptions): boolean { - return ( - this.canUseLayerHinting === other.canUseLayerHinting - && this.pixelRatio === other.pixelRatio - && this.editorClassName === other.editorClassName - && this.lineHeight === other.lineHeight - && this.readOnly === other.readOnly - && this.accessibilitySupport === other.accessibilitySupport - && this.multiCursorModifier === other.multiCursorModifier - && this.multiCursorMergeOverlapping === other.multiCursorMergeOverlapping - && this.wordSeparators === other.wordSeparators - && this.autoClosingBrackets === other.autoClosingBrackets - && this.autoClosingQuotes === other.autoClosingQuotes - && this.autoClosingOvertype === other.autoClosingOvertype - && this.autoSurround === other.autoSurround - && this.autoIndent === other.autoIndent - && this.useTabStops === other.useTabStops - && this.tabFocusMode === other.tabFocusMode - && this.dragAndDrop === other.dragAndDrop - && this.showUnused === other.showUnused - && this.emptySelectionClipboard === other.emptySelectionClipboard - && this.copyWithSyntaxHighlighting === other.copyWithSyntaxHighlighting - && InternalEditorOptions._equalsLayoutInfo(this.layoutInfo, other.layoutInfo) - && this.fontInfo.equals(other.fontInfo) - && InternalEditorOptions._equalsViewOptions(this.viewInfo, other.viewInfo) - && InternalEditorOptions._equalsWrappingInfo(this.wrappingInfo, other.wrappingInfo) - && InternalEditorOptions._equalsContribOptions(this.contribInfo, other.contribInfo) + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: string): string { + let className = 'monaco-editor'; + if (options.get(EditorOption.extraEditorClassName)) { + className += ' ' + options.get(EditorOption.extraEditorClassName); + } + if (env.extraEditorClassName) { + className += ' ' + env.extraEditorClassName; + } + if (options.get(EditorOption.fontLigatures)) { + className += ' enable-ligatures'; + } + if (options.get(EditorOption.mouseStyle) === 'default') { + className += ' mouse-default'; + } else if (options.get(EditorOption.mouseStyle) === 'copy') { + className += ' mouse-copy'; + } + return className; + } +} + +//#endregion + +//#region emptySelectionClipboard + +class EditorEmptySelectionClipboard extends EditorBooleanOption { + + constructor() { + super( + EditorOption.emptySelectionClipboard, 'emptySelectionClipboard', true, + { description: nls.localize('emptySelectionClipboard', "Controls whether copying without a selection copies the current line.") } ); } + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: boolean): boolean { + return value && env.emptySelectionClipboard; + } +} + +//#endregion + +//#region find + +/** + * Configuration options for editor find widget + */ +export interface IEditorFindOptions { + /** + * Controls if we seed search string in the Find Widget with editor selection. + */ + seedSearchStringFromSelection?: boolean; + /** + * Controls if Find in Selection flag is turned on when multiple lines of text are selected in the editor. + */ + autoFindInSelection?: boolean; + /* + * Controls whether the Find Widget should add extra lines on top of the editor. + */ + addExtraSpaceOnTop?: boolean; /** * @internal + * Controls if the Find Widget should read or modify the shared find clipboard on macOS */ - public createChangeEvent(newOpts: InternalEditorOptions): IConfigurationChangedEvent { + globalFindClipboard?: boolean; +} + +export type EditorFindOptions = Readonly>; + +class EditorFind extends BaseEditorOption { + + constructor() { + const defaults: EditorFindOptions = { + seedSearchStringFromSelection: true, + autoFindInSelection: false, + globalFindClipboard: false, + addExtraSpaceOnTop: true + }; + super( + EditorOption.find, 'find', defaults, + { + 'editor.find.seedSearchStringFromSelection': { + type: 'boolean', + default: defaults.seedSearchStringFromSelection, + description: nls.localize('find.seedSearchStringFromSelection', "Controls whether the search string in the Find Widget is seeded from the editor selection.") + }, + 'editor.find.autoFindInSelection': { + type: 'boolean', + default: defaults.autoFindInSelection, + description: nls.localize('find.autoFindInSelection', "Controls whether the find operation is carried out on selected text or the entire file in the editor.") + }, + 'editor.find.globalFindClipboard': { + type: 'boolean', + default: defaults.globalFindClipboard, + description: nls.localize('find.globalFindClipboard', "Controls whether the Find Widget should read or modify the shared find clipboard on macOS."), + included: platform.isMacintosh + }, + 'editor.find.addExtraSpaceOnTop': { + type: 'boolean', + default: defaults.addExtraSpaceOnTop, + description: nls.localize('find.addExtraSpaceOnTop', "Controls whether the Find Widget should add extra lines on top of the editor. When true, you can scroll beyond the first line when the Find Widget is visible.") + } + } + ); + } + + public validate(_input: any): EditorFindOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorFindOptions; return { - canUseLayerHinting: (this.canUseLayerHinting !== newOpts.canUseLayerHinting), - pixelRatio: (this.pixelRatio !== newOpts.pixelRatio), - editorClassName: (this.editorClassName !== newOpts.editorClassName), - lineHeight: (this.lineHeight !== newOpts.lineHeight), - readOnly: (this.readOnly !== newOpts.readOnly), - accessibilitySupport: (this.accessibilitySupport !== newOpts.accessibilitySupport), - multiCursorModifier: (this.multiCursorModifier !== newOpts.multiCursorModifier), - multiCursorMergeOverlapping: (this.multiCursorMergeOverlapping !== newOpts.multiCursorMergeOverlapping), - wordSeparators: (this.wordSeparators !== newOpts.wordSeparators), - autoClosingBrackets: (this.autoClosingBrackets !== newOpts.autoClosingBrackets), - autoClosingQuotes: (this.autoClosingQuotes !== newOpts.autoClosingQuotes), - autoClosingOvertype: (this.autoClosingOvertype !== newOpts.autoClosingOvertype), - autoSurround: (this.autoSurround !== newOpts.autoSurround), - autoIndent: (this.autoIndent !== newOpts.autoIndent), - useTabStops: (this.useTabStops !== newOpts.useTabStops), - tabFocusMode: (this.tabFocusMode !== newOpts.tabFocusMode), - dragAndDrop: (this.dragAndDrop !== newOpts.dragAndDrop), - emptySelectionClipboard: (this.emptySelectionClipboard !== newOpts.emptySelectionClipboard), - copyWithSyntaxHighlighting: (this.copyWithSyntaxHighlighting !== newOpts.copyWithSyntaxHighlighting), - layoutInfo: (!InternalEditorOptions._equalsLayoutInfo(this.layoutInfo, newOpts.layoutInfo)), - fontInfo: (!this.fontInfo.equals(newOpts.fontInfo)), - viewInfo: (!InternalEditorOptions._equalsViewOptions(this.viewInfo, newOpts.viewInfo)), - wrappingInfo: (!InternalEditorOptions._equalsWrappingInfo(this.wrappingInfo, newOpts.wrappingInfo)), - contribInfo: (!InternalEditorOptions._equalsContribOptions(this.contribInfo, newOpts.contribInfo)) + seedSearchStringFromSelection: EditorBooleanOption.boolean(input.seedSearchStringFromSelection, this.defaultValue.seedSearchStringFromSelection), + autoFindInSelection: EditorBooleanOption.boolean(input.autoFindInSelection, this.defaultValue.autoFindInSelection), + globalFindClipboard: EditorBooleanOption.boolean(input.globalFindClipboard, this.defaultValue.globalFindClipboard), + addExtraSpaceOnTop: EditorBooleanOption.boolean(input.addExtraSpaceOnTop, this.defaultValue.addExtraSpaceOnTop) }; } +} - /** - * @internal - */ - private static _equalsLayoutInfo(a: EditorLayoutInfo, b: EditorLayoutInfo): boolean { - return ( - a.width === b.width - && a.height === b.height - && a.glyphMarginLeft === b.glyphMarginLeft - && a.glyphMarginWidth === b.glyphMarginWidth - && a.glyphMarginHeight === b.glyphMarginHeight - && a.lineNumbersLeft === b.lineNumbersLeft - && a.lineNumbersWidth === b.lineNumbersWidth - && a.lineNumbersHeight === b.lineNumbersHeight - && a.decorationsLeft === b.decorationsLeft - && a.decorationsWidth === b.decorationsWidth - && a.decorationsHeight === b.decorationsHeight - && a.contentLeft === b.contentLeft - && a.contentWidth === b.contentWidth - && a.contentHeight === b.contentHeight - && a.renderMinimap === b.renderMinimap - && a.minimapLeft === b.minimapLeft - && a.minimapWidth === b.minimapWidth - && a.viewportColumn === b.viewportColumn - && a.verticalScrollbarWidth === b.verticalScrollbarWidth - && a.horizontalScrollbarHeight === b.horizontalScrollbarHeight - && this._equalsOverviewRuler(a.overviewRuler, b.overviewRuler) - ); +//#endregion + +//#region fontInfo + +class EditorFontInfo extends ComputedEditorOption { + + constructor() { + super(EditorOption.fontInfo); } - /** - * @internal - */ - private static _equalsOverviewRuler(a: OverviewRulerPosition, b: OverviewRulerPosition): boolean { - return ( - a.width === b.width - && a.height === b.height - && a.top === b.top - && a.right === b.right - ); - } - - /** - * @internal - */ - private static _equalsViewOptions(a: InternalEditorViewOptions, b: InternalEditorViewOptions): boolean { - return ( - a.extraEditorClassName === b.extraEditorClassName - && a.disableMonospaceOptimizations === b.disableMonospaceOptimizations - && arrays.equals(a.rulers, b.rulers) - && a.ariaLabel === b.ariaLabel - && a.renderLineNumbers === b.renderLineNumbers - && a.renderCustomLineNumbers === b.renderCustomLineNumbers - && a.cursorSurroundingLines === b.cursorSurroundingLines - && a.renderFinalNewline === b.renderFinalNewline - && a.selectOnLineNumbers === b.selectOnLineNumbers - && a.glyphMargin === b.glyphMargin - && a.revealHorizontalRightPadding === b.revealHorizontalRightPadding - && a.roundedSelection === b.roundedSelection - && a.overviewRulerLanes === b.overviewRulerLanes - && a.overviewRulerBorder === b.overviewRulerBorder - && a.cursorBlinking === b.cursorBlinking - && a.mouseWheelZoom === b.mouseWheelZoom - && a.cursorSmoothCaretAnimation === b.cursorSmoothCaretAnimation - && a.cursorStyle === b.cursorStyle - && a.cursorWidth === b.cursorWidth - && a.hideCursorInOverviewRuler === b.hideCursorInOverviewRuler - && a.scrollBeyondLastLine === b.scrollBeyondLastLine - && a.scrollBeyondLastColumn === b.scrollBeyondLastColumn - && a.smoothScrolling === b.smoothScrolling - && a.stopRenderingLineAfter === b.stopRenderingLineAfter - && a.renderWhitespace === b.renderWhitespace - && a.renderControlCharacters === b.renderControlCharacters - && a.fontLigatures === b.fontLigatures - && a.renderIndentGuides === b.renderIndentGuides - && a.highlightActiveIndentGuide === b.highlightActiveIndentGuide - && a.renderLineHighlight === b.renderLineHighlight - && this._equalsScrollbarOptions(a.scrollbar, b.scrollbar) - && this._equalsMinimapOptions(a.minimap, b.minimap) - && a.fixedOverflowWidgets === b.fixedOverflowWidgets - ); - } - - /** - * @internal - */ - private static _equalsScrollbarOptions(a: InternalEditorScrollbarOptions, b: InternalEditorScrollbarOptions): boolean { - return ( - a.arrowSize === b.arrowSize - && a.vertical === b.vertical - && a.horizontal === b.horizontal - && a.useShadows === b.useShadows - && a.verticalHasArrows === b.verticalHasArrows - && a.horizontalHasArrows === b.horizontalHasArrows - && a.handleMouseWheel === b.handleMouseWheel - && a.horizontalScrollbarSize === b.horizontalScrollbarSize - && a.horizontalSliderSize === b.horizontalSliderSize - && a.verticalScrollbarSize === b.verticalScrollbarSize - && a.verticalSliderSize === b.verticalSliderSize - && a.mouseWheelScrollSensitivity === b.mouseWheelScrollSensitivity - && a.fastScrollSensitivity === b.fastScrollSensitivity - ); - } - - /** - * @internal - */ - private static _equalsMinimapOptions(a: InternalEditorMinimapOptions, b: InternalEditorMinimapOptions): boolean { - return ( - a.enabled === b.enabled - && a.side === b.side - && a.showSlider === b.showSlider - && a.renderCharacters === b.renderCharacters - && a.maxColumn === b.maxColumn - ); - } - - /** - * @internal - */ - private static _equalFindOptions(a: InternalEditorFindOptions, b: InternalEditorFindOptions): boolean { - return ( - a.seedSearchStringFromSelection === b.seedSearchStringFromSelection - && a.autoFindInSelection === b.autoFindInSelection - && a.globalFindClipboard === b.globalFindClipboard - && a.addExtraSpaceOnTop === b.addExtraSpaceOnTop - ); - } - - /** - * @internal - */ - private static _equalsParameterHintOptions(a: InternalParameterHintOptions, b: InternalParameterHintOptions): boolean { - return ( - a.enabled === b.enabled - && a.cycle === b.cycle - ); - } - - /** - * @internal - */ - private static _equalsHoverOptions(a: InternalEditorHoverOptions, b: InternalEditorHoverOptions): boolean { - return ( - a.enabled === b.enabled - && a.delay === b.delay - && a.sticky === b.sticky - ); - } - - /** - * @internal - */ - private static _equalsSuggestOptions(a: InternalSuggestOptions, b: InternalSuggestOptions): any { - if (a === b) { - return true; - } else if (!a || !b) { - return false; - } else { - return a.filterGraceful === b.filterGraceful - && a.snippets === b.snippets - && a.snippetsPreventQuickSuggestions === b.snippetsPreventQuickSuggestions - && a.localityBonus === b.localityBonus - && a.shareSuggestSelections === b.shareSuggestSelections - && a.showIcons === b.showIcons - && a.maxVisibleSuggestions === b.maxVisibleSuggestions - && objects.equals(a.filteredTypes, b.filteredTypes); - } - } - - private static _equalsGotoLocationOptions(a: InternalGoToLocationOptions | undefined, b: InternalGoToLocationOptions | undefined): boolean { - if (a === b) { - return true; - } else if (!a || !b) { - return false; - } else { - return a.multiple === b.multiple; - } - } - - /** - * @internal - */ - private static _equalsWrappingInfo(a: EditorWrappingInfo, b: EditorWrappingInfo): boolean { - return ( - a.inDiffEditor === b.inDiffEditor - && a.isDominatedByLongLines === b.isDominatedByLongLines - && a.isWordWrapMinified === b.isWordWrapMinified - && a.isViewportWrapping === b.isViewportWrapping - && a.wrappingColumn === b.wrappingColumn - && a.wrappingIndent === b.wrappingIndent - && a.wordWrapBreakBeforeCharacters === b.wordWrapBreakBeforeCharacters - && a.wordWrapBreakAfterCharacters === b.wordWrapBreakAfterCharacters - && a.wordWrapBreakObtrusiveCharacters === b.wordWrapBreakObtrusiveCharacters - ); - } - - /** - * @internal - */ - private static _equalsContribOptions(a: EditorContribOptions, b: EditorContribOptions): boolean { - return ( - a.selectionClipboard === b.selectionClipboard - && this._equalsHoverOptions(a.hover, b.hover) - && a.links === b.links - && a.contextmenu === b.contextmenu - && InternalEditorOptions._equalsQuickSuggestions(a.quickSuggestions, b.quickSuggestions) - && a.quickSuggestionsDelay === b.quickSuggestionsDelay - && this._equalsParameterHintOptions(a.parameterHints, b.parameterHints) - && a.formatOnType === b.formatOnType - && a.formatOnPaste === b.formatOnPaste - && a.suggestOnTriggerCharacters === b.suggestOnTriggerCharacters - && a.acceptSuggestionOnEnter === b.acceptSuggestionOnEnter - && a.acceptSuggestionOnCommitCharacter === b.acceptSuggestionOnCommitCharacter - && a.wordBasedSuggestions === b.wordBasedSuggestions - && a.suggestSelection === b.suggestSelection - && a.suggestFontSize === b.suggestFontSize - && a.suggestLineHeight === b.suggestLineHeight - && a.tabCompletion === b.tabCompletion - && this._equalsSuggestOptions(a.suggest, b.suggest) - && InternalEditorOptions._equalsGotoLocationOptions(a.gotoLocation, b.gotoLocation) - && a.selectionHighlight === b.selectionHighlight - && a.occurrencesHighlight === b.occurrencesHighlight - && a.codeLens === b.codeLens - && a.folding === b.folding - && a.foldingStrategy === b.foldingStrategy - && a.showFoldingControls === b.showFoldingControls - && a.matchBrackets === b.matchBrackets - && this._equalFindOptions(a.find, b.find) - && a.colorDecorators === b.colorDecorators - && objects.equals(a.codeActionsOnSave, b.codeActionsOnSave) - && a.codeActionsOnSaveTimeout === b.codeActionsOnSaveTimeout - && a.lightbulbEnabled === b.lightbulbEnabled - ); - } - - private static _equalsQuickSuggestions(a: boolean | { other: boolean, comments: boolean, strings: boolean }, b: boolean | { other: boolean, comments: boolean, strings: boolean }): boolean { - if (typeof a === 'boolean') { - if (typeof b !== 'boolean') { - return false; - } - return a === b; - } - if (typeof b === 'boolean') { - return false; - } - return ( - a.comments === b.comments - && a.other === b.other - && a.strings === b.strings - ); + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: FontInfo): FontInfo { + return env.fontInfo; } } +//#endregion + +//#region fontSize + +class EditorFontSize extends SimpleEditorOption { + + constructor() { + super( + EditorOption.fontSize, 'fontSize', EDITOR_FONT_DEFAULTS.fontSize, + { + type: 'number', + default: EDITOR_FONT_DEFAULTS.fontSize, + description: nls.localize('fontSize', "Controls the font size in pixels.") + } + ); + } + + public validate(input: any): number { + let r = EditorFloatOption.float(input, this.defaultValue); + if (r === 0) { + return EDITOR_FONT_DEFAULTS.fontSize; + } + return EditorFloatOption.clamp(r, 8, 100); + } + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number { + // The final fontSize respects the editor zoom level. + // So take the result from env.fontInfo + return env.fontInfo.fontSize; + } +} + +//#endregion + +//#region gotoLocation + +/** + * Configuration options for go to location + */ +export interface IGotoLocationOptions { + /** + * Control how goto-command work when having multiple results. + */ + multiple?: 'peek' | 'gotoAndPeek' | 'goto'; +} + +export type GoToLocationOptions = Readonly>; + +class EditorGoToLocation extends BaseEditorOption { + + constructor() { + const defaults: GoToLocationOptions = { multiple: 'peek' }; + super( + EditorOption.gotoLocation, 'gotoLocation', defaults, + { + 'editor.gotoLocation.multiple': { + description: nls.localize('editor.gotoLocation.multiple', "Controls the behavior of 'Go To' commands, like Go To Definition, when multiple target locations exist."), + type: 'string', + enum: ['peek', 'gotoAndPeek', 'goto'], + default: defaults.multiple, + enumDescriptions: [ + nls.localize('editor.gotoLocation.multiple.peek', 'Show peek view of the results (default)'), + nls.localize('editor.gotoLocation.multiple.gotoAndPeek', 'Go to the primary result and show a peek view'), + nls.localize('editor.gotoLocation.multiple.goto', 'Go to the primary result and enable peek-less navigation to others') + ] + }, + } + ); + } + + public validate(_input: any): GoToLocationOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IGotoLocationOptions; + return { + multiple: EditorStringEnumOption.stringSet<'peek' | 'gotoAndPeek' | 'goto'>(input.multiple, this.defaultValue.multiple, ['peek', 'gotoAndPeek', 'goto']) + }; + } +} + +//#endregion + +//#region hover + +/** + * Configuration options for editor hover + */ +export interface IEditorHoverOptions { + /** + * Enable the hover. + * Defaults to true. + */ + enabled?: boolean; + /** + * Delay for showing the hover. + * Defaults to 300. + */ + delay?: number; + /** + * Is the hover sticky such that it can be clicked and its contents selected? + * Defaults to true. + */ + sticky?: boolean; +} + +export type EditorHoverOptions = Readonly>; + +class EditorHover extends BaseEditorOption { + + constructor() { + const defaults: EditorHoverOptions = { + enabled: true, + delay: 300, + sticky: true + }; + super( + EditorOption.hover, 'hover', defaults, + { + 'editor.hover.enabled': { + type: 'boolean', + default: defaults.enabled, + description: nls.localize('hover.enabled', "Controls whether the hover is shown.") + }, + 'editor.hover.delay': { + type: 'number', + default: defaults.delay, + description: nls.localize('hover.delay', "Controls the delay in milliseconds after which the hover is shown.") + }, + 'editor.hover.sticky': { + type: 'boolean', + default: defaults.sticky, + description: nls.localize('hover.sticky', "Controls whether the hover should remain visible when mouse is moved over it.") + }, + } + ); + } + + public validate(_input: any): EditorHoverOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorHoverOptions; + return { + enabled: EditorBooleanOption.boolean(input.enabled, this.defaultValue.enabled), + delay: EditorIntOption.clampedInt(input.delay, this.defaultValue.delay, 0, 10000), + sticky: EditorBooleanOption.boolean(input.sticky, this.defaultValue.sticky) + }; + } +} + +//#endregion + +//#region layoutInfo + /** * A description for the overview ruler position. */ @@ -1534,6 +1348,14 @@ export interface OverviewRulerPosition { readonly right: number; } +export const enum RenderMinimap { + None = 0, + Small = 1, + Large = 2, + SmallBlocks = 3, + LargeBlocks = 4, +} + /** * The internal layout details of the editor. */ @@ -1635,851 +1457,79 @@ export interface EditorLayoutInfo { } /** - * An event describing that the configuration of the editor has changed. + * @internal */ -export interface IConfigurationChangedEvent { - readonly canUseLayerHinting: boolean; - readonly pixelRatio: boolean; - readonly editorClassName: boolean; - readonly lineHeight: boolean; - readonly readOnly: boolean; - readonly accessibilitySupport: boolean; - readonly multiCursorModifier: boolean; - readonly multiCursorMergeOverlapping: boolean; - readonly wordSeparators: boolean; - readonly autoClosingBrackets: boolean; - readonly autoClosingQuotes: boolean; - readonly autoClosingOvertype: boolean; - readonly autoSurround: boolean; - readonly autoIndent: boolean; - readonly useTabStops: boolean; - readonly tabFocusMode: boolean; - readonly dragAndDrop: boolean; - readonly emptySelectionClipboard: boolean; - readonly copyWithSyntaxHighlighting: boolean; - readonly layoutInfo: boolean; - readonly fontInfo: boolean; - readonly viewInfo: boolean; - readonly wrappingInfo: boolean; - readonly contribInfo: boolean; +export interface EditorLayoutInfoComputerEnv { + outerWidth: number; + outerHeight: number; + lineHeight: number; + lineNumbersDigitCount: number; + typicalHalfwidthCharacterWidth: number; + maxDigitWidth: number; + pixelRatio: number; } /** * @internal */ -export interface IEnvironmentalOptions { - readonly outerWidth: number; - readonly outerHeight: number; - readonly fontInfo: FontInfo; - readonly extraEditorClassName: string; - readonly isDominatedByLongLines: boolean; - readonly lineNumbersDigitCount: number; - readonly emptySelectionClipboard: boolean; - readonly pixelRatio: number; - readonly tabFocusMode: boolean; - readonly accessibilitySupport: AccessibilitySupport; -} +export class EditorLayoutInfoComputer extends ComputedEditorOption { -function _boolean(value: any, defaultValue: T): boolean | T { - if (typeof value === 'undefined') { - return defaultValue; - } - if (value === 'false') { - // treat the string 'false' as false - return false; - } - return Boolean(value); -} - -function _booleanMap(value: { [key: string]: boolean } | undefined, defaultValue: { [key: string]: boolean }): { [key: string]: boolean } { - if (!value) { - return defaultValue; + constructor() { + super( + EditorOption.layoutInfo, + [EditorOption.glyphMargin, EditorOption.lineDecorationsWidth, EditorOption.folding, EditorOption.minimap, EditorOption.scrollbar, EditorOption.lineNumbers] + ); } - const out = Object.create(null); - for (const k of Object.keys(value)) { - const v = value[k]; - if (typeof v === 'boolean') { - out[k] = v; - } - } - return out; -} - -function _string(value: any, defaultValue: string): string { - if (typeof value !== 'string') { - return defaultValue; - } - return value; -} - -function _stringSet(value: T | undefined, defaultValue: T, allowedValues: T[]): T { - if (typeof value !== 'string') { - return defaultValue; - } - if (allowedValues.indexOf(value) === -1) { - return defaultValue; - } - return value; -} - -function _clampedInt(value: any, defaultValue: number, minimum: number, maximum: number): number { - let r: number; - if (typeof value === 'undefined') { - r = defaultValue; - } else { - r = parseInt(value, 10); - if (isNaN(r)) { - r = defaultValue; - } - } - r = Math.max(minimum, r); - r = Math.min(maximum, r); - return r | 0; -} - -function _float(value: any, defaultValue: number): number { - let r = parseFloat(value); - if (isNaN(r)) { - r = defaultValue; - } - return r; -} - -function _wrappingIndentFromString(wrappingIndent: string | undefined, defaultValue: WrappingIndent): WrappingIndent { - if (typeof wrappingIndent !== 'string') { - return defaultValue; - } - if (wrappingIndent === 'same') { - return WrappingIndent.Same; - } else if (wrappingIndent === 'indent') { - return WrappingIndent.Indent; - } else if (wrappingIndent === 'deepIndent') { - return WrappingIndent.DeepIndent; - } else { - return WrappingIndent.None; - } -} - -function _cursorBlinkingStyleFromString(cursorBlinkingStyle: string | undefined, defaultValue: TextEditorCursorBlinkingStyle): TextEditorCursorBlinkingStyle { - if (typeof cursorBlinkingStyle !== 'string') { - return defaultValue; - } - switch (cursorBlinkingStyle) { - case 'blink': - return TextEditorCursorBlinkingStyle.Blink; - case 'smooth': - return TextEditorCursorBlinkingStyle.Smooth; - case 'phase': - return TextEditorCursorBlinkingStyle.Phase; - case 'expand': - return TextEditorCursorBlinkingStyle.Expand; - case 'visible': // maintain compatibility - case 'solid': - return TextEditorCursorBlinkingStyle.Solid; - } - return TextEditorCursorBlinkingStyle.Blink; -} - -function _scrollbarVisibilityFromString(visibility: string | undefined, defaultValue: ScrollbarVisibility): ScrollbarVisibility { - if (typeof visibility !== 'string') { - return defaultValue; - } - switch (visibility) { - case 'hidden': - return ScrollbarVisibility.Hidden; - case 'visible': - return ScrollbarVisibility.Visible; - default: - return ScrollbarVisibility.Auto; - } -} - -/** - * @internal - */ -export class EditorOptionsValidator { - - /** - * Validate raw editor options. - * i.e. since they can be defined by the user, they might be invalid. - */ - public static validate(opts: IEditorOptions, defaults: IValidatedEditorOptions): IValidatedEditorOptions { - let wordWrap = opts.wordWrap; - { - // Compatibility with old true or false values - if (wordWrap === true) { - wordWrap = 'on'; - } else if (wordWrap === false) { - wordWrap = 'off'; - } - - wordWrap = _stringSet<'off' | 'on' | 'wordWrapColumn' | 'bounded'>(wordWrap, defaults.wordWrap, ['off', 'on', 'wordWrapColumn', 'bounded']); - } - - const viewInfo = this._sanitizeViewInfo(opts, defaults.viewInfo); - const contribInfo = this._sanitizeContribInfo(opts, defaults.contribInfo); - - let configuredMulticursorModifier: 'altKey' | 'metaKey' | 'ctrlKey' | undefined = undefined; - if (typeof opts.multiCursorModifier === 'string') { - if (opts.multiCursorModifier === 'ctrlCmd') { - configuredMulticursorModifier = platform.isMacintosh ? 'metaKey' : 'ctrlKey'; - } else { - configuredMulticursorModifier = 'altKey'; - } - } - const multiCursorModifier = _stringSet<'altKey' | 'metaKey' | 'ctrlKey'>(configuredMulticursorModifier, defaults.multiCursorModifier, ['altKey', 'metaKey', 'ctrlKey']); - - let autoClosingBrackets: EditorAutoClosingStrategy; - let autoClosingQuotes: EditorAutoClosingStrategy; - let autoSurround: EditorAutoSurroundStrategy; - if (typeof opts.autoClosingBrackets === 'boolean' && opts.autoClosingBrackets === false) { - // backwards compatibility: disable all on boolean false - autoClosingBrackets = 'never'; - autoClosingQuotes = 'never'; - autoSurround = 'never'; - } else { - autoClosingBrackets = _stringSet(opts.autoClosingBrackets, defaults.autoClosingBrackets, ['always', 'languageDefined', 'beforeWhitespace', 'never']); - autoClosingQuotes = _stringSet(opts.autoClosingQuotes, defaults.autoClosingQuotes, ['always', 'languageDefined', 'beforeWhitespace', 'never']); - autoSurround = _stringSet(opts.autoSurround, defaults.autoSurround, ['languageDefined', 'brackets', 'quotes', 'never']); - } - - return { - inDiffEditor: _boolean(opts.inDiffEditor, defaults.inDiffEditor), - wordSeparators: _string(opts.wordSeparators, defaults.wordSeparators), - lineNumbersMinChars: _clampedInt(opts.lineNumbersMinChars, defaults.lineNumbersMinChars, 1, 10), - lineDecorationsWidth: (typeof opts.lineDecorationsWidth === 'undefined' ? defaults.lineDecorationsWidth : opts.lineDecorationsWidth), - readOnly: _boolean(opts.readOnly, defaults.readOnly), - mouseStyle: _stringSet<'text' | 'default' | 'copy'>(opts.mouseStyle, defaults.mouseStyle, ['text', 'default', 'copy']), - disableLayerHinting: _boolean(opts.disableLayerHinting, defaults.disableLayerHinting), - automaticLayout: _boolean(opts.automaticLayout, defaults.automaticLayout), - wordWrap: wordWrap, - wordWrapColumn: _clampedInt(opts.wordWrapColumn, defaults.wordWrapColumn, 1, Constants.MAX_SAFE_SMALL_INTEGER), - wordWrapMinified: _boolean(opts.wordWrapMinified, defaults.wordWrapMinified), - wrappingIndent: _wrappingIndentFromString(opts.wrappingIndent, defaults.wrappingIndent), - wordWrapBreakBeforeCharacters: _string(opts.wordWrapBreakBeforeCharacters, defaults.wordWrapBreakBeforeCharacters), - wordWrapBreakAfterCharacters: _string(opts.wordWrapBreakAfterCharacters, defaults.wordWrapBreakAfterCharacters), - wordWrapBreakObtrusiveCharacters: _string(opts.wordWrapBreakObtrusiveCharacters, defaults.wordWrapBreakObtrusiveCharacters), - autoClosingBrackets, - autoClosingQuotes, - autoClosingOvertype: _stringSet(opts.autoClosingOvertype, defaults.autoClosingOvertype, ['always', 'auto', 'never']), - autoSurround, - autoIndent: _boolean(opts.autoIndent, defaults.autoIndent), - dragAndDrop: _boolean(opts.dragAndDrop, defaults.dragAndDrop), - emptySelectionClipboard: _boolean(opts.emptySelectionClipboard, defaults.emptySelectionClipboard), - copyWithSyntaxHighlighting: _boolean(opts.copyWithSyntaxHighlighting, defaults.copyWithSyntaxHighlighting), - useTabStops: _boolean(opts.useTabStops, defaults.useTabStops), - multiCursorModifier: multiCursorModifier, - multiCursorMergeOverlapping: _boolean(opts.multiCursorMergeOverlapping, defaults.multiCursorMergeOverlapping), - accessibilitySupport: _stringSet<'auto' | 'on' | 'off'>(opts.accessibilitySupport, defaults.accessibilitySupport, ['auto', 'on', 'off']), - showUnused: _boolean(opts.showUnused, defaults.showUnused), - viewInfo: viewInfo, - contribInfo: contribInfo, - }; - } - - private static _sanitizeScrollbarOpts(opts: IEditorScrollbarOptions | undefined, defaults: InternalEditorScrollbarOptions, mouseWheelScrollSensitivity: number, fastScrollSensitivity: number): InternalEditorScrollbarOptions { - if (typeof opts !== 'object') { - return defaults; - } - const horizontalScrollbarSize = _clampedInt(opts.horizontalScrollbarSize, defaults.horizontalScrollbarSize, 0, 1000); - const verticalScrollbarSize = _clampedInt(opts.verticalScrollbarSize, defaults.verticalScrollbarSize, 0, 1000); - return { - vertical: _scrollbarVisibilityFromString(opts.vertical, defaults.vertical), - horizontal: _scrollbarVisibilityFromString(opts.horizontal, defaults.horizontal), - - arrowSize: _clampedInt(opts.arrowSize, defaults.arrowSize, 0, 1000), - useShadows: _boolean(opts.useShadows, defaults.useShadows), - - verticalHasArrows: _boolean(opts.verticalHasArrows, defaults.verticalHasArrows), - horizontalHasArrows: _boolean(opts.horizontalHasArrows, defaults.horizontalHasArrows), - - horizontalScrollbarSize: horizontalScrollbarSize, - horizontalSliderSize: _clampedInt(opts.horizontalSliderSize, horizontalScrollbarSize, 0, 1000), - - verticalScrollbarSize: verticalScrollbarSize, - verticalSliderSize: _clampedInt(opts.verticalSliderSize, verticalScrollbarSize, 0, 1000), - - handleMouseWheel: _boolean(opts.handleMouseWheel, defaults.handleMouseWheel), - mouseWheelScrollSensitivity: mouseWheelScrollSensitivity, - fastScrollSensitivity: fastScrollSensitivity, - }; - } - - private static _sanitizeMinimapOpts(opts: IEditorMinimapOptions | undefined, defaults: InternalEditorMinimapOptions): InternalEditorMinimapOptions { - if (typeof opts !== 'object') { - return defaults; - } - return { - enabled: _boolean(opts.enabled, defaults.enabled), - side: _stringSet<'right' | 'left'>(opts.side, defaults.side, ['right', 'left']), - showSlider: _stringSet<'always' | 'mouseover'>(opts.showSlider, defaults.showSlider, ['always', 'mouseover']), - renderCharacters: _boolean(opts.renderCharacters, defaults.renderCharacters), - maxColumn: _clampedInt(opts.maxColumn, defaults.maxColumn, 1, 10000), - }; - } - - private static _sanitizeFindOpts(opts: IEditorFindOptions | undefined, defaults: InternalEditorFindOptions): InternalEditorFindOptions { - if (typeof opts !== 'object') { - return defaults; - } - - return { - seedSearchStringFromSelection: _boolean(opts.seedSearchStringFromSelection, defaults.seedSearchStringFromSelection), - autoFindInSelection: _boolean(opts.autoFindInSelection, defaults.autoFindInSelection), - globalFindClipboard: _boolean(opts.globalFindClipboard, defaults.globalFindClipboard), - addExtraSpaceOnTop: _boolean(opts.addExtraSpaceOnTop, defaults.addExtraSpaceOnTop) - }; - } - - private static _sanitizeParameterHintOpts(opts: IEditorParameterHintOptions | undefined, defaults: InternalParameterHintOptions): InternalParameterHintOptions { - if (typeof opts !== 'object') { - return defaults; - } - - return { - enabled: _boolean(opts.enabled, defaults.enabled), - cycle: _boolean(opts.cycle, defaults.cycle) - }; - } - - private static _sanitizeHoverOpts(_opts: boolean | IEditorHoverOptions | undefined, defaults: InternalEditorHoverOptions): InternalEditorHoverOptions { - let opts: IEditorHoverOptions; - if (typeof _opts === 'boolean') { - opts = { - enabled: _opts - }; - } else if (typeof _opts === 'object') { - opts = _opts; - } else { - return defaults; - } - - return { - enabled: _boolean(opts.enabled, defaults.enabled), - delay: _clampedInt(opts.delay, defaults.delay, 0, 10000), - sticky: _boolean(opts.sticky, defaults.sticky) - }; - } - - private static _sanitizeSuggestOpts(opts: IEditorOptions, defaults: InternalSuggestOptions): InternalSuggestOptions { - const suggestOpts = opts.suggest || {}; - return { - filterGraceful: _boolean(suggestOpts.filterGraceful, defaults.filterGraceful), - snippets: _stringSet<'top' | 'bottom' | 'inline' | 'none'>(opts.snippetSuggestions, defaults.snippets, ['top', 'bottom', 'inline', 'none']), - snippetsPreventQuickSuggestions: _boolean(suggestOpts.snippetsPreventQuickSuggestions, defaults.filterGraceful), - localityBonus: _boolean(suggestOpts.localityBonus, defaults.localityBonus), - shareSuggestSelections: _boolean(suggestOpts.shareSuggestSelections, defaults.shareSuggestSelections), - showIcons: _boolean(suggestOpts.showIcons, defaults.showIcons), - maxVisibleSuggestions: _clampedInt(suggestOpts.maxVisibleSuggestions, defaults.maxVisibleSuggestions, 1, 15), - filteredTypes: isObject(suggestOpts.filteredTypes) ? suggestOpts.filteredTypes : Object.create(null) - }; - } - - private static _sanitizeGotoLocationOpts(opts: IEditorOptions, defaults: InternalGoToLocationOptions): InternalGoToLocationOptions { - const gotoOpts = opts.gotoLocation || {}; - return { - multiple: _stringSet<'peek' | 'gotoAndPeek' | 'goto'>(gotoOpts.multiple, defaults.multiple, ['peek', 'gotoAndPeek', 'goto']) - }; - } - - private static _sanitizeTabCompletionOpts(opts: boolean | 'on' | 'off' | 'onlySnippets' | undefined, defaults: 'on' | 'off' | 'onlySnippets'): 'on' | 'off' | 'onlySnippets' { - if (opts === false) { - return 'off'; - } else if (opts === true) { - return 'onlySnippets'; - } else { - return _stringSet<'on' | 'off' | 'onlySnippets'>(opts, defaults, ['on', 'off', 'onlySnippets']); - } - } - - private static _sanitizeViewInfo(opts: IEditorOptions, defaults: InternalEditorViewOptions): InternalEditorViewOptions { - - let rulers: number[] = []; - if (Array.isArray(opts.rulers)) { - for (let i = 0, len = opts.rulers.length; i < len; i++) { - rulers.push(_clampedInt(opts.rulers[i], 0, 0, 10000)); - } - rulers.sort(); - } - - let renderLineNumbers: RenderLineNumbersType = defaults.renderLineNumbers; - let renderCustomLineNumbers: ((lineNumber: number) => string) | null = defaults.renderCustomLineNumbers; - - if (typeof opts.lineNumbers !== 'undefined') { - let lineNumbers = opts.lineNumbers; - - // Compatibility with old true or false values - if (lineNumbers === true) { - lineNumbers = 'on'; - } else if (lineNumbers === false) { - lineNumbers = 'off'; - } - - if (typeof lineNumbers === 'function') { - renderLineNumbers = RenderLineNumbersType.Custom; - renderCustomLineNumbers = lineNumbers; - } else if (lineNumbers === 'interval') { - renderLineNumbers = RenderLineNumbersType.Interval; - } else if (lineNumbers === 'relative') { - renderLineNumbers = RenderLineNumbersType.Relative; - } else if (lineNumbers === 'on') { - renderLineNumbers = RenderLineNumbersType.On; - } else { - renderLineNumbers = RenderLineNumbersType.Off; - } - } - - const fontLigatures = _boolean(opts.fontLigatures, defaults.fontLigatures); - const disableMonospaceOptimizations = _boolean(opts.disableMonospaceOptimizations, defaults.disableMonospaceOptimizations) || fontLigatures; - - let renderWhitespace = opts.renderWhitespace; - { - // Compatibility with old true or false values - if (renderWhitespace === true) { - renderWhitespace = 'boundary'; - } else if (renderWhitespace === false) { - renderWhitespace = 'none'; - } - renderWhitespace = _stringSet<'none' | 'boundary' | 'selection' | 'all'>(renderWhitespace, defaults.renderWhitespace, ['none', 'boundary', 'selection', 'all']); - } - - let renderLineHighlight = opts.renderLineHighlight; - { - // Compatibility with old true or false values - if (renderLineHighlight === true) { - renderLineHighlight = 'line'; - } else if (renderLineHighlight === false) { - renderLineHighlight = 'none'; - } - renderLineHighlight = _stringSet<'none' | 'gutter' | 'line' | 'all'>(renderLineHighlight, defaults.renderLineHighlight, ['none', 'gutter', 'line', 'all']); - } - - let mouseWheelScrollSensitivity = _float(opts.mouseWheelScrollSensitivity, defaults.scrollbar.mouseWheelScrollSensitivity); - if (mouseWheelScrollSensitivity === 0) { - // Disallow 0, as it would prevent/block scrolling - mouseWheelScrollSensitivity = 1; - } - - let fastScrollSensitivity = _float(opts.fastScrollSensitivity, defaults.scrollbar.fastScrollSensitivity); - if (fastScrollSensitivity <= 0) { - fastScrollSensitivity = defaults.scrollbar.fastScrollSensitivity; - } - const scrollbar = this._sanitizeScrollbarOpts(opts.scrollbar, defaults.scrollbar, mouseWheelScrollSensitivity, fastScrollSensitivity); - const minimap = this._sanitizeMinimapOpts(opts.minimap, defaults.minimap); - - return { - extraEditorClassName: _string(opts.extraEditorClassName, defaults.extraEditorClassName), - disableMonospaceOptimizations: disableMonospaceOptimizations, - rulers: rulers, - ariaLabel: _string(opts.ariaLabel, defaults.ariaLabel), - cursorSurroundingLines: _clampedInt(opts.cursorSurroundingLines, defaults.cursorWidth, 0, Number.MAX_VALUE), - renderLineNumbers: renderLineNumbers, - renderCustomLineNumbers: renderCustomLineNumbers, - renderFinalNewline: _boolean(opts.renderFinalNewline, defaults.renderFinalNewline), - selectOnLineNumbers: _boolean(opts.selectOnLineNumbers, defaults.selectOnLineNumbers), - glyphMargin: _boolean(opts.glyphMargin, defaults.glyphMargin), - revealHorizontalRightPadding: _clampedInt(opts.revealHorizontalRightPadding, defaults.revealHorizontalRightPadding, 0, 1000), - roundedSelection: _boolean(opts.roundedSelection, defaults.roundedSelection), - overviewRulerLanes: _clampedInt(opts.overviewRulerLanes, defaults.overviewRulerLanes, 0, 3), - overviewRulerBorder: _boolean(opts.overviewRulerBorder, defaults.overviewRulerBorder), - cursorBlinking: _cursorBlinkingStyleFromString(opts.cursorBlinking, defaults.cursorBlinking), - mouseWheelZoom: _boolean(opts.mouseWheelZoom, defaults.mouseWheelZoom), - cursorSmoothCaretAnimation: _boolean(opts.cursorSmoothCaretAnimation, defaults.cursorSmoothCaretAnimation), - cursorStyle: _cursorStyleFromString(opts.cursorStyle, defaults.cursorStyle), - cursorWidth: _clampedInt(opts.cursorWidth, defaults.cursorWidth, 0, Number.MAX_VALUE), - hideCursorInOverviewRuler: _boolean(opts.hideCursorInOverviewRuler, defaults.hideCursorInOverviewRuler), - scrollBeyondLastLine: _boolean(opts.scrollBeyondLastLine, defaults.scrollBeyondLastLine), - scrollBeyondLastColumn: _clampedInt(opts.scrollBeyondLastColumn, defaults.scrollBeyondLastColumn, 0, Constants.MAX_SAFE_SMALL_INTEGER), - smoothScrolling: _boolean(opts.smoothScrolling, defaults.smoothScrolling), - stopRenderingLineAfter: _clampedInt(opts.stopRenderingLineAfter, defaults.stopRenderingLineAfter, -1, Constants.MAX_SAFE_SMALL_INTEGER), - renderWhitespace: renderWhitespace, - renderControlCharacters: _boolean(opts.renderControlCharacters, defaults.renderControlCharacters), - fontLigatures: fontLigatures, - renderIndentGuides: _boolean(opts.renderIndentGuides, defaults.renderIndentGuides), - highlightActiveIndentGuide: _boolean(opts.highlightActiveIndentGuide, defaults.highlightActiveIndentGuide), - renderLineHighlight: renderLineHighlight, - scrollbar: scrollbar, - minimap: minimap, - fixedOverflowWidgets: _boolean(opts.fixedOverflowWidgets, defaults.fixedOverflowWidgets), - }; - } - - private static _sanitizeContribInfo(opts: IEditorOptions, defaults: EditorContribOptions): EditorContribOptions { - let quickSuggestions: boolean | { other: boolean, comments: boolean, strings: boolean }; - if (typeof opts.quickSuggestions === 'object') { - quickSuggestions = { other: true, ...opts.quickSuggestions }; - } else { - quickSuggestions = _boolean(opts.quickSuggestions, defaults.quickSuggestions); - } - // Compatibility support for acceptSuggestionOnEnter - if (typeof opts.acceptSuggestionOnEnter === 'boolean') { - opts.acceptSuggestionOnEnter = opts.acceptSuggestionOnEnter ? 'on' : 'off'; - } - const find = this._sanitizeFindOpts(opts.find, defaults.find); - return { - selectionClipboard: _boolean(opts.selectionClipboard, defaults.selectionClipboard), - hover: this._sanitizeHoverOpts(opts.hover, defaults.hover), - links: _boolean(opts.links, defaults.links), - contextmenu: _boolean(opts.contextmenu, defaults.contextmenu), - quickSuggestions: quickSuggestions, - quickSuggestionsDelay: _clampedInt(opts.quickSuggestionsDelay, defaults.quickSuggestionsDelay, Constants.MIN_SAFE_SMALL_INTEGER, Constants.MAX_SAFE_SMALL_INTEGER), - parameterHints: this._sanitizeParameterHintOpts(opts.parameterHints, defaults.parameterHints), - formatOnType: _boolean(opts.formatOnType, defaults.formatOnType), - formatOnPaste: _boolean(opts.formatOnPaste, defaults.formatOnPaste), - suggestOnTriggerCharacters: _boolean(opts.suggestOnTriggerCharacters, defaults.suggestOnTriggerCharacters), - acceptSuggestionOnEnter: _stringSet<'on' | 'smart' | 'off'>(opts.acceptSuggestionOnEnter, defaults.acceptSuggestionOnEnter, ['on', 'smart', 'off']), - acceptSuggestionOnCommitCharacter: _boolean(opts.acceptSuggestionOnCommitCharacter, defaults.acceptSuggestionOnCommitCharacter), - wordBasedSuggestions: _boolean(opts.wordBasedSuggestions, defaults.wordBasedSuggestions), - suggestSelection: _stringSet<'first' | 'recentlyUsed' | 'recentlyUsedByPrefix'>(opts.suggestSelection, defaults.suggestSelection, ['first', 'recentlyUsed', 'recentlyUsedByPrefix']), - suggestFontSize: _clampedInt(opts.suggestFontSize, defaults.suggestFontSize, 0, 1000), - suggestLineHeight: _clampedInt(opts.suggestLineHeight, defaults.suggestLineHeight, 0, 1000), - tabCompletion: this._sanitizeTabCompletionOpts(opts.tabCompletion, defaults.tabCompletion), - suggest: this._sanitizeSuggestOpts(opts, defaults.suggest), - gotoLocation: this._sanitizeGotoLocationOpts(opts, defaults.gotoLocation), - selectionHighlight: _boolean(opts.selectionHighlight, defaults.selectionHighlight), - occurrencesHighlight: _boolean(opts.occurrencesHighlight, defaults.occurrencesHighlight), - codeLens: _boolean(opts.codeLens, defaults.codeLens), - folding: _boolean(opts.folding, defaults.folding), - foldingStrategy: _stringSet<'auto' | 'indentation'>(opts.foldingStrategy, defaults.foldingStrategy, ['auto', 'indentation']), - showFoldingControls: _stringSet<'always' | 'mouseover'>(opts.showFoldingControls, defaults.showFoldingControls, ['always', 'mouseover']), - matchBrackets: _boolean(opts.matchBrackets, defaults.matchBrackets), - find: find, - colorDecorators: _boolean(opts.colorDecorators, defaults.colorDecorators), - lightbulbEnabled: _boolean(opts.lightbulb ? opts.lightbulb.enabled : false, defaults.lightbulbEnabled), - codeActionsOnSave: _booleanMap(opts.codeActionsOnSave, {}), - codeActionsOnSaveTimeout: _clampedInt(opts.codeActionsOnSaveTimeout, defaults.codeActionsOnSaveTimeout, 1, 10000) - }; - } -} - -/** - * @internal - */ -export class InternalEditorOptionsFactory { - - private static _tweakValidatedOptions(opts: IValidatedEditorOptions, accessibilitySupport: AccessibilitySupport): IValidatedEditorOptions { - const accessibilityIsOff = (accessibilitySupport === AccessibilitySupport.Disabled); - return { - inDiffEditor: opts.inDiffEditor, - wordSeparators: opts.wordSeparators, - lineNumbersMinChars: opts.lineNumbersMinChars, - lineDecorationsWidth: opts.lineDecorationsWidth, - readOnly: opts.readOnly, - mouseStyle: opts.mouseStyle, - disableLayerHinting: opts.disableLayerHinting, - automaticLayout: opts.automaticLayout, - wordWrap: opts.wordWrap, - wordWrapColumn: opts.wordWrapColumn, - wordWrapMinified: opts.wordWrapMinified, - wrappingIndent: opts.wrappingIndent, - wordWrapBreakBeforeCharacters: opts.wordWrapBreakBeforeCharacters, - wordWrapBreakAfterCharacters: opts.wordWrapBreakAfterCharacters, - wordWrapBreakObtrusiveCharacters: opts.wordWrapBreakObtrusiveCharacters, - autoClosingBrackets: opts.autoClosingBrackets, - autoClosingQuotes: opts.autoClosingQuotes, - autoClosingOvertype: opts.autoClosingOvertype, - autoSurround: opts.autoSurround, - autoIndent: opts.autoIndent, - dragAndDrop: opts.dragAndDrop, - emptySelectionClipboard: opts.emptySelectionClipboard, - copyWithSyntaxHighlighting: opts.copyWithSyntaxHighlighting, - useTabStops: opts.useTabStops, - multiCursorModifier: opts.multiCursorModifier, - multiCursorMergeOverlapping: opts.multiCursorMergeOverlapping, - accessibilitySupport: opts.accessibilitySupport, - showUnused: opts.showUnused, - - viewInfo: { - extraEditorClassName: opts.viewInfo.extraEditorClassName, - disableMonospaceOptimizations: opts.viewInfo.disableMonospaceOptimizations, - rulers: opts.viewInfo.rulers, - ariaLabel: (accessibilityIsOff ? nls.localize('accessibilityOffAriaLabel', "The editor is not accessible at this time. Press Alt+F1 for options.") : opts.viewInfo.ariaLabel), - renderLineNumbers: opts.viewInfo.renderLineNumbers, - renderCustomLineNumbers: opts.viewInfo.renderCustomLineNumbers, - cursorSurroundingLines: opts.viewInfo.cursorSurroundingLines, - renderFinalNewline: opts.viewInfo.renderFinalNewline, - selectOnLineNumbers: opts.viewInfo.selectOnLineNumbers, - glyphMargin: opts.viewInfo.glyphMargin, - revealHorizontalRightPadding: opts.viewInfo.revealHorizontalRightPadding, - roundedSelection: opts.viewInfo.roundedSelection, - overviewRulerLanes: opts.viewInfo.overviewRulerLanes, - overviewRulerBorder: opts.viewInfo.overviewRulerBorder, - cursorBlinking: opts.viewInfo.cursorBlinking, - mouseWheelZoom: opts.viewInfo.mouseWheelZoom, - cursorSmoothCaretAnimation: opts.viewInfo.cursorSmoothCaretAnimation, - cursorStyle: opts.viewInfo.cursorStyle, - cursorWidth: opts.viewInfo.cursorWidth, - hideCursorInOverviewRuler: opts.viewInfo.hideCursorInOverviewRuler, - scrollBeyondLastLine: opts.viewInfo.scrollBeyondLastLine, - scrollBeyondLastColumn: opts.viewInfo.scrollBeyondLastColumn, - smoothScrolling: opts.viewInfo.smoothScrolling, - stopRenderingLineAfter: opts.viewInfo.stopRenderingLineAfter, - renderWhitespace: opts.viewInfo.renderWhitespace, - renderControlCharacters: opts.viewInfo.renderControlCharacters, - fontLigatures: opts.viewInfo.fontLigatures, - renderIndentGuides: opts.viewInfo.renderIndentGuides, - highlightActiveIndentGuide: opts.viewInfo.highlightActiveIndentGuide, - renderLineHighlight: opts.viewInfo.renderLineHighlight, - scrollbar: opts.viewInfo.scrollbar, - minimap: { - enabled: opts.viewInfo.minimap.enabled, - side: opts.viewInfo.minimap.side, - renderCharacters: opts.viewInfo.minimap.renderCharacters, - showSlider: opts.viewInfo.minimap.showSlider, - maxColumn: opts.viewInfo.minimap.maxColumn - }, - fixedOverflowWidgets: opts.viewInfo.fixedOverflowWidgets - }, - - contribInfo: { - selectionClipboard: opts.contribInfo.selectionClipboard, - hover: opts.contribInfo.hover, - links: opts.contribInfo.links, - contextmenu: opts.contribInfo.contextmenu, - quickSuggestions: opts.contribInfo.quickSuggestions, - quickSuggestionsDelay: opts.contribInfo.quickSuggestionsDelay, - parameterHints: opts.contribInfo.parameterHints, - formatOnType: opts.contribInfo.formatOnType, - formatOnPaste: opts.contribInfo.formatOnPaste, - suggestOnTriggerCharacters: opts.contribInfo.suggestOnTriggerCharacters, - acceptSuggestionOnEnter: opts.contribInfo.acceptSuggestionOnEnter, - acceptSuggestionOnCommitCharacter: opts.contribInfo.acceptSuggestionOnCommitCharacter, - wordBasedSuggestions: opts.contribInfo.wordBasedSuggestions, - suggestSelection: opts.contribInfo.suggestSelection, - suggestFontSize: opts.contribInfo.suggestFontSize, - suggestLineHeight: opts.contribInfo.suggestLineHeight, - tabCompletion: opts.contribInfo.tabCompletion, - suggest: opts.contribInfo.suggest, - gotoLocation: opts.contribInfo.gotoLocation, - selectionHighlight: opts.contribInfo.selectionHighlight, - occurrencesHighlight: opts.contribInfo.occurrencesHighlight, - codeLens: opts.contribInfo.codeLens, - folding: opts.contribInfo.folding, - foldingStrategy: opts.contribInfo.foldingStrategy, - showFoldingControls: opts.contribInfo.showFoldingControls, - matchBrackets: opts.contribInfo.matchBrackets, - find: opts.contribInfo.find, - colorDecorators: opts.contribInfo.colorDecorators, - lightbulbEnabled: opts.contribInfo.lightbulbEnabled, - codeActionsOnSave: opts.contribInfo.codeActionsOnSave, - codeActionsOnSaveTimeout: opts.contribInfo.codeActionsOnSaveTimeout - } - }; - } - - public static createInternalEditorOptions(env: IEnvironmentalOptions, _opts: IValidatedEditorOptions) { - - let accessibilitySupport: AccessibilitySupport; - if (_opts.accessibilitySupport === 'auto') { - // The editor reads the `accessibilitySupport` from the environment - accessibilitySupport = env.accessibilitySupport; - } else if (_opts.accessibilitySupport === 'on') { - accessibilitySupport = AccessibilitySupport.Enabled; - } else { - accessibilitySupport = AccessibilitySupport.Disabled; - } - - // Disable some non critical features to get as best performance as possible - // See https://github.com/Microsoft/vscode/issues/26730 - const opts = this._tweakValidatedOptions(_opts, accessibilitySupport); - - let lineDecorationsWidth: number; - if (typeof opts.lineDecorationsWidth === 'string' && /^\d+(\.\d+)?ch$/.test(opts.lineDecorationsWidth)) { - const multiple = parseFloat(opts.lineDecorationsWidth.substr(0, opts.lineDecorationsWidth.length - 2)); - lineDecorationsWidth = multiple * env.fontInfo.typicalHalfwidthCharacterWidth; - } else { - lineDecorationsWidth = _clampedInt(opts.lineDecorationsWidth, 0, 0, 1000); - } - if (opts.contribInfo.folding) { - lineDecorationsWidth += 16; - } - - const layoutInfo = EditorLayoutProvider.compute({ + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: EditorLayoutInfo): EditorLayoutInfo { + return EditorLayoutInfoComputer.computeLayout(options, { outerWidth: env.outerWidth, outerHeight: env.outerHeight, - showGlyphMargin: opts.viewInfo.glyphMargin, lineHeight: env.fontInfo.lineHeight, - showLineNumbers: (opts.viewInfo.renderLineNumbers !== RenderLineNumbersType.Off), - lineNumbersMinChars: opts.lineNumbersMinChars, lineNumbersDigitCount: env.lineNumbersDigitCount, - lineDecorationsWidth: lineDecorationsWidth, typicalHalfwidthCharacterWidth: env.fontInfo.typicalHalfwidthCharacterWidth, maxDigitWidth: env.fontInfo.maxDigitWidth, - verticalScrollbarWidth: opts.viewInfo.scrollbar.verticalScrollbarSize, - horizontalScrollbarHeight: opts.viewInfo.scrollbar.horizontalScrollbarSize, - scrollbarArrowSize: opts.viewInfo.scrollbar.arrowSize, - verticalScrollbarHasArrows: opts.viewInfo.scrollbar.verticalHasArrows, - minimap: opts.viewInfo.minimap.enabled, - minimapSide: opts.viewInfo.minimap.side, - minimapRenderCharacters: opts.viewInfo.minimap.renderCharacters, - minimapMaxColumn: opts.viewInfo.minimap.maxColumn, pixelRatio: env.pixelRatio }); - - let bareWrappingInfo: { isWordWrapMinified: boolean; isViewportWrapping: boolean; wrappingColumn: number; } | null = null; - { - const wordWrap = opts.wordWrap; - const wordWrapColumn = opts.wordWrapColumn; - const wordWrapMinified = opts.wordWrapMinified; - - if (accessibilitySupport === AccessibilitySupport.Enabled) { - // See https://github.com/Microsoft/vscode/issues/27766 - // Never enable wrapping when a screen reader is attached - // because arrow down etc. will not move the cursor in the way - // a screen reader expects. - bareWrappingInfo = { - isWordWrapMinified: false, - isViewportWrapping: false, - wrappingColumn: -1 - }; - } else if (wordWrapMinified && env.isDominatedByLongLines) { - // Force viewport width wrapping if model is dominated by long lines - bareWrappingInfo = { - isWordWrapMinified: true, - isViewportWrapping: true, - wrappingColumn: Math.max(1, layoutInfo.viewportColumn) - }; - } else if (wordWrap === 'on') { - bareWrappingInfo = { - isWordWrapMinified: false, - isViewportWrapping: true, - wrappingColumn: Math.max(1, layoutInfo.viewportColumn) - }; - } else if (wordWrap === 'bounded') { - bareWrappingInfo = { - isWordWrapMinified: false, - isViewportWrapping: true, - wrappingColumn: Math.min(Math.max(1, layoutInfo.viewportColumn), wordWrapColumn) - }; - } else if (wordWrap === 'wordWrapColumn') { - bareWrappingInfo = { - isWordWrapMinified: false, - isViewportWrapping: false, - wrappingColumn: wordWrapColumn - }; - } else { - bareWrappingInfo = { - isWordWrapMinified: false, - isViewportWrapping: false, - wrappingColumn: -1 - }; - } - } - - const wrappingInfo: EditorWrappingInfo = { - inDiffEditor: opts.inDiffEditor, - isDominatedByLongLines: env.isDominatedByLongLines, - isWordWrapMinified: bareWrappingInfo.isWordWrapMinified, - isViewportWrapping: bareWrappingInfo.isViewportWrapping, - wrappingColumn: bareWrappingInfo.wrappingColumn, - wrappingIndent: opts.wrappingIndent, - wordWrapBreakBeforeCharacters: opts.wordWrapBreakBeforeCharacters, - wordWrapBreakAfterCharacters: opts.wordWrapBreakAfterCharacters, - wordWrapBreakObtrusiveCharacters: opts.wordWrapBreakObtrusiveCharacters, - }; - - let className = 'monaco-editor'; - if (opts.viewInfo.extraEditorClassName) { - className += ' ' + opts.viewInfo.extraEditorClassName; - } - if (env.extraEditorClassName) { - className += ' ' + env.extraEditorClassName; - } - if (opts.viewInfo.fontLigatures) { - className += ' enable-ligatures'; - } - if (opts.mouseStyle === 'default') { - className += ' mouse-default'; - } else if (opts.mouseStyle === 'copy') { - className += ' mouse-copy'; - } - - return new InternalEditorOptions({ - canUseLayerHinting: opts.disableLayerHinting ? false : true, - pixelRatio: env.pixelRatio, - editorClassName: className, - lineHeight: env.fontInfo.lineHeight, - readOnly: opts.readOnly, - accessibilitySupport: accessibilitySupport, - multiCursorModifier: opts.multiCursorModifier, - multiCursorMergeOverlapping: opts.multiCursorMergeOverlapping, - wordSeparators: opts.wordSeparators, - autoClosingBrackets: opts.autoClosingBrackets, - autoClosingQuotes: opts.autoClosingQuotes, - autoClosingOvertype: opts.autoClosingOvertype, - autoSurround: opts.autoSurround, - autoIndent: opts.autoIndent, - useTabStops: opts.useTabStops, - tabFocusMode: opts.readOnly ? true : env.tabFocusMode, - dragAndDrop: opts.dragAndDrop, - emptySelectionClipboard: opts.emptySelectionClipboard && env.emptySelectionClipboard, - copyWithSyntaxHighlighting: opts.copyWithSyntaxHighlighting, - layoutInfo: layoutInfo, - fontInfo: env.fontInfo, - viewInfo: opts.viewInfo, - wrappingInfo: wrappingInfo, - contribInfo: opts.contribInfo, - showUnused: opts.showUnused, - }); } -} -/** - * @internal - */ -export interface IEditorLayoutProviderOpts { - readonly outerWidth: number; - readonly outerHeight: number; + public static computeLayout(options: IComputedEditorOptions, env: EditorLayoutInfoComputerEnv): EditorLayoutInfo { + const outerWidth = env.outerWidth | 0; + const outerHeight = env.outerHeight | 0; + const lineHeight = env.lineHeight | 0; + const lineNumbersDigitCount = env.lineNumbersDigitCount | 0; + const typicalHalfwidthCharacterWidth = env.typicalHalfwidthCharacterWidth; + const maxDigitWidth = env.maxDigitWidth; + const pixelRatio = env.pixelRatio; - readonly showGlyphMargin: boolean; - readonly lineHeight: number; + const showGlyphMargin = options.get(EditorOption.glyphMargin); + const showLineNumbers = (options.get(EditorOption.lineNumbers).renderType !== RenderLineNumbersType.Off); + const lineNumbersMinChars = options.get(EditorOption.lineNumbersMinChars) | 0; + const minimap = options.get(EditorOption.minimap); + const minimapEnabled = minimap.enabled; + const minimapSide = minimap.side; + const minimapRenderCharacters = minimap.renderCharacters; + const minimapMaxColumn = minimap.maxColumn | 0; - readonly showLineNumbers: boolean; - readonly lineNumbersMinChars: number; - readonly lineNumbersDigitCount: number; + const scrollbar = options.get(EditorOption.scrollbar); + const verticalScrollbarWidth = scrollbar.verticalScrollbarSize | 0; + const verticalScrollbarHasArrows = scrollbar.verticalHasArrows; + const scrollbarArrowSize = scrollbar.arrowSize | 0; + const horizontalScrollbarHeight = scrollbar.horizontalScrollbarSize | 0; - readonly lineDecorationsWidth: number; + const rawLineDecorationsWidth = options.get(EditorOption.lineDecorationsWidth); + const folding = options.get(EditorOption.folding); - readonly typicalHalfwidthCharacterWidth: number; - readonly maxDigitWidth: number; - - readonly verticalScrollbarWidth: number; - readonly verticalScrollbarHasArrows: boolean; - readonly scrollbarArrowSize: number; - readonly horizontalScrollbarHeight: number; - - readonly minimap: boolean; - readonly minimapSide: string; - readonly minimapRenderCharacters: boolean; - readonly minimapMaxColumn: number; - readonly pixelRatio: number; -} - -/** - * @internal - */ -export class EditorLayoutProvider { - public static compute(_opts: IEditorLayoutProviderOpts): EditorLayoutInfo { - const outerWidth = _opts.outerWidth | 0; - const outerHeight = _opts.outerHeight | 0; - const showGlyphMargin = _opts.showGlyphMargin; - const lineHeight = _opts.lineHeight | 0; - const showLineNumbers = _opts.showLineNumbers; - const lineNumbersMinChars = _opts.lineNumbersMinChars | 0; - const lineNumbersDigitCount = _opts.lineNumbersDigitCount | 0; - const lineDecorationsWidth = _opts.lineDecorationsWidth | 0; - const typicalHalfwidthCharacterWidth = _opts.typicalHalfwidthCharacterWidth; - const maxDigitWidth = _opts.maxDigitWidth; - const verticalScrollbarWidth = _opts.verticalScrollbarWidth | 0; - const verticalScrollbarHasArrows = _opts.verticalScrollbarHasArrows; - const scrollbarArrowSize = _opts.scrollbarArrowSize | 0; - const horizontalScrollbarHeight = _opts.horizontalScrollbarHeight | 0; - const minimap = _opts.minimap; - const minimapSide = _opts.minimapSide; - const minimapRenderCharacters = _opts.minimapRenderCharacters; - const minimapMaxColumn = _opts.minimapMaxColumn | 0; - const pixelRatio = _opts.pixelRatio; + let lineDecorationsWidth: number; + if (typeof rawLineDecorationsWidth === 'string' && /^\d+(\.\d+)?ch$/.test(rawLineDecorationsWidth)) { + const multiple = parseFloat(rawLineDecorationsWidth.substr(0, rawLineDecorationsWidth.length - 2)); + lineDecorationsWidth = EditorIntOption.clampedInt(multiple * typicalHalfwidthCharacterWidth, 0, 0, 1000); + } else { + lineDecorationsWidth = EditorIntOption.clampedInt(rawLineDecorationsWidth, 0, 0, 1000); + } + if (folding) { + lineDecorationsWidth += 16; + } let lineNumbersWidth = 0; if (showLineNumbers) { @@ -2503,7 +1553,7 @@ export class EditorLayoutProvider { let minimapLeft: number; let minimapWidth: number; let contentWidth: number; - if (!minimap) { + if (!minimapEnabled) { minimapLeft = 0; minimapWidth = 0; renderMinimap = RenderMinimap.None; @@ -2593,6 +1643,944 @@ export class EditorLayoutProvider { } } +//#endregion + +//#region lightbulb + +/** + * Configuration options for editor lightbulb + */ +export interface IEditorLightbulbOptions { + /** + * Enable the lightbulb code action. + * Defaults to true. + */ + enabled?: boolean; +} + +export type EditorLightbulbOptions = Readonly>; + +class EditorLightbulb extends BaseEditorOption { + + constructor() { + const defaults: EditorLightbulbOptions = { enabled: true }; + super( + EditorOption.lightbulb, 'lightbulb', defaults, + { + 'editor.lightbulb.enabled': { + type: 'boolean', + default: defaults.enabled, + description: nls.localize('codeActions', "Enables the code action lightbulb in the editor.") + }, + } + ); + } + + public validate(_input: any): EditorLightbulbOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorLightbulbOptions; + return { + enabled: EditorBooleanOption.boolean(input.enabled, this.defaultValue.enabled) + }; + } +} + +//#endregion + +//#region lineHeight + +class EditorLineHeight extends EditorIntOption { + + constructor() { + super( + EditorOption.lineHeight, 'lineHeight', + EDITOR_FONT_DEFAULTS.lineHeight, 0, 150, + { description: nls.localize('lineHeight', "Controls the line height. Use 0 to compute the line height from the font size.") } + ); + } + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number { + // The lineHeight is computed from the fontSize if it is 0. + // Moreover, the final lineHeight respects the editor zoom level. + // So take the result from env.fontInfo + return env.fontInfo.lineHeight; + } +} + +//#endregion + +//#region minimap + +/** + * Configuration options for editor minimap + */ +export interface IEditorMinimapOptions { + /** + * Enable the rendering of the minimap. + * Defaults to true. + */ + enabled?: boolean; + /** + * Control the side of the minimap in editor. + * Defaults to 'right'. + */ + side?: 'right' | 'left'; + /** + * Control the rendering of the minimap slider. + * Defaults to 'mouseover'. + */ + showSlider?: 'always' | 'mouseover'; + /** + * Render the actual text on a line (as opposed to color blocks). + * Defaults to true. + */ + renderCharacters?: boolean; + /** + * Limit the width of the minimap to render at most a certain number of columns. + * Defaults to 120. + */ + maxColumn?: number; +} + +export type EditorMinimapOptions = Readonly>; + +class EditorMinimap extends BaseEditorOption { + + constructor() { + const defaults: EditorMinimapOptions = { + enabled: true, + side: 'right', + showSlider: 'mouseover', + renderCharacters: true, + maxColumn: 120, + }; + super( + EditorOption.minimap, 'minimap', defaults, + { + 'editor.minimap.enabled': { + type: 'boolean', + default: defaults.enabled, + description: nls.localize('minimap.enabled', "Controls whether the minimap is shown.") + }, + 'editor.minimap.side': { + type: 'string', + enum: ['left', 'right'], + default: defaults.side, + description: nls.localize('minimap.side', "Controls the side where to render the minimap.") + }, + 'editor.minimap.showSlider': { + type: 'string', + enum: ['always', 'mouseover'], + default: defaults.showSlider, + description: nls.localize('minimap.showSlider', "Controls whether the minimap slider is automatically hidden.") + }, + 'editor.minimap.renderCharacters': { + type: 'boolean', + default: defaults.renderCharacters, + description: nls.localize('minimap.renderCharacters', "Render the actual characters on a line as opposed to color blocks.") + }, + 'editor.minimap.maxColumn': { + type: 'number', + default: defaults.maxColumn, + description: nls.localize('minimap.maxColumn', "Limit the width of the minimap to render at most a certain number of columns.") + }, + } + ); + } + + public validate(_input: any): EditorMinimapOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorMinimapOptions; + return { + enabled: EditorBooleanOption.boolean(input.enabled, this.defaultValue.enabled), + side: EditorStringEnumOption.stringSet<'right' | 'left'>(input.side, this.defaultValue.side, ['right', 'left']), + showSlider: EditorStringEnumOption.stringSet<'always' | 'mouseover'>(input.showSlider, this.defaultValue.showSlider, ['always', 'mouseover']), + renderCharacters: EditorBooleanOption.boolean(input.renderCharacters, this.defaultValue.renderCharacters), + maxColumn: EditorIntOption.clampedInt(input.maxColumn, this.defaultValue.maxColumn, 1, 10000), + }; + } +} + +//#endregion + +//#region multiCursorModifier + +function _multiCursorModifierFromString(multiCursorModifier: 'ctrlCmd' | 'alt'): 'altKey' | 'metaKey' | 'ctrlKey' { + if (multiCursorModifier === 'ctrlCmd') { + return (platform.isMacintosh ? 'metaKey' : 'ctrlKey'); + } + return 'altKey'; +} + +//#endregion + +//#region parameterHints + +/** + * Configuration options for parameter hints + */ +export interface IEditorParameterHintOptions { + /** + * Enable parameter hints. + * Defaults to true. + */ + enabled?: boolean; + /** + * Enable cycling of parameter hints. + * Defaults to false. + */ + cycle?: boolean; +} + +export type InternalParameterHintOptions = Readonly>; + +class EditorParameterHints extends BaseEditorOption { + + constructor() { + const defaults: InternalParameterHintOptions = { + enabled: true, + cycle: false + }; + super( + EditorOption.parameterHints, 'parameterHints', defaults, + { + 'editor.parameterHints.enabled': { + type: 'boolean', + default: defaults.enabled, + description: nls.localize('parameterHints.enabled', "Enables a pop-up that shows parameter documentation and type information as you type.") + }, + 'editor.parameterHints.cycle': { + type: 'boolean', + default: defaults.cycle, + description: nls.localize('parameterHints.cycle', "Controls whether the parameter hints menu cycles or closes when reaching the end of the list.") + }, + } + ); + } + + public validate(_input: any): InternalParameterHintOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorParameterHintOptions; + return { + enabled: EditorBooleanOption.boolean(input.enabled, this.defaultValue.enabled), + cycle: EditorBooleanOption.boolean(input.cycle, this.defaultValue.cycle) + }; + } +} + +//#endregion + +//#region pixelRatio + +class EditorPixelRatio extends ComputedEditorOption { + + constructor() { + super(EditorOption.pixelRatio); + } + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: number): number { + return env.pixelRatio; + } +} + +//#endregion + +//#region quickSuggestions + +/** + * Configuration options for quick suggestions + */ +export interface IQuickSuggestionsOptions { + other: boolean; + comments: boolean; + strings: boolean; +} + +export type ValidQuickSuggestionsOptions = boolean | Readonly>; + +class EditorQuickSuggestions extends BaseEditorOption { + + public readonly defaultValue: Readonly>; + + constructor() { + const defaults: ValidQuickSuggestionsOptions = { + other: true, + comments: false, + strings: false + }; + super( + EditorOption.quickSuggestions, 'quickSuggestions', defaults, + { + anyOf: [ + { + type: 'boolean', + }, + { + type: 'object', + properties: { + strings: { + type: 'boolean', + default: defaults.strings, + description: nls.localize('quickSuggestions.strings', "Enable quick suggestions inside strings.") + }, + comments: { + type: 'boolean', + default: defaults.comments, + description: nls.localize('quickSuggestions.comments', "Enable quick suggestions inside comments.") + }, + other: { + type: 'boolean', + default: defaults.other, + description: nls.localize('quickSuggestions.other', "Enable quick suggestions outside of strings and comments.") + }, + } + } + ], + default: defaults, + description: nls.localize('quickSuggestions', "Controls whether suggestions should automatically show up while typing.") + } + ); + } + + public validate(_input: any): ValidQuickSuggestionsOptions { + if (typeof _input === 'boolean') { + return _input; + } + if (typeof _input === 'object') { + const input = _input as IQuickSuggestionsOptions; + const opts = { + other: EditorBooleanOption.boolean(input.other, this.defaultValue.other), + comments: EditorBooleanOption.boolean(input.comments, this.defaultValue.comments), + strings: EditorBooleanOption.boolean(input.strings, this.defaultValue.strings), + }; + if (opts.other && opts.comments && opts.strings) { + return true; // all on + } else if (!opts.other && !opts.comments && !opts.strings) { + return false; // all off + } else { + return opts; + } + } + return this.defaultValue; + } +} + +//#endregion + +//#region renderLineNumbers + +export type LineNumbersType = 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string); + +export const enum RenderLineNumbersType { + Off = 0, + On = 1, + Relative = 2, + Interval = 3, + Custom = 4 +} + +export interface InternalEditorRenderLineNumbersOptions { + readonly renderType: RenderLineNumbersType; + readonly renderFn: ((lineNumber: number) => string) | null; +} + +class EditorRenderLineNumbersOption extends BaseEditorOption { + + constructor() { + super( + EditorOption.lineNumbers, 'lineNumbers', { renderType: RenderLineNumbersType.On, renderFn: null }, + { + type: 'string', + enum: ['off', 'on', 'relative', 'interval'], + enumDescriptions: [ + nls.localize('lineNumbers.off', "Line numbers are not rendered."), + nls.localize('lineNumbers.on', "Line numbers are rendered as absolute number."), + nls.localize('lineNumbers.relative', "Line numbers are rendered as distance in lines to cursor position."), + nls.localize('lineNumbers.interval', "Line numbers are rendered every 10 lines.") + ], + default: 'on', + description: nls.localize('lineNumbers', "Controls the display of line numbers.") + } + ); + } + + public validate(lineNumbers: any): InternalEditorRenderLineNumbersOptions { + let renderType: RenderLineNumbersType = this.defaultValue.renderType; + let renderFn: ((lineNumber: number) => string) | null = this.defaultValue.renderFn; + + if (typeof lineNumbers !== 'undefined') { + if (typeof lineNumbers === 'function') { + renderType = RenderLineNumbersType.Custom; + renderFn = lineNumbers; + } else if (lineNumbers === 'interval') { + renderType = RenderLineNumbersType.Interval; + } else if (lineNumbers === 'relative') { + renderType = RenderLineNumbersType.Relative; + } else if (lineNumbers === 'on') { + renderType = RenderLineNumbersType.On; + } else { + renderType = RenderLineNumbersType.Off; + } + } + + return { + renderType, + renderFn + }; + } +} + +//#endregion + +//#region rulers + +class EditorRulers extends SimpleEditorOption { + + constructor() { + const defaults: number[] = []; + super( + EditorOption.rulers, 'rulers', defaults, + { + type: 'array', + items: { + type: 'number' + }, + default: defaults, + description: nls.localize('rulers', "Render vertical rulers after a certain number of monospace characters. Use multiple values for multiple rulers. No rulers are drawn if array is empty.") + } + ); + } + + public validate(input: any): number[] { + if (Array.isArray(input)) { + let rulers: number[] = []; + for (let value of input) { + rulers.push(EditorIntOption.clampedInt(value, 0, 0, 10000)); + } + rulers.sort(); + return rulers; + } + return this.defaultValue; + } +} + +//#endregion + +//#region scrollbar + +/** + * Configuration options for editor scrollbars + */ +export interface IEditorScrollbarOptions { + /** + * The size of arrows (if displayed). + * Defaults to 11. + */ + arrowSize?: number; + /** + * Render vertical scrollbar. + * Defaults to 'auto'. + */ + vertical?: 'auto' | 'visible' | 'hidden'; + /** + * Render horizontal scrollbar. + * Defaults to 'auto'. + */ + horizontal?: 'auto' | 'visible' | 'hidden'; + /** + * Cast horizontal and vertical shadows when the content is scrolled. + * Defaults to true. + */ + useShadows?: boolean; + /** + * Render arrows at the top and bottom of the vertical scrollbar. + * Defaults to false. + */ + verticalHasArrows?: boolean; + /** + * Render arrows at the left and right of the horizontal scrollbar. + * Defaults to false. + */ + horizontalHasArrows?: boolean; + /** + * Listen to mouse wheel events and react to them by scrolling. + * Defaults to true. + */ + handleMouseWheel?: boolean; + /** + * Height in pixels for the horizontal scrollbar. + * Defaults to 10 (px). + */ + horizontalScrollbarSize?: number; + /** + * Width in pixels for the vertical scrollbar. + * Defaults to 10 (px). + */ + verticalScrollbarSize?: number; + /** + * Width in pixels for the vertical slider. + * Defaults to `verticalScrollbarSize`. + */ + verticalSliderSize?: number; + /** + * Height in pixels for the horizontal slider. + * Defaults to `horizontalScrollbarSize`. + */ + horizontalSliderSize?: number; +} + +export interface InternalEditorScrollbarOptions { + readonly arrowSize: number; + readonly vertical: ScrollbarVisibility; + readonly horizontal: ScrollbarVisibility; + readonly useShadows: boolean; + readonly verticalHasArrows: boolean; + readonly horizontalHasArrows: boolean; + readonly handleMouseWheel: boolean; + readonly horizontalScrollbarSize: number; + readonly horizontalSliderSize: number; + readonly verticalScrollbarSize: number; + readonly verticalSliderSize: number; +} + +function _scrollbarVisibilityFromString(visibility: string | undefined, defaultValue: ScrollbarVisibility): ScrollbarVisibility { + if (typeof visibility !== 'string') { + return defaultValue; + } + switch (visibility) { + case 'hidden': return ScrollbarVisibility.Hidden; + case 'visible': return ScrollbarVisibility.Visible; + default: return ScrollbarVisibility.Auto; + } +} + +class EditorScrollbar extends BaseEditorOption { + + constructor() { + super( + EditorOption.scrollbar, 'scrollbar', + { + vertical: ScrollbarVisibility.Auto, + horizontal: ScrollbarVisibility.Auto, + arrowSize: 11, + useShadows: true, + verticalHasArrows: false, + horizontalHasArrows: false, + horizontalScrollbarSize: 10, + horizontalSliderSize: 10, + verticalScrollbarSize: 14, + verticalSliderSize: 14, + handleMouseWheel: true, + } + ); + } + + public validate(_input: any): InternalEditorScrollbarOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IEditorScrollbarOptions; + const horizontalScrollbarSize = EditorIntOption.clampedInt(input.horizontalScrollbarSize, this.defaultValue.horizontalScrollbarSize, 0, 1000); + const verticalScrollbarSize = EditorIntOption.clampedInt(input.verticalScrollbarSize, this.defaultValue.verticalScrollbarSize, 0, 1000); + return { + arrowSize: EditorIntOption.clampedInt(input.arrowSize, this.defaultValue.arrowSize, 0, 1000), + vertical: _scrollbarVisibilityFromString(input.vertical, this.defaultValue.vertical), + horizontal: _scrollbarVisibilityFromString(input.horizontal, this.defaultValue.horizontal), + useShadows: EditorBooleanOption.boolean(input.useShadows, this.defaultValue.useShadows), + verticalHasArrows: EditorBooleanOption.boolean(input.verticalHasArrows, this.defaultValue.verticalHasArrows), + horizontalHasArrows: EditorBooleanOption.boolean(input.horizontalHasArrows, this.defaultValue.horizontalHasArrows), + handleMouseWheel: EditorBooleanOption.boolean(input.handleMouseWheel, this.defaultValue.handleMouseWheel), + horizontalScrollbarSize: horizontalScrollbarSize, + horizontalSliderSize: EditorIntOption.clampedInt(input.horizontalSliderSize, horizontalScrollbarSize, 0, 1000), + verticalScrollbarSize: verticalScrollbarSize, + verticalSliderSize: EditorIntOption.clampedInt(input.verticalSliderSize, verticalScrollbarSize, 0, 1000), + }; + } +} + +//#endregion + +//#region suggest + +/** + * Configuration options for editor suggest widget + */ +export interface ISuggestOptions { + /** + * Enable graceful matching. Defaults to true. + */ + filterGraceful?: boolean; + /** + * Prevent quick suggestions when a snippet is active. Defaults to true. + */ + snippetsPreventQuickSuggestions?: boolean; + /** + * Favours words that appear close to the cursor. + */ + localityBonus?: boolean; + /** + * Enable using global storage for remembering suggestions. + */ + shareSuggestSelections?: boolean; + /** + * Enable or disable icons in suggestions. Defaults to true. + */ + showIcons?: boolean; + /** + * Max suggestions to show in suggestions. Defaults to 12. + */ + maxVisibleSuggestions?: number; + /** + * Names of suggestion types to filter. + */ + filteredTypes?: Record; +} + +export type InternalSuggestOptions = Readonly>; + +class EditorSuggest extends BaseEditorOption { + + constructor() { + const defaults: InternalSuggestOptions = { + filterGraceful: true, + snippetsPreventQuickSuggestions: true, + localityBonus: false, + shareSuggestSelections: false, + showIcons: true, + maxVisibleSuggestions: 12, + filteredTypes: Object.create(null) + }; + super( + EditorOption.suggest, 'suggest', defaults, + { + 'editor.suggest.filterGraceful': { + type: 'boolean', + default: defaults.filterGraceful, + description: nls.localize('suggest.filterGraceful', "Controls whether filtering and sorting suggestions accounts for small typos.") + }, + 'editor.suggest.localityBonus': { + type: 'boolean', + default: defaults.localityBonus, + description: nls.localize('suggest.localityBonus', "Controls whether sorting favours words that appear close to the cursor.") + }, + 'editor.suggest.shareSuggestSelections': { + type: 'boolean', + default: defaults.shareSuggestSelections, + markdownDescription: nls.localize('suggest.shareSuggestSelections', "Controls whether remembered suggestion selections are shared between multiple workspaces and windows (needs `#editor.suggestSelection#`).") + }, + 'editor.suggest.snippetsPreventQuickSuggestions': { + type: 'boolean', + default: defaults.snippetsPreventQuickSuggestions, + description: nls.localize('suggest.snippetsPreventQuickSuggestions', "Control whether an active snippet prevents quick suggestions.") + }, + 'editor.suggest.showIcons': { + type: 'boolean', + default: defaults.showIcons, + description: nls.localize('suggest.showIcons', "Controls whether to show or hide icons in suggestions.") + }, + 'editor.suggest.maxVisibleSuggestions': { + type: 'number', + default: defaults.maxVisibleSuggestions, + minimum: 1, + maximum: 15, + description: nls.localize('suggest.maxVisibleSuggestions', "Controls how many suggestions IntelliSense will show before showing a scrollbar (maximum 15).") + }, + 'editor.suggest.filteredTypes': { + type: 'object', + default: { keyword: true, snippet: true }, + markdownDescription: nls.localize('suggest.filtered', "Controls whether some suggestion types should be filtered from IntelliSense. A list of suggestion types can be found here: https://code.visualstudio.com/docs/editor/intellisense#_types-of-completions."), + properties: { + method: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.method', "When set to `false` IntelliSense never shows `method` suggestions.") + }, + function: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.function', "When set to `false` IntelliSense never shows `function` suggestions.") + }, + constructor: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.constructor', "When set to `false` IntelliSense never shows `constructor` suggestions.") + }, + field: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.field', "When set to `false` IntelliSense never shows `field` suggestions.") + }, + variable: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.variable', "When set to `false` IntelliSense never shows `variable` suggestions.") + }, + class: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.class', "When set to `false` IntelliSense never shows `class` suggestions.") + }, + struct: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.struct', "When set to `false` IntelliSense never shows `struct` suggestions.") + }, + interface: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.interface', "When set to `false` IntelliSense never shows `interface` suggestions.") + }, + module: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.module', "When set to `false` IntelliSense never shows `module` suggestions.") + }, + property: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.property', "When set to `false` IntelliSense never shows `property` suggestions.") + }, + event: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.event', "When set to `false` IntelliSense never shows `event` suggestions.") + }, + operator: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.operator', "When set to `false` IntelliSense never shows `operator` suggestions.") + }, + unit: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.unit', "When set to `false` IntelliSense never shows `unit` suggestions.") + }, + value: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.value', "When set to `false` IntelliSense never shows `value` suggestions.") + }, + constant: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.constant', "When set to `false` IntelliSense never shows `constant` suggestions.") + }, + enum: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.enum', "When set to `false` IntelliSense never shows `enum` suggestions.") + }, + enumMember: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.enumMember', "When set to `false` IntelliSense never shows `enumMember` suggestions.") + }, + keyword: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.keyword', "When set to `false` IntelliSense never shows `keyword` suggestions.") + }, + text: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.text', "When set to `false` IntelliSense never shows `text` suggestions.") + }, + color: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.color', "When set to `false` IntelliSense never shows `color` suggestions.") + }, + file: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.file', "When set to `false` IntelliSense never shows `file` suggestions.") + }, + reference: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.reference', "When set to `false` IntelliSense never shows `reference` suggestions.") + }, + customcolor: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.customcolor', "When set to `false` IntelliSense never shows `customcolor` suggestions.") + }, + folder: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.folder', "When set to `false` IntelliSense never shows `folder` suggestions.") + }, + typeParameter: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.typeParameter', "When set to `false` IntelliSense never shows `typeParameter` suggestions.") + }, + snippet: { + type: 'boolean', + default: true, + markdownDescription: nls.localize('suggest.filtered.snippet', "When set to `false` IntelliSense never shows `snippet` suggestions.") + }, + } + }, + } + ); + } + + public validate(_input: any): InternalSuggestOptions { + if (typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as ISuggestOptions; + return { + filterGraceful: EditorBooleanOption.boolean(input.filterGraceful, this.defaultValue.filterGraceful), + snippetsPreventQuickSuggestions: EditorBooleanOption.boolean(input.snippetsPreventQuickSuggestions, this.defaultValue.filterGraceful), + localityBonus: EditorBooleanOption.boolean(input.localityBonus, this.defaultValue.localityBonus), + shareSuggestSelections: EditorBooleanOption.boolean(input.shareSuggestSelections, this.defaultValue.shareSuggestSelections), + showIcons: EditorBooleanOption.boolean(input.showIcons, this.defaultValue.showIcons), + maxVisibleSuggestions: EditorIntOption.clampedInt(input.maxVisibleSuggestions, this.defaultValue.maxVisibleSuggestions, 1, 15), + filteredTypes: isObject(input.filteredTypes) ? input.filteredTypes : Object.create(null) + }; + } +} + +//#endregion + +//#region tabFocusMode + +class EditorTabFocusMode extends ComputedEditorOption { + + constructor() { + super(EditorOption.tabFocusMode, [EditorOption.readOnly]); + } + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: boolean): boolean { + const readOnly = options.get(EditorOption.readOnly); + return (readOnly ? true : env.tabFocusMode); + } +} + +//#endregion + +//#region wrappingIndent + +/** + * Describes how to indent wrapped lines. + */ +export const enum WrappingIndent { + /** + * No indentation => wrapped lines begin at column 1. + */ + None = 0, + /** + * Same => wrapped lines get the same indentation as the parent. + */ + Same = 1, + /** + * Indent => wrapped lines get +1 indentation toward the parent. + */ + Indent = 2, + /** + * DeepIndent => wrapped lines get +2 indentation toward the parent. + */ + DeepIndent = 3 +} + +function _wrappingIndentFromString(wrappingIndent: 'none' | 'same' | 'indent' | 'deepIndent'): WrappingIndent { + switch (wrappingIndent) { + case 'none': return WrappingIndent.None; + case 'same': return WrappingIndent.Same; + case 'indent': return WrappingIndent.Indent; + case 'deepIndent': return WrappingIndent.DeepIndent; + } +} + +//#endregion + +//#region wrappingInfo + +export interface EditorWrappingInfo { + readonly isDominatedByLongLines: boolean; + readonly isWordWrapMinified: boolean; + readonly isViewportWrapping: boolean; + readonly wrappingColumn: number; +} + +class EditorWrappingInfoComputer extends ComputedEditorOption { + + constructor() { + super(EditorOption.wrappingInfo, [EditorOption.wordWrap, EditorOption.wordWrapColumn, EditorOption.wordWrapMinified, EditorOption.layoutInfo, EditorOption.accessibilitySupport]); + } + + public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: EditorWrappingInfo): EditorWrappingInfo { + const wordWrap = options.get(EditorOption.wordWrap); + const wordWrapColumn = options.get(EditorOption.wordWrapColumn); + const wordWrapMinified = options.get(EditorOption.wordWrapMinified); + const layoutInfo = options.get(EditorOption.layoutInfo); + const accessibilitySupport = options.get(EditorOption.accessibilitySupport); + + let bareWrappingInfo: { isWordWrapMinified: boolean; isViewportWrapping: boolean; wrappingColumn: number; } | null = null; + { + if (accessibilitySupport === AccessibilitySupport.Enabled) { + // See https://github.com/Microsoft/vscode/issues/27766 + // Never enable wrapping when a screen reader is attached + // because arrow down etc. will not move the cursor in the way + // a screen reader expects. + bareWrappingInfo = { + isWordWrapMinified: false, + isViewportWrapping: false, + wrappingColumn: -1 + }; + } else if (wordWrapMinified && env.isDominatedByLongLines) { + // Force viewport width wrapping if model is dominated by long lines + bareWrappingInfo = { + isWordWrapMinified: true, + isViewportWrapping: true, + wrappingColumn: Math.max(1, layoutInfo.viewportColumn) + }; + } else if (wordWrap === 'on') { + bareWrappingInfo = { + isWordWrapMinified: false, + isViewportWrapping: true, + wrappingColumn: Math.max(1, layoutInfo.viewportColumn) + }; + } else if (wordWrap === 'bounded') { + bareWrappingInfo = { + isWordWrapMinified: false, + isViewportWrapping: true, + wrappingColumn: Math.min(Math.max(1, layoutInfo.viewportColumn), wordWrapColumn) + }; + } else if (wordWrap === 'wordWrapColumn') { + bareWrappingInfo = { + isWordWrapMinified: false, + isViewportWrapping: false, + wrappingColumn: wordWrapColumn + }; + } else { + bareWrappingInfo = { + isWordWrapMinified: false, + isViewportWrapping: false, + wrappingColumn: -1 + }; + } + } + + return { + isDominatedByLongLines: env.isDominatedByLongLines, + isWordWrapMinified: bareWrappingInfo.isWordWrapMinified, + isViewportWrapping: bareWrappingInfo.isViewportWrapping, + wrappingColumn: bareWrappingInfo.wrappingColumn, + }; + } +} + +//#endregion + const DEFAULT_WINDOWS_FONT_FAMILY = 'Consolas, \'Courier New\', monospace'; const DEFAULT_MAC_FONT_FAMILY = 'Menlo, Monaco, \'Courier New\', monospace'; const DEFAULT_LINUX_FONT_FAMILY = '\'Droid Sans Mono\', \'monospace\', monospace, \'Droid Sans Fallback\''; @@ -2627,146 +2615,673 @@ export const EDITOR_MODEL_DEFAULTS = { /** * @internal */ -export const EDITOR_DEFAULTS: IValidatedEditorOptions = { - inDiffEditor: false, - wordSeparators: USUAL_WORD_SEPARATORS, - lineNumbersMinChars: 5, - lineDecorationsWidth: 10, - readOnly: false, - mouseStyle: 'text', - disableLayerHinting: false, - automaticLayout: false, - wordWrap: 'off', - wordWrapColumn: 80, - wordWrapMinified: true, - wrappingIndent: WrappingIndent.Same, - wordWrapBreakBeforeCharacters: '([{‘“〈《「『【〔([{「£¥$£¥++', - wordWrapBreakAfterCharacters: ' \t})]?|/&,;¢°′″‰℃、。。、¢,.:;?!%・・ゝゞヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻ァィゥェォャュョッー”〉》」』】〕)]}」', - wordWrapBreakObtrusiveCharacters: '.', - autoClosingBrackets: 'languageDefined', - autoClosingQuotes: 'languageDefined', - autoClosingOvertype: 'auto', - autoSurround: 'languageDefined', - autoIndent: true, - dragAndDrop: true, - emptySelectionClipboard: true, - copyWithSyntaxHighlighting: true, - useTabStops: true, - multiCursorModifier: 'altKey', - multiCursorMergeOverlapping: true, - accessibilitySupport: 'auto', - showUnused: true, +export const editorOptionsRegistry: IEditorOption[] = []; - viewInfo: { - extraEditorClassName: '', - disableMonospaceOptimizations: false, - rulers: [], - ariaLabel: nls.localize('editorViewAccessibleLabel', "Editor content"), - renderLineNumbers: RenderLineNumbersType.On, - renderCustomLineNumbers: null, - cursorSurroundingLines: 0, - renderFinalNewline: true, - selectOnLineNumbers: true, - glyphMargin: true, - revealHorizontalRightPadding: 30, - roundedSelection: true, - overviewRulerLanes: 2, - overviewRulerBorder: true, - cursorBlinking: TextEditorCursorBlinkingStyle.Blink, - mouseWheelZoom: false, - cursorSmoothCaretAnimation: false, - cursorStyle: TextEditorCursorStyle.Line, - cursorWidth: 0, - hideCursorInOverviewRuler: false, - scrollBeyondLastLine: true, - scrollBeyondLastColumn: 5, - smoothScrolling: false, - stopRenderingLineAfter: 10000, - renderWhitespace: 'none', - renderControlCharacters: false, - fontLigatures: false, - renderIndentGuides: true, - highlightActiveIndentGuide: true, - renderLineHighlight: 'line', - scrollbar: { - vertical: ScrollbarVisibility.Auto, - horizontal: ScrollbarVisibility.Auto, - arrowSize: 11, - useShadows: true, - verticalHasArrows: false, - horizontalHasArrows: false, - horizontalScrollbarSize: 10, - horizontalSliderSize: 10, - verticalScrollbarSize: 14, - verticalSliderSize: 14, - handleMouseWheel: true, - mouseWheelScrollSensitivity: 1, - fastScrollSensitivity: 5, - }, - minimap: { - enabled: true, - side: 'right', - showSlider: 'mouseover', - renderCharacters: true, - maxColumn: 120 - }, - fixedOverflowWidgets: false, - }, +function register(option: IEditorOption): IEditorOption { + editorOptionsRegistry[option.id] = option; + return option; +} - contribInfo: { - selectionClipboard: true, - hover: { - enabled: true, - delay: 300, - sticky: true - }, - links: true, - contextmenu: true, - quickSuggestions: { other: true, comments: false, strings: false }, - quickSuggestionsDelay: 10, - parameterHints: { - enabled: true, - cycle: false - }, - formatOnType: false, - formatOnPaste: false, - suggestOnTriggerCharacters: true, - acceptSuggestionOnEnter: 'on', - acceptSuggestionOnCommitCharacter: true, - wordBasedSuggestions: true, - suggestSelection: 'recentlyUsed', - suggestFontSize: 0, - suggestLineHeight: 0, - tabCompletion: 'off', - suggest: { - filterGraceful: true, - snippets: 'inline', - snippetsPreventQuickSuggestions: true, - localityBonus: false, - shareSuggestSelections: false, - showIcons: true, - maxVisibleSuggestions: 12, - filteredTypes: Object.create(null) - }, - gotoLocation: { - multiple: 'peek' - }, - selectionHighlight: true, - occurrencesHighlight: true, - codeLens: true, - folding: true, - foldingStrategy: 'auto', - showFoldingControls: 'mouseover', - matchBrackets: true, - find: { - seedSearchStringFromSelection: true, - autoFindInSelection: false, - globalFindClipboard: false, - addExtraSpaceOnTop: true - }, - colorDecorators: true, - lightbulbEnabled: true, - codeActionsOnSave: {}, - codeActionsOnSaveTimeout: 750 - }, +/** + * @internal + */ +export const enum EditorOption { + acceptSuggestionOnCommitCharacter, + acceptSuggestionOnEnter, + accessibilitySupport, + ariaLabel, + autoClosingBrackets, + autoClosingOvertype, + autoClosingQuotes, + autoIndent, + automaticLayout, + autoSurround, + codeLens, + colorDecorators, + contextmenu, + copyWithSyntaxHighlighting, + cursorBlinking, + cursorSmoothCaretAnimation, + cursorStyle, + cursorSurroundingLines, + cursorWidth, + disableLayerHinting, + disableMonospaceOptimizations, + dragAndDrop, + emptySelectionClipboard, + extraEditorClassName, + fastScrollSensitivity, + find, + fixedOverflowWidgets, + folding, + foldingStrategy, + fontFamily, + fontInfo, + fontLigatures, + fontSize, + fontWeight, + formatOnPaste, + formatOnType, + glyphMargin, + gotoLocation, + hideCursorInOverviewRuler, + highlightActiveIndentGuide, + hover, + inDiffEditor, + letterSpacing, + lightbulb, + lineDecorationsWidth, + lineHeight, + lineNumbers, + lineNumbersMinChars, + links, + matchBrackets, + minimap, + mouseStyle, + mouseWheelScrollSensitivity, + mouseWheelZoom, + multiCursorMergeOverlapping, + multiCursorModifier, + multiCursorPaste, + occurrencesHighlight, + overviewRulerBorder, + overviewRulerLanes, + parameterHints, + quickSuggestions, + quickSuggestionsDelay, + readOnly, + renderControlCharacters, + renderIndentGuides, + renderFinalNewline, + renderLineHighlight, + renderWhitespace, + revealHorizontalRightPadding, + roundedSelection, + rulers, + scrollbar, + scrollBeyondLastColumn, + scrollBeyondLastLine, + selectionClipboard, + selectionHighlight, + selectOnLineNumbers, + showFoldingControls, + showUnused, + snippetSuggestions, + smoothScrolling, + stopRenderingLineAfter, + suggest, + suggestFontSize, + suggestLineHeight, + suggestOnTriggerCharacters, + suggestSelection, + tabCompletion, + useTabStops, + wordSeparators, + wordWrap, + wordWrapBreakAfterCharacters, + wordWrapBreakBeforeCharacters, + wordWrapBreakObtrusiveCharacters, + wordWrapColumn, + wordWrapMinified, + wrappingIndent, + + // Leave these at the end (because they have dependencies!) + editorClassName, + pixelRatio, + tabFocusMode, + layoutInfo, + wrappingInfo, +} + +/** + * @internal + */ +export const EditorOptions = { + acceptSuggestionOnCommitCharacter: register(new EditorBooleanOption( + EditorOption.acceptSuggestionOnCommitCharacter, 'acceptSuggestionOnCommitCharacter', true, + { markdownDescription: nls.localize('acceptSuggestionOnCommitCharacter', "Controls whether suggestions should be accepted on commit characters. For example, in JavaScript, the semi-colon (`;`) can be a commit character that accepts a suggestion and types that character.") } + )), + acceptSuggestionOnEnter: register(new EditorStringEnumOption( + EditorOption.acceptSuggestionOnEnter, 'acceptSuggestionOnEnter', + 'on' as 'on' | 'smart' | 'off', + ['on', 'smart', 'off'] as const, + { + markdownEnumDescriptions: [ + '', + nls.localize('acceptSuggestionOnEnterSmart', "Only accept a suggestion with `Enter` when it makes a textual change."), + '' + ], + markdownDescription: nls.localize('acceptSuggestionOnEnter', "Controls whether suggestions should be accepted on `Enter`, in addition to `Tab`. Helps to avoid ambiguity between inserting new lines or accepting suggestions.") + } + )), + accessibilitySupport: register(new EditorAccessibilitySupport()), + ariaLabel: register(new EditorStringOption( + EditorOption.ariaLabel, 'ariaLabel', nls.localize('editorViewAccessibleLabel', "Editor content") + )), + autoClosingBrackets: register(new EditorStringEnumOption( + EditorOption.autoClosingBrackets, 'autoClosingBrackets', + 'languageDefined' as 'always' | 'languageDefined' | 'beforeWhitespace' | 'never', + ['always', 'languageDefined', 'beforeWhitespace', 'never'] as const, + { + enumDescriptions: [ + '', + nls.localize('editor.autoClosingBrackets.languageDefined', "Use language configurations to determine when to autoclose brackets."), + nls.localize('editor.autoClosingBrackets.beforeWhitespace', "Autoclose brackets only when the cursor is to the left of whitespace."), + '', + ], + description: nls.localize('autoClosingBrackets', "Controls whether the editor should automatically close brackets after the user adds an opening bracket.") + } + )), + autoClosingOvertype: register(new EditorStringEnumOption( + EditorOption.autoClosingOvertype, 'autoClosingOvertype', + 'auto' as 'always' | 'auto' | 'never', + ['always', 'auto', 'never'] as const, + { + enumDescriptions: [ + '', + nls.localize('editor.autoClosingOvertype.auto', "Type over closing quotes or brackets only if they were automatically inserted."), + '', + ], + description: nls.localize('autoClosingOvertype', "Controls whether the editor should type over closing quotes or brackets.") + } + )), + autoClosingQuotes: register(new EditorStringEnumOption( + EditorOption.autoClosingQuotes, 'autoClosingQuotes', + 'languageDefined' as 'always' | 'languageDefined' | 'beforeWhitespace' | 'never', + ['always', 'languageDefined', 'beforeWhitespace', 'never'] as const, + { + enumDescriptions: [ + '', + nls.localize('editor.autoClosingQuotes.languageDefined', "Use language configurations to determine when to autoclose quotes."), + nls.localize('editor.autoClosingQuotes.beforeWhitespace', "Autoclose quotes only when the cursor is to the left of whitespace."), + '', + ], + description: nls.localize('autoClosingQuotes', "Controls whether the editor should automatically close quotes after the user adds an opening quote.") + } + )), + autoIndent: register(new EditorBooleanOption( + EditorOption.autoIndent, 'autoIndent', true, + { description: nls.localize('autoIndent', "Controls whether the editor should automatically adjust the indentation when users type, paste or move lines. Extensions with indentation rules of the language must be available.") } + )), + automaticLayout: register(new EditorBooleanOption( + EditorOption.automaticLayout, 'automaticLayout', false, + )), + autoSurround: register(new EditorStringEnumOption( + EditorOption.autoSurround, 'autoSurround', + 'languageDefined' as 'languageDefined' | 'quotes' | 'brackets' | 'never', + ['languageDefined', 'quotes', 'brackets', 'never'] as const, + { + enumDescriptions: [ + nls.localize('editor.autoSurround.languageDefined', "Use language configurations to determine when to automatically surround selections."), + nls.localize('editor.autoSurround.quotes', "Surround with quotes but not brackets."), + nls.localize('editor.autoSurround.brackets', "Surround with brackets but not quotes."), + '' + ], + description: nls.localize('autoSurround', "Controls whether the editor should automatically surround selections.") + } + )), + codeLens: register(new EditorBooleanOption( + EditorOption.codeLens, 'codeLens', true, + { description: nls.localize('codeLens', "Controls whether the editor shows CodeLens.") } + )), + colorDecorators: register(new EditorBooleanOption( + EditorOption.colorDecorators, 'colorDecorators', true, + { description: nls.localize('colorDecorators', "Controls whether the editor should render the inline color decorators and color picker.") } + )), + contextmenu: register(new EditorBooleanOption( + EditorOption.contextmenu, 'contextmenu', true, + )), + copyWithSyntaxHighlighting: register(new EditorBooleanOption( + EditorOption.copyWithSyntaxHighlighting, 'copyWithSyntaxHighlighting', true, + { description: nls.localize('copyWithSyntaxHighlighting', "Controls whether syntax highlighting should be copied into the clipboard.") } + )), + cursorBlinking: register(new EditorEnumOption( + EditorOption.cursorBlinking, 'cursorBlinking', + TextEditorCursorBlinkingStyle.Blink, 'blink', + ['blink', 'smooth', 'phase', 'expand', 'solid'], + _cursorBlinkingStyleFromString, + { description: nls.localize('cursorBlinking', "Control the cursor animation style.") } + )), + cursorSmoothCaretAnimation: register(new EditorBooleanOption( + EditorOption.cursorSmoothCaretAnimation, 'cursorSmoothCaretAnimation', false, + { description: nls.localize('cursorSmoothCaretAnimation', "Controls whether the smooth caret animation should be enabled.") } + )), + cursorStyle: register(new EditorEnumOption( + EditorOption.cursorStyle, 'cursorStyle', + TextEditorCursorStyle.Line, 'line', + ['line', 'block', 'underline', 'line-thin', 'block-outline', 'underline-thin'], + _cursorStyleFromString, + { description: nls.localize('cursorStyle', "Controls the cursor style.") } + )), + cursorSurroundingLines: register(new EditorIntOption( + EditorOption.cursorSurroundingLines, 'cursorSurroundingLines', + 0, 0, Constants.MAX_SAFE_SMALL_INTEGER, + { description: nls.localize('cursorSurroundingLines', "Controls the minimal number of visible leading and trailing lines surrounding the cursor. Known as 'scrollOff' or `scrollOffset` in some other editors.") } + )), + cursorWidth: register(new EditorIntOption( + EditorOption.cursorWidth, 'cursorWidth', + 0, 0, Constants.MAX_SAFE_SMALL_INTEGER, + { markdownDescription: nls.localize('cursorWidth', "Controls the width of the cursor when `#editor.cursorStyle#` is set to `line`.") } + )), + disableLayerHinting: register(new EditorBooleanOption( + EditorOption.disableLayerHinting, 'disableLayerHinting', false, + )), + disableMonospaceOptimizations: register(new EditorBooleanOption( + EditorOption.disableMonospaceOptimizations, 'disableMonospaceOptimizations', false + )), + dragAndDrop: register(new EditorBooleanOption( + EditorOption.dragAndDrop, 'dragAndDrop', true, + { description: nls.localize('dragAndDrop', "Controls whether the editor should allow moving selections via drag and drop.") } + )), + emptySelectionClipboard: register(new EditorEmptySelectionClipboard()), + extraEditorClassName: register(new EditorStringOption( + EditorOption.extraEditorClassName, 'extraEditorClassName', '', + )), + fastScrollSensitivity: register(new EditorFloatOption( + EditorOption.fastScrollSensitivity, 'fastScrollSensitivity', + 5, x => (x <= 0 ? 5 : x), + { markdownDescription: nls.localize('fastScrollSensitivity', "Scrolling speed multiplier when pressing `Alt`.") } + )), + find: register(new EditorFind()), + fixedOverflowWidgets: register(new EditorBooleanOption( + EditorOption.fixedOverflowWidgets, 'fixedOverflowWidgets', false, + )), + folding: register(new EditorBooleanOption( + EditorOption.folding, 'folding', true, + { description: nls.localize('folding', "Controls whether the editor has code folding enabled.") } + )), + foldingStrategy: register(new EditorStringEnumOption( + EditorOption.foldingStrategy, 'foldingStrategy', + 'auto' as 'auto' | 'indentation', + ['auto', 'indentation'] as const, + { markdownDescription: nls.localize('foldingStrategy', "Controls the strategy for computing folding ranges. `auto` uses a language specific folding strategy, if available. `indentation` uses the indentation based folding strategy.") } + )), + fontFamily: register(new EditorStringOption( + EditorOption.fontFamily, 'fontFamily', EDITOR_FONT_DEFAULTS.fontFamily, + { description: nls.localize('fontFamily', "Controls the font family.") } + )), + fontInfo: register(new EditorFontInfo()), + fontLigatures: register(new EditorBooleanOption( + EditorOption.fontLigatures, 'fontLigatures', false, + { description: nls.localize('fontLigatures', "Enables/Disables font ligatures.") } + )), + fontSize: register(new EditorFontSize()), + fontWeight: register(new EditorStringOption( + EditorOption.fontWeight, 'fontWeight', EDITOR_FONT_DEFAULTS.fontWeight, + { + enum: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'], + description: nls.localize('fontWeight', "Controls the font weight.") + } + )), + formatOnPaste: register(new EditorBooleanOption( + EditorOption.formatOnPaste, 'formatOnPaste', false, + { description: nls.localize('formatOnPaste', "Controls whether the editor should automatically format the pasted content. A formatter must be available and the formatter should be able to format a range in a document.") } + )), + formatOnType: register(new EditorBooleanOption( + EditorOption.formatOnType, 'formatOnType', false, + { description: nls.localize('formatOnType', "Controls whether the editor should automatically format the line after typing.") } + )), + glyphMargin: register(new EditorBooleanOption( + EditorOption.glyphMargin, 'glyphMargin', true, + { description: nls.localize('glyphMargin', "Controls whether the editor should render the vertical glyph margin. Glyph margin is mostly used for debugging.") } + )), + gotoLocation: register(new EditorGoToLocation()), + hideCursorInOverviewRuler: register(new EditorBooleanOption( + EditorOption.hideCursorInOverviewRuler, 'hideCursorInOverviewRuler', false, + { description: nls.localize('hideCursorInOverviewRuler', "Controls whether the cursor should be hidden in the overview ruler.") } + )), + highlightActiveIndentGuide: register(new EditorBooleanOption( + EditorOption.highlightActiveIndentGuide, 'highlightActiveIndentGuide', true, + { description: nls.localize('highlightActiveIndentGuide', "Controls whether the editor should highlight the active indent guide.") } + )), + hover: register(new EditorHover()), + inDiffEditor: register(new EditorBooleanOption( + EditorOption.inDiffEditor, 'inDiffEditor', false, + )), + letterSpacing: register(new EditorFloatOption( + EditorOption.letterSpacing, 'letterSpacing', + EDITOR_FONT_DEFAULTS.letterSpacing, x => EditorFloatOption.clamp(x, -5, 20), + { description: nls.localize('letterSpacing', "Controls the letter spacing in pixels.") } + )), + lightbulb: register(new EditorLightbulb()), + lineDecorationsWidth: register(new SimpleEditorOption(EditorOption.lineDecorationsWidth, 'lineDecorationsWidth', 10 as number | string)), + lineHeight: register(new EditorLineHeight()), + lineNumbers: register(new EditorRenderLineNumbersOption()), + lineNumbersMinChars: register(new EditorIntOption( + EditorOption.lineNumbersMinChars, 'lineNumbersMinChars', + 5, 1, 10 + )), + links: register(new EditorBooleanOption( + EditorOption.links, 'links', true, + { description: nls.localize('links', "Controls whether the editor should detect links and make them clickable.") } + )), + matchBrackets: register(new EditorBooleanOption( + EditorOption.matchBrackets, 'matchBrackets', true, + { description: nls.localize('matchBrackets', "Highlight matching brackets when one of them is selected.") } + )), + minimap: register(new EditorMinimap()), + mouseStyle: register(new EditorStringEnumOption( + EditorOption.mouseStyle, 'mouseStyle', + 'text' as 'text' | 'default' | 'copy', + ['text', 'default', 'copy'] as const, + )), + mouseWheelScrollSensitivity: register(new EditorFloatOption( + EditorOption.mouseWheelScrollSensitivity, 'mouseWheelScrollSensitivity', + 1, x => (x === 0 ? 1 : x), + { markdownDescription: nls.localize('mouseWheelScrollSensitivity', "A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.") } + )), + mouseWheelZoom: register(new EditorBooleanOption( + EditorOption.mouseWheelZoom, 'mouseWheelZoom', false, + { markdownDescription: nls.localize('mouseWheelZoom', "Zoom the font of the editor when using mouse wheel and holding `Ctrl`.") } + )), + multiCursorMergeOverlapping: register(new EditorBooleanOption( + EditorOption.multiCursorMergeOverlapping, 'multiCursorMergeOverlapping', true, + { description: nls.localize('multiCursorMergeOverlapping', "Merge multiple cursors when they are overlapping.") } + )), + multiCursorModifier: register(new EditorEnumOption( + EditorOption.multiCursorModifier, 'multiCursorModifier', + 'altKey', 'alt', + ['ctrlCmd', 'alt'], + _multiCursorModifierFromString, + { + markdownEnumDescriptions: [ + nls.localize('multiCursorModifier.ctrlCmd', "Maps to `Control` on Windows and Linux and to `Command` on macOS."), + nls.localize('multiCursorModifier.alt', "Maps to `Alt` on Windows and Linux and to `Option` on macOS.") + ], + markdownDescription: nls.localize({ + key: 'multiCursorModifier', + comment: [ + '- `ctrlCmd` refers to a value the setting can take and should not be localized.', + '- `Control` and `Command` refer to the modifier keys Ctrl or Cmd on the keyboard and can be localized.' + ] + }, "The modifier to be used to add multiple cursors with the mouse. The Go To Definition and Open Link mouse gestures will adapt such that they do not conflict with the multicursor modifier. [Read more](https://code.visualstudio.com/docs/editor/codebasics#_multicursor-modifier).") + } + )), + multiCursorPaste: register(new EditorStringEnumOption( + EditorOption.multiCursorPaste, 'multiCursorPaste', + 'spread' as 'spread' | 'full', + ['spread', 'full'] as const, + { + markdownEnumDescriptions: [ + nls.localize('multiCursorPaste.spread', "Each cursor pastes a single line of the text."), + nls.localize('multiCursorPaste.full', "Each cursor pastes the full text.") + ], + markdownDescription: nls.localize('multiCursorPaste', "Controls pasting when the line count of the pasted text matches the cursor count.") + } + )), + occurrencesHighlight: register(new EditorBooleanOption( + EditorOption.occurrencesHighlight, 'occurrencesHighlight', true, + { description: nls.localize('occurrencesHighlight', "Controls whether the editor should highlight semantic symbol occurrences.") } + )), + overviewRulerBorder: register(new EditorBooleanOption( + EditorOption.overviewRulerBorder, 'overviewRulerBorder', true, + { description: nls.localize('overviewRulerBorder', "Controls whether a border should be drawn around the overview ruler.") } + )), + overviewRulerLanes: register(new EditorIntOption( + EditorOption.overviewRulerLanes, 'overviewRulerLanes', + 3, 0, 3, + { description: nls.localize('overviewRulerLanes', "Controls the number of decorations that can show up at the same position in the overview ruler.") } + )), + parameterHints: register(new EditorParameterHints()), + quickSuggestions: register(new EditorQuickSuggestions()), + quickSuggestionsDelay: register(new EditorIntOption( + EditorOption.quickSuggestionsDelay, 'quickSuggestionsDelay', + 10, 0, Constants.MAX_SAFE_SMALL_INTEGER, + { description: nls.localize('quickSuggestionsDelay', "Controls the delay in milliseconds after which quick suggestions will show up.") } + )), + readOnly: register(new EditorBooleanOption( + EditorOption.readOnly, 'readOnly', false, + )), + renderControlCharacters: register(new EditorBooleanOption( + EditorOption.renderControlCharacters, 'renderControlCharacters', false, + { description: nls.localize('renderControlCharacters', "Controls whether the editor should render control characters.") } + )), + renderIndentGuides: register(new EditorBooleanOption( + EditorOption.renderIndentGuides, 'renderIndentGuides', true, + { description: nls.localize('renderIndentGuides', "Controls whether the editor should render indent guides.") } + )), + renderFinalNewline: register(new EditorBooleanOption( + EditorOption.renderFinalNewline, 'renderFinalNewline', true, + { description: nls.localize('renderFinalNewline', "Render last line number when the file ends with a newline.") } + )), + renderLineHighlight: register(new EditorStringEnumOption( + EditorOption.renderLineHighlight, 'renderLineHighlight', + 'line' as 'none' | 'gutter' | 'line' | 'all', + ['none', 'gutter', 'line', 'all'] as const, + { + enumDescriptions: [ + '', + '', + '', + nls.localize('renderLineHighlight.all', "Highlights both the gutter and the current line."), + ], + description: nls.localize('renderLineHighlight', "Controls how the editor should render the current line highlight.") + } + )), + renderWhitespace: register(new EditorStringEnumOption( + EditorOption.renderWhitespace, 'renderWhitespace', + 'none' as 'none' | 'boundary' | 'selection' | 'all', + ['none', 'boundary', 'selection', 'all'] as const, + { + enumDescriptions: [ + '', + nls.localize('renderWhitespace.boundary', "Render whitespace characters except for single spaces between words."), + nls.localize('renderWhitespace.selection', "Render whitespace characters only on selected text."), + '' + ], + description: nls.localize('renderWhitespace', "Controls how the editor should render whitespace characters.") + } + )), + revealHorizontalRightPadding: register(new EditorIntOption( + EditorOption.revealHorizontalRightPadding, 'revealHorizontalRightPadding', + 30, 0, 1000, + )), + roundedSelection: register(new EditorBooleanOption( + EditorOption.roundedSelection, 'roundedSelection', true, + { description: nls.localize('roundedSelection', "Controls whether selections should have rounded corners.") } + )), + rulers: register(new EditorRulers()), + scrollbar: register(new EditorScrollbar()), + scrollBeyondLastColumn: register(new EditorIntOption( + EditorOption.scrollBeyondLastColumn, 'scrollBeyondLastColumn', + 5, 0, Constants.MAX_SAFE_SMALL_INTEGER, + { description: nls.localize('scrollBeyondLastColumn', "Controls the number of extra characters beyond which the editor will scroll horizontally.") } + )), + scrollBeyondLastLine: register(new EditorBooleanOption( + EditorOption.scrollBeyondLastLine, 'scrollBeyondLastLine', true, + { description: nls.localize('scrollBeyondLastLine', "Controls whether the editor will scroll beyond the last line.") } + )), + selectionClipboard: register(new EditorBooleanOption( + EditorOption.selectionClipboard, 'selectionClipboard', true, + { + description: nls.localize('selectionClipboard', "Controls whether the Linux primary clipboard should be supported."), + included: platform.isLinux + } + )), + selectionHighlight: register(new EditorBooleanOption( + EditorOption.selectionHighlight, 'selectionHighlight', true, + { description: nls.localize('selectionHighlight', "Controls whether the editor should highlight matches similar to the selection.") } + )), + selectOnLineNumbers: register(new EditorBooleanOption( + EditorOption.selectOnLineNumbers, 'selectOnLineNumbers', true, + )), + showFoldingControls: register(new EditorStringEnumOption( + EditorOption.showFoldingControls, 'showFoldingControls', + 'mouseover' as 'always' | 'mouseover', + ['always', 'mouseover'] as const, + { description: nls.localize('showFoldingControls', "Controls whether the fold controls on the gutter are automatically hidden.") } + )), + showUnused: register(new EditorBooleanOption( + EditorOption.showUnused, 'showUnused', true, + { description: nls.localize('showUnused', "Controls fading out of unused code.") } + )), + snippetSuggestions: register(new EditorStringEnumOption( + EditorOption.snippetSuggestions, 'snippetSuggestions', + 'inline' as 'top' | 'bottom' | 'inline' | 'none', + ['top', 'bottom', 'inline', 'none'] as const, + { + enumDescriptions: [ + nls.localize('snippetSuggestions.top', "Show snippet suggestions on top of other suggestions."), + nls.localize('snippetSuggestions.bottom', "Show snippet suggestions below other suggestions."), + nls.localize('snippetSuggestions.inline', "Show snippets suggestions with other suggestions."), + nls.localize('snippetSuggestions.none', "Do not show snippet suggestions."), + ], + description: nls.localize('snippetSuggestions', "Controls whether snippets are shown with other suggestions and how they are sorted.") + } + )), + smoothScrolling: register(new EditorBooleanOption( + EditorOption.smoothScrolling, 'smoothScrolling', false, + { description: nls.localize('smoothScrolling', "Controls whether the editor will scroll using an animation.") } + )), + stopRenderingLineAfter: register(new EditorIntOption( + EditorOption.stopRenderingLineAfter, 'stopRenderingLineAfter', + 10000, -1, Constants.MAX_SAFE_SMALL_INTEGER, + )), + suggest: register(new EditorSuggest()), + suggestFontSize: register(new EditorIntOption( + EditorOption.suggestFontSize, 'suggestFontSize', + 0, 0, 1000, + { markdownDescription: nls.localize('suggestFontSize', "Font size for the suggest widget. When set to `0`, the value of `#editor.fontSize#` is used.") } + )), + suggestLineHeight: register(new EditorIntOption( + EditorOption.suggestLineHeight, 'suggestLineHeight', + 0, 0, 1000, + { markdownDescription: nls.localize('suggestLineHeight', "Line height for the suggest widget. When set to `0`, the value of `#editor.lineHeight#` is used.") } + )), + suggestOnTriggerCharacters: register(new EditorBooleanOption( + EditorOption.suggestOnTriggerCharacters, 'suggestOnTriggerCharacters', true, + { description: nls.localize('suggestOnTriggerCharacters', "Controls whether suggestions should automatically show up when typing trigger characters.") } + )), + suggestSelection: register(new EditorStringEnumOption( + EditorOption.suggestSelection, 'suggestSelection', + 'recentlyUsed' as 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix', + ['first', 'recentlyUsed', 'recentlyUsedByPrefix'] as const, + { + markdownEnumDescriptions: [ + nls.localize('suggestSelection.first', "Always select the first suggestion."), + nls.localize('suggestSelection.recentlyUsed', "Select recent suggestions unless further typing selects one, e.g. `console.| -> console.log` because `log` has been completed recently."), + nls.localize('suggestSelection.recentlyUsedByPrefix', "Select suggestions based on previous prefixes that have completed those suggestions, e.g. `co -> console` and `con -> const`."), + ], + description: nls.localize('suggestSelection', "Controls how suggestions are pre-selected when showing the suggest list.") + } + )), + tabCompletion: register(new EditorStringEnumOption( + EditorOption.tabCompletion, 'tabCompletion', + 'off' as 'on' | 'off' | 'onlySnippets', + ['on', 'off', 'onlySnippets'] as const, + { + enumDescriptions: [ + nls.localize('tabCompletion.on', "Tab complete will insert the best matching suggestion when pressing tab."), + nls.localize('tabCompletion.off', "Disable tab completions."), + nls.localize('tabCompletion.onlySnippets', "Tab complete snippets when their prefix match. Works best when 'quickSuggestions' aren't enabled."), + ], + description: nls.localize('tabCompletion', "Enables tab completions.") + } + )), + useTabStops: register(new EditorBooleanOption( + EditorOption.useTabStops, 'useTabStops', true, + { description: nls.localize('useTabStops', "Inserting and deleting whitespace follows tab stops.") } + )), + wordSeparators: register(new EditorStringOption( + EditorOption.wordSeparators, 'wordSeparators', USUAL_WORD_SEPARATORS, + { description: nls.localize('wordSeparators', "Characters that will be used as word separators when doing word related navigations or operations.") } + )), + wordWrap: register(new EditorStringEnumOption( + EditorOption.wordWrap, 'wordWrap', + 'off' as 'off' | 'on' | 'wordWrapColumn' | 'bounded', + ['off', 'on', 'wordWrapColumn', 'bounded'] as const, + { + markdownEnumDescriptions: [ + nls.localize('wordWrap.off', "Lines will never wrap."), + nls.localize('wordWrap.on', "Lines will wrap at the viewport width."), + nls.localize({ + key: 'wordWrap.wordWrapColumn', + comment: [ + '- `editor.wordWrapColumn` refers to a different setting and should not be localized.' + ] + }, "Lines will wrap at `#editor.wordWrapColumn#`."), + nls.localize({ + key: 'wordWrap.bounded', + comment: [ + '- viewport means the edge of the visible window size.', + '- `editor.wordWrapColumn` refers to a different setting and should not be localized.' + ] + }, "Lines will wrap at the minimum of viewport and `#editor.wordWrapColumn#`."), + ], + description: nls.localize({ + key: 'wordWrap', + comment: [ + '- \'off\', \'on\', \'wordWrapColumn\' and \'bounded\' refer to values the setting can take and should not be localized.', + '- `editor.wordWrapColumn` refers to a different setting and should not be localized.' + ] + }, "Controls how lines should wrap.") + } + )), + wordWrapBreakAfterCharacters: register(new EditorStringOption( + EditorOption.wordWrapBreakAfterCharacters, 'wordWrapBreakAfterCharacters', + ' \t})]?|/&,;¢°′″‰℃、。。、¢,.:;?!%・・ゝゞヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻ァィゥェォャュョッー”〉》」』】〕)]}」', + )), + wordWrapBreakBeforeCharacters: register(new EditorStringOption( + EditorOption.wordWrapBreakBeforeCharacters, 'wordWrapBreakBeforeCharacters', + '([{‘“〈《「『【〔([{「£¥$£¥++' + )), + wordWrapBreakObtrusiveCharacters: register(new EditorStringOption( + EditorOption.wordWrapBreakObtrusiveCharacters, 'wordWrapBreakObtrusiveCharacters', + '.' + )), + wordWrapColumn: register(new EditorIntOption( + EditorOption.wordWrapColumn, 'wordWrapColumn', + 80, 1, Constants.MAX_SAFE_SMALL_INTEGER, + { + markdownDescription: nls.localize({ + key: 'wordWrapColumn', + comment: [ + '- `editor.wordWrap` refers to a different setting and should not be localized.', + '- \'wordWrapColumn\' and \'bounded\' refer to values the different setting can take and should not be localized.' + ] + }, "Controls the wrapping column of the editor when `#editor.wordWrap#` is `wordWrapColumn` or `bounded`.") + } + )), + wordWrapMinified: register(new EditorBooleanOption( + EditorOption.wordWrapMinified, 'wordWrapMinified', true, + )), + wrappingIndent: register(new EditorEnumOption( + EditorOption.wrappingIndent, 'wrappingIndent', + WrappingIndent.Same, 'same', + ['none', 'same', 'indent', 'deepIndent'], + _wrappingIndentFromString, + { + enumDescriptions: [ + nls.localize('wrappingIndent.none', "No indentation. Wrapped lines begin at column 1."), + nls.localize('wrappingIndent.same', "Wrapped lines get the same indentation as the parent."), + nls.localize('wrappingIndent.indent', "Wrapped lines get +1 indentation toward the parent."), + nls.localize('wrappingIndent.deepIndent', "Wrapped lines get +2 indentation toward the parent."), + ], + description: nls.localize('wrappingIndent', "Controls the indentation of wrapped lines."), + } + )), + + // Leave these at the end (because they have dependencies!) + editorClassName: register(new EditorClassName()), + pixelRatio: register(new EditorPixelRatio()), + tabFocusMode: register(new EditorTabFocusMode()), + layoutInfo: register(new EditorLayoutInfoComputer()), + wrappingInfo: register(new EditorWrappingInfoComputer()), }; + +/** + * @internal + */ +type EditorOptionsType = typeof EditorOptions; +/** + * @internal + */ +type FindEditorOptionsKeyById = { [K in keyof EditorOptionsType]: EditorOptionsType[K]['id'] extends T ? K : never }[keyof EditorOptionsType]; +/** + * @internal + */ +type ComputedEditorOptionValue> = T extends IEditorOption ? R : never; +/** + * @internal + */ +export type FindComputedEditorOptionValueById = NonNullable]>>; diff --git a/src/vs/editor/common/config/fontInfo.ts b/src/vs/editor/common/config/fontInfo.ts index c69ea3f3320..6aa495b1d82 100644 --- a/src/vs/editor/common/config/fontInfo.ts +++ b/src/vs/editor/common/config/fontInfo.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as platform from 'vs/base/common/platform'; -import { EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; +import { EditorOptions, ValidatedEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { EditorZoom } from 'vs/editor/common/config/editorZoom'; /** @@ -14,59 +14,9 @@ import { EditorZoom } from 'vs/editor/common/config/editorZoom'; const GOLDEN_LINE_HEIGHT_RATIO = platform.isMacintosh ? 1.5 : 1.35; /** - * Font settings maximum and minimum limits + * @internal */ -const MINIMUM_FONT_SIZE = 8; -const MAXIMUM_FONT_SIZE = 100; const MINIMUM_LINE_HEIGHT = 8; -const MAXIMUM_LINE_HEIGHT = 150; -const MINIMUM_LETTER_SPACING = -5; -const MAXIMUM_LETTER_SPACING = 20; - -function safeParseFloat(n: number | string | undefined, defaultValue: number): number { - if (typeof n === 'number') { - return n; - } - if (typeof n === 'undefined') { - return defaultValue; - } - let r = parseFloat(n); - if (isNaN(r)) { - return defaultValue; - } - return r; -} - -function safeParseInt(n: number | string | undefined, defaultValue: number): number { - if (typeof n === 'number') { - return Math.round(n); - } - if (typeof n === 'undefined') { - return defaultValue; - } - let r = parseInt(n); - if (isNaN(r)) { - return defaultValue; - } - return r; -} - -function clamp(n: number, min: number, max: number): number { - if (n < min) { - return min; - } - if (n > max) { - return max; - } - return n; -} - -function _string(value: any, defaultValue: string): string { - if (typeof value !== 'string') { - return defaultValue; - } - return value; -} export class BareFontInfo { readonly _bareFontInfoBrand: void; @@ -74,38 +24,38 @@ export class BareFontInfo { /** * @internal */ - public static createFromRawSettings(opts: { - fontFamily?: string; - fontWeight?: string; - fontSize?: number | string; - lineHeight?: number | string; - letterSpacing?: number | string; - }, zoomLevel: number, ignoreEditorZoom: boolean = false): BareFontInfo { + public static createFromValidatedSettings(options: ValidatedEditorOptions, zoomLevel: number, ignoreEditorZoom: boolean): BareFontInfo { + const fontFamily = options.get(EditorOption.fontFamily); + const fontWeight = options.get(EditorOption.fontWeight); + const fontSize = options.get(EditorOption.fontSize); + const lineHeight = options.get(EditorOption.lineHeight); + const letterSpacing = options.get(EditorOption.letterSpacing); + return BareFontInfo._create(fontFamily, fontWeight, fontSize, lineHeight, letterSpacing, zoomLevel, ignoreEditorZoom); + } - let fontFamily = _string(opts.fontFamily, EDITOR_FONT_DEFAULTS.fontFamily); - let fontWeight = _string(opts.fontWeight, EDITOR_FONT_DEFAULTS.fontWeight); + /** + * @internal + */ + public static createFromRawSettings(opts: { fontFamily?: string; fontWeight?: string; fontSize?: number; lineHeight?: number; letterSpacing?: number; }, zoomLevel: number, ignoreEditorZoom: boolean = false): BareFontInfo { + const fontFamily = EditorOptions.fontFamily.validate(opts.fontFamily); + const fontWeight = EditorOptions.fontWeight.validate(opts.fontWeight); + const fontSize = EditorOptions.fontSize.validate(opts.fontSize); + const lineHeight = EditorOptions.lineHeight.validate(opts.lineHeight); + const letterSpacing = EditorOptions.letterSpacing.validate(opts.letterSpacing); + return BareFontInfo._create(fontFamily, fontWeight, fontSize, lineHeight, letterSpacing, zoomLevel, ignoreEditorZoom); + } - - let fontSize = safeParseFloat(opts.fontSize, EDITOR_FONT_DEFAULTS.fontSize); - fontSize = clamp(fontSize, 0, MAXIMUM_FONT_SIZE); - if (fontSize === 0) { - fontSize = EDITOR_FONT_DEFAULTS.fontSize; - } else if (fontSize < MINIMUM_FONT_SIZE) { - fontSize = MINIMUM_FONT_SIZE; - } - - let lineHeight = safeParseInt(opts.lineHeight, 0); - lineHeight = clamp(lineHeight, 0, MAXIMUM_LINE_HEIGHT); + /** + * @internal + */ + private static _create(fontFamily: string, fontWeight: string, fontSize: number, lineHeight: number, letterSpacing: number, zoomLevel: number, ignoreEditorZoom: boolean): BareFontInfo { if (lineHeight === 0) { lineHeight = Math.round(GOLDEN_LINE_HEIGHT_RATIO * fontSize); } else if (lineHeight < MINIMUM_LINE_HEIGHT) { lineHeight = MINIMUM_LINE_HEIGHT; } - let letterSpacing = safeParseFloat(opts.letterSpacing, 0); - letterSpacing = clamp(letterSpacing, MINIMUM_LETTER_SPACING, MAXIMUM_LETTER_SPACING); - - let editorZoomLevelMultiplier = 1 + (ignoreEditorZoom ? 0 : EditorZoom.getZoomLevel() * 0.1); + const editorZoomLevelMultiplier = 1 + (ignoreEditorZoom ? 0 : EditorZoom.getZoomLevel() * 0.1); fontSize *= editorZoomLevelMultiplier; lineHeight *= editorZoomLevelMultiplier; diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index a49d3635759..79bd220af75 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -20,6 +20,7 @@ import { RawContentChangedType } from 'vs/editor/common/model/textModelEvents'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; import { dispose } from 'vs/base/common/lifecycle'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; function containsLineMappingChanged(events: viewEvents.ViewEvent[]): boolean { for (let i = 0, len = events.length; i < len; i++) { @@ -399,7 +400,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { return this._columnSelectData; } const primaryCursor = this._cursors.getPrimaryCursor(); - const primaryPos = primaryCursor.viewState.position; + const primaryPos = primaryCursor.viewState.selectionStart.getStartPosition(); const viewLineNumber = primaryPos.lineNumber; const viewVisualColumn = CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, primaryPos); return { @@ -673,7 +674,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._isDoingComposition = false; } - if (this._configuration.editor.readOnly) { + if (this._configuration.options.get(EditorOption.readOnly)) { // All the remaining handlers will try to edit the model, // but we cannot edit when read only... this._onDidAttemptReadOnlyEdit.fire(undefined); diff --git a/src/vs/editor/common/controller/cursorCommon.ts b/src/vs/editor/common/controller/cursorCommon.ts index 8d95fadebcf..5b074c3c4f7 100644 --- a/src/vs/editor/common/controller/cursorCommon.ts +++ b/src/vs/editor/common/controller/cursorCommon.ts @@ -6,7 +6,7 @@ import { CharCode } from 'vs/base/common/charCode'; import { onUnexpectedError } from 'vs/base/common/errors'; import * as strings from 'vs/base/common/strings'; -import { EditorAutoClosingStrategy, EditorAutoSurroundStrategy, IConfigurationChangedEvent, EditorAutoClosingOvertypeStrategy } from 'vs/editor/common/config/editorOptions'; +import { EditorAutoClosingStrategy, EditorAutoSurroundStrategy, ConfigurationChangedEvent, EditorAutoClosingOvertypeStrategy, EditorOption } from 'vs/editor/common/config/editorOptions'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; @@ -97,6 +97,7 @@ export class CursorConfiguration { public readonly emptySelectionClipboard: boolean; public readonly copyWithSyntaxHighlighting: boolean; public readonly multiCursorMergeOverlapping: boolean; + public readonly multiCursorPaste: 'spread' | 'full'; public readonly autoClosingBrackets: EditorAutoClosingStrategy; public readonly autoClosingQuotes: EditorAutoClosingStrategy; public readonly autoClosingOvertype: EditorAutoClosingOvertypeStrategy; @@ -110,19 +111,20 @@ export class CursorConfiguration { private readonly _languageIdentifier: LanguageIdentifier; private _electricChars: { [key: string]: boolean; } | null; - public static shouldRecreate(e: IConfigurationChangedEvent): boolean { + public static shouldRecreate(e: ConfigurationChangedEvent): boolean { return ( - e.layoutInfo - || e.wordSeparators - || e.emptySelectionClipboard - || e.multiCursorMergeOverlapping - || e.autoClosingBrackets - || e.autoClosingQuotes - || e.autoClosingOvertype - || e.autoSurround - || e.useTabStops - || e.lineHeight - || e.readOnly + e.hasChanged(EditorOption.layoutInfo) + || e.hasChanged(EditorOption.wordSeparators) + || e.hasChanged(EditorOption.emptySelectionClipboard) + || e.hasChanged(EditorOption.multiCursorMergeOverlapping) + || e.hasChanged(EditorOption.multiCursorPaste) + || e.hasChanged(EditorOption.autoClosingBrackets) + || e.hasChanged(EditorOption.autoClosingQuotes) + || e.hasChanged(EditorOption.autoClosingOvertype) + || e.hasChanged(EditorOption.autoSurround) + || e.hasChanged(EditorOption.useTabStops) + || e.hasChanged(EditorOption.lineHeight) + || e.hasChanged(EditorOption.readOnly) ); } @@ -133,24 +135,26 @@ export class CursorConfiguration { ) { this._languageIdentifier = languageIdentifier; - let c = configuration.editor; + const options = configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); - this.readOnly = c.readOnly; + this.readOnly = options.get(EditorOption.readOnly); this.tabSize = modelOptions.tabSize; this.indentSize = modelOptions.indentSize; this.insertSpaces = modelOptions.insertSpaces; - this.pageSize = Math.max(1, Math.floor(c.layoutInfo.height / c.fontInfo.lineHeight) - 2); - this.lineHeight = c.lineHeight; - this.useTabStops = c.useTabStops; - this.wordSeparators = c.wordSeparators; - this.emptySelectionClipboard = c.emptySelectionClipboard; - this.copyWithSyntaxHighlighting = c.copyWithSyntaxHighlighting; - this.multiCursorMergeOverlapping = c.multiCursorMergeOverlapping; - this.autoClosingBrackets = c.autoClosingBrackets; - this.autoClosingQuotes = c.autoClosingQuotes; - this.autoClosingOvertype = c.autoClosingOvertype; - this.autoSurround = c.autoSurround; - this.autoIndent = c.autoIndent; + this.lineHeight = options.get(EditorOption.lineHeight); + this.pageSize = Math.max(1, Math.floor(layoutInfo.height / this.lineHeight) - 2); + this.useTabStops = options.get(EditorOption.useTabStops); + this.wordSeparators = options.get(EditorOption.wordSeparators); + this.emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard); + this.copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting); + this.multiCursorMergeOverlapping = options.get(EditorOption.multiCursorMergeOverlapping); + this.multiCursorPaste = options.get(EditorOption.multiCursorPaste); + this.autoClosingBrackets = options.get(EditorOption.autoClosingBrackets); + this.autoClosingQuotes = options.get(EditorOption.autoClosingQuotes); + this.autoClosingOvertype = options.get(EditorOption.autoClosingOvertype); + this.autoSurround = options.get(EditorOption.autoSurround); + this.autoIndent = options.get(EditorOption.autoIndent); this.autoClosingPairsOpen2 = new Map(); this.autoClosingPairsClose2 = new Map(); diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts index bcf4d3ef83a..9fc69bc842e 100644 --- a/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -105,7 +105,7 @@ export class TypeOperations { }); } - private static _distributePasteToCursors(selections: Selection[], text: string, pasteOnNewLine: boolean, multicursorText: string[]): string[] | null { + private static _distributePasteToCursors(config: CursorConfiguration, selections: Selection[], text: string, pasteOnNewLine: boolean, multicursorText: string[]): string[] | null { if (pasteOnNewLine) { return null; } @@ -118,20 +118,27 @@ export class TypeOperations { return multicursorText; } - // Remove trailing \n if present - if (text.charCodeAt(text.length - 1) === CharCode.LineFeed) { - text = text.substr(0, text.length - 1); - } - let lines = text.split(/\r\n|\r|\n/); - if (lines.length === selections.length) { - return lines; + if (config.multiCursorPaste === 'spread') { + // Try to spread the pasted text in case the line count matches the cursor count + // Remove trailing \n if present + if (text.charCodeAt(text.length - 1) === CharCode.LineFeed) { + text = text.substr(0, text.length - 1); + } + // Remove trailing \r if present + if (text.charCodeAt(text.length - 1) === CharCode.CarriageReturn) { + text = text.substr(0, text.length - 1); + } + let lines = text.split(/\r\n|\r|\n/); + if (lines.length === selections.length) { + return lines; + } } return null; } public static paste(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[], text: string, pasteOnNewLine: boolean, multicursorText: string[]): EditOperationResult { - const distributedPaste = this._distributePasteToCursors(selections, text, pasteOnNewLine, multicursorText); + const distributedPaste = this._distributePasteToCursors(config, selections, text, pasteOnNewLine, multicursorText); if (distributedPaste) { selections = selections.sort(Range.compareRangesUsingStarts); diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index bde26ab9802..e11482fa25b 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -6,7 +6,7 @@ import { IMarkdownString } from 'vs/base/common/htmlContent'; import { IDisposable } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, IComputedEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; @@ -149,13 +149,13 @@ export interface ILineChange extends IChange { * @internal */ export interface IConfiguration extends IDisposable { - onDidChange(listener: (e: editorOptions.IConfigurationChangedEvent) => void): IDisposable; + onDidChange(listener: (e: ConfigurationChangedEvent) => void): IDisposable; - readonly editor: editorOptions.InternalEditorOptions; + readonly options: IComputedEditorOptions; setMaxLineNumber(maxLineNumber: number): void; - updateOptions(newOptions: editorOptions.IEditorOptions): void; - getRawOptions(): editorOptions.IEditorOptions; + updateOptions(newOptions: IEditorOptions): void; + getRawOptions(): IEditorOptions; observeReferenceElement(dimension?: IDimension): void; setIsDominatedByLongLines(isDominatedByLongLines: boolean): void; } @@ -263,7 +263,7 @@ export interface IEditor { /** * Update the editor's options after the editor has been created. */ - updateOptions(newOptions: editorOptions.IEditorOptions): void; + updateOptions(newOptions: IEditorOptions): void; /** * Indicates that the editor becomes visible. diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index 0469471f8c4..f9a90e5f387 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -2621,8 +2621,8 @@ class DecorationOptions implements model.IDecorationOptions { readonly darkColor: string | ThemeColor; constructor(options: model.IDecorationOptions) { - this.color = options.color || strings.empty; - this.darkColor = options.darkColor || strings.empty; + this.color = options.color || ''; + this.darkColor = options.darkColor || ''; } } @@ -2658,7 +2658,7 @@ export class ModelDecorationOverviewRulerOptions extends DecorationOptions { } let c = color ? theme.getColor(color.id) : null; if (!c) { - return strings.empty; + return ''; } return c.toString(); } diff --git a/src/vs/editor/common/services/editorWorkerServiceImpl.ts b/src/vs/editor/common/services/editorWorkerServiceImpl.ts index 34001e40608..9267a035826 100644 --- a/src/vs/editor/common/services/editorWorkerServiceImpl.ts +++ b/src/vs/editor/common/services/editorWorkerServiceImpl.ts @@ -8,7 +8,6 @@ import { Disposable, IDisposable, dispose, toDisposable, DisposableStore } from import { URI } from 'vs/base/common/uri'; import { SimpleWorkerClient, logOnceWebWorkerWarning, IWorkerClient } from 'vs/base/common/worker/simpleWorker'; import { DefaultWorkerFactory } from 'vs/base/worker/defaultWorkerFactory'; -import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; @@ -146,7 +145,7 @@ class WordBasedCompletionItemProvider implements modes.CompletionItemProvider { } provideCompletionItems(model: ITextModel, position: Position): Promise | undefined { - const { wordBasedSuggestions } = this._configurationService.getValue(model.uri, position, 'editor'); + const { wordBasedSuggestions } = this._configurationService.getValue<{ wordBasedSuggestions?: boolean }>(model.uri, position, 'editor'); if (!wordBasedSuggestions) { return undefined; } diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index a705c132478..8ef13878743 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -332,34 +332,13 @@ export enum CursorChangeReason { Redo = 6 } -export enum RenderMinimap { - None = 0, - Small = 1, - Large = 2, - SmallBlocks = 3, - LargeBlocks = 4 -} - -/** - * Describes how to indent wrapped lines. - */ -export enum WrappingIndent { +export enum AccessibilitySupport { /** - * No indentation => wrapped lines begin at column 1. + * This should be the browser case where it is not known if a screen reader is attached or no. */ - None = 0, - /** - * Same => wrapped lines get the same indentation as the parent. - */ - Same = 1, - /** - * Indent => wrapped lines get +1 indentation toward the parent. - */ - Indent = 2, - /** - * DeepIndent => wrapped lines get +2 indentation toward the parent. - */ - DeepIndent = 3 + Unknown = 0, + Disabled = 1, + Enabled = 2 } /** @@ -422,6 +401,14 @@ export enum TextEditorCursorStyle { UnderlineThin = 6 } +export enum RenderMinimap { + None = 0, + Small = 1, + Large = 2, + SmallBlocks = 3, + LargeBlocks = 4 +} + export enum RenderLineNumbersType { Off = 0, On = 1, @@ -430,6 +417,28 @@ export enum RenderLineNumbersType { Custom = 4 } +/** + * Describes how to indent wrapped lines. + */ +export enum WrappingIndent { + /** + * No indentation => wrapped lines begin at column 1. + */ + None = 0, + /** + * Same => wrapped lines get the same indentation as the parent. + */ + Same = 1, + /** + * Indent => wrapped lines get +1 indentation toward the parent. + */ + Indent = 2, + /** + * DeepIndent => wrapped lines get +2 indentation toward the parent. + */ + DeepIndent = 3 +} + /** * A positioning preference for rendering content widgets. */ diff --git a/src/vs/editor/common/view/viewEvents.ts b/src/vs/editor/common/view/viewEvents.ts index 67258c117e0..55c455808ad 100644 --- a/src/vs/editor/common/view/viewEvents.ts +++ b/src/vs/editor/common/view/viewEvents.ts @@ -6,7 +6,7 @@ import * as errors from 'vs/base/common/errors'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ScrollEvent } from 'vs/base/common/scrollable'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { ScrollType } from 'vs/editor/common/editorCommon'; @@ -34,32 +34,14 @@ export class ViewConfigurationChangedEvent { public readonly type = ViewEventType.ViewConfigurationChanged; - public readonly canUseLayerHinting: boolean; - public readonly pixelRatio: boolean; - public readonly editorClassName: boolean; - public readonly lineHeight: boolean; - public readonly readOnly: boolean; - public readonly accessibilitySupport: boolean; - public readonly emptySelectionClipboard: boolean; - public readonly copyWithSyntaxHighlighting: boolean; - public readonly layoutInfo: boolean; - public readonly fontInfo: boolean; - public readonly viewInfo: boolean; - public readonly wrappingInfo: boolean; + public readonly _source: ConfigurationChangedEvent; - constructor(source: IConfigurationChangedEvent) { - this.canUseLayerHinting = source.canUseLayerHinting; - this.pixelRatio = source.pixelRatio; - this.editorClassName = source.editorClassName; - this.lineHeight = source.lineHeight; - this.readOnly = source.readOnly; - this.accessibilitySupport = source.accessibilitySupport; - this.emptySelectionClipboard = source.emptySelectionClipboard; - this.copyWithSyntaxHighlighting = source.copyWithSyntaxHighlighting; - this.layoutInfo = source.layoutInfo; - this.fontInfo = source.fontInfo; - this.viewInfo = source.viewInfo; - this.wrappingInfo = source.wrappingInfo; + constructor(source: ConfigurationChangedEvent) { + this._source = source; + } + + public hasChanged(id: EditorOption): boolean { + return this._source.hasChanged(id); } } diff --git a/src/vs/editor/common/viewLayout/viewLayout.ts b/src/vs/editor/common/viewLayout/viewLayout.ts index ad24479b4b2..c06d7220a42 100644 --- a/src/vs/editor/common/viewLayout/viewLayout.ts +++ b/src/vs/editor/common/viewLayout/viewLayout.ts @@ -6,7 +6,7 @@ import { Event } from 'vs/base/common/event'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { IScrollDimensions, IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { LinesLayout } from 'vs/editor/common/viewLayout/linesLayout'; import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; @@ -27,14 +27,17 @@ export class ViewLayout extends Disposable implements IViewLayout { super(); this._configuration = configuration; - this._linesLayout = new LinesLayout(lineCount, this._configuration.editor.lineHeight); + const options = this._configuration.options; + const layoutInfo = options.get(EditorOption.layoutInfo); + + this._linesLayout = new LinesLayout(lineCount, options.get(EditorOption.lineHeight)); this.scrollable = this._register(new Scrollable(0, scheduleAtNextAnimationFrame)); this._configureSmoothScrollDuration(); this.scrollable.setScrollDimensions({ - width: configuration.editor.layoutInfo.contentWidth, - height: configuration.editor.layoutInfo.contentHeight + width: layoutInfo.contentWidth, + height: layoutInfo.contentHeight }); this.onDidScroll = this.scrollable.onScroll; @@ -50,22 +53,24 @@ export class ViewLayout extends Disposable implements IViewLayout { } private _configureSmoothScrollDuration(): void { - this.scrollable.setSmoothScrollDuration(this._configuration.editor.viewInfo.smoothScrolling ? SMOOTH_SCROLLING_TIME : 0); + this.scrollable.setSmoothScrollDuration(this._configuration.options.get(EditorOption.smoothScrolling) ? SMOOTH_SCROLLING_TIME : 0); } // ---- begin view event handlers - public onConfigurationChanged(e: IConfigurationChangedEvent): void { - if (e.lineHeight) { - this._linesLayout.setLineHeight(this._configuration.editor.lineHeight); + public onConfigurationChanged(e: ConfigurationChangedEvent): void { + const options = this._configuration.options; + if (e.hasChanged(EditorOption.lineHeight)) { + this._linesLayout.setLineHeight(options.get(EditorOption.lineHeight)); } - if (e.layoutInfo) { + if (e.hasChanged(EditorOption.layoutInfo)) { + const layoutInfo = options.get(EditorOption.layoutInfo); this.scrollable.setScrollDimensions({ - width: this._configuration.editor.layoutInfo.contentWidth, - height: this._configuration.editor.layoutInfo.contentHeight + width: layoutInfo.contentWidth, + height: layoutInfo.contentHeight }); } - if (e.viewInfo) { + if (e.hasChanged(EditorOption.smoothScrolling)) { this._configureSmoothScrollDuration(); } this._updateHeight(); @@ -83,7 +88,9 @@ export class ViewLayout extends Disposable implements IViewLayout { // ---- end view event handlers private _getHorizontalScrollbarHeight(scrollDimensions: IScrollDimensions): number { - if (this._configuration.editor.viewInfo.scrollbar.horizontal === ScrollbarVisibility.Hidden) { + const options = this._configuration.options; + const scrollbar = options.get(EditorOption.scrollbar); + if (scrollbar.horizontal === ScrollbarVisibility.Hidden) { // horizontal scrollbar not visible return 0; } @@ -91,15 +98,16 @@ export class ViewLayout extends Disposable implements IViewLayout { // horizontal scrollbar not visible return 0; } - return this._configuration.editor.viewInfo.scrollbar.horizontalScrollbarSize; + return scrollbar.horizontalScrollbarSize; } private _getTotalHeight(): number { + const options = this._configuration.options; const scrollDimensions = this.scrollable.getScrollDimensions(); let result = this._linesLayout.getLinesTotalHeight(); - if (this._configuration.editor.viewInfo.scrollBeyondLastLine) { - result += scrollDimensions.height - this._configuration.editor.lineHeight; + if (options.get(EditorOption.scrollBeyondLastLine)) { + result += scrollDimensions.height - options.get(EditorOption.lineHeight); } else { result += this._getHorizontalScrollbarHeight(scrollDimensions); } @@ -138,9 +146,11 @@ export class ViewLayout extends Disposable implements IViewLayout { } private _computeScrollWidth(maxLineWidth: number, viewportWidth: number): number { - let isViewportWrapping = this._configuration.editor.wrappingInfo.isViewportWrapping; + const options = this._configuration.options; + const wrappingInfo = options.get(EditorOption.wrappingInfo); + let isViewportWrapping = wrappingInfo.isViewportWrapping; if (!isViewportWrapping) { - const extraHorizontalSpace = this._configuration.editor.viewInfo.scrollBeyondLastColumn * this._configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; + const extraHorizontalSpace = options.get(EditorOption.scrollBeyondLastColumn) * options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; const whitespaceMinWidth = this._linesLayout.getWhitespaceMinWidth(); return Math.max(maxLineWidth + extraHorizontalSpace, viewportWidth, whitespaceMinWidth); } diff --git a/src/vs/editor/common/viewModel/viewModelDecorations.ts b/src/vs/editor/common/viewModel/viewModelDecorations.ts index 07df48c622e..b74baa8dd1c 100644 --- a/src/vs/editor/common/viewModel/viewModelDecorations.ts +++ b/src/vs/editor/common/viewModel/viewModelDecorations.ts @@ -10,6 +10,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { IModelDecoration, ITextModel } from 'vs/editor/common/model'; import { IViewModelLinesCollection } from 'vs/editor/common/viewModel/splitLinesCollection'; import { ICoordinatesConverter, InlineDecoration, InlineDecorationType, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface IDecorationsViewportData { /** @@ -103,7 +104,7 @@ export class ViewModelDecorations implements IDisposable { } private _getDecorationsViewportData(viewportRange: Range): IDecorationsViewportData { - const modelDecorations = this._linesCollection.getDecorationsInRange(viewportRange, this.editorId, this.configuration.editor.readOnly); + const modelDecorations = this._linesCollection.getDecorationsInRange(viewportRange, this.editorId, this.configuration.options.get(EditorOption.readOnly)); const startLineNumber = viewportRange.startLineNumber; const endLineNumber = viewportRange.endLineNumber; diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index 65284147a64..01e9f36723c 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -6,7 +6,7 @@ import { Color } from 'vs/base/common/color'; import { IDisposable } from 'vs/base/common/lifecycle'; import * as strings from 'vs/base/common/strings'; -import { IConfigurationChangedEvent, EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EDITOR_FONT_DEFAULTS, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; @@ -59,21 +59,27 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel this.lines = new IdentityLinesCollection(this.model); } else { - const conf = this.configuration.editor; + const options = this.configuration.options; + const wrappingInfo = options.get(EditorOption.wrappingInfo); + const fontInfo = options.get(EditorOption.fontInfo); + const wordWrapBreakAfterCharacters = options.get(EditorOption.wordWrapBreakAfterCharacters); + const wordWrapBreakBeforeCharacters = options.get(EditorOption.wordWrapBreakBeforeCharacters); + const wordWrapBreakObtrusiveCharacters = options.get(EditorOption.wordWrapBreakObtrusiveCharacters); + const wrappingIndent = options.get(EditorOption.wrappingIndent); let hardWrappingLineMapperFactory = new CharacterHardWrappingLineMapperFactory( - conf.wrappingInfo.wordWrapBreakBeforeCharacters, - conf.wrappingInfo.wordWrapBreakAfterCharacters, - conf.wrappingInfo.wordWrapBreakObtrusiveCharacters + wordWrapBreakBeforeCharacters, + wordWrapBreakAfterCharacters, + wordWrapBreakObtrusiveCharacters ); this.lines = new SplitLinesCollection( this.model, hardWrappingLineMapperFactory, this.model.getOptions().tabSize, - conf.wrappingInfo.wrappingColumn, - conf.fontInfo.typicalFullwidthCharacterWidth / conf.fontInfo.typicalHalfwidthCharacterWidth, - conf.wrappingInfo.wrappingIndent + wrappingInfo.wrappingColumn, + fontInfo.typicalFullwidthCharacterWidth / fontInfo.typicalHalfwidthCharacterWidth, + wrappingIndent ); } @@ -136,7 +142,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel this.hasFocus = hasFocus; } - private _onConfigurationChanged(eventsCollector: viewEvents.ViewEventsCollector, e: IConfigurationChangedEvent): void { + private _onConfigurationChanged(eventsCollector: viewEvents.ViewEventsCollector, e: ConfigurationChangedEvent): void { // We might need to restore the current centered view range, so save it (if available) let previousViewportStartModelPosition: Position | null = null; @@ -146,9 +152,12 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel } let restorePreviousViewportStart = false; - const conf = this.configuration.editor; + const options = this.configuration.options; + const wrappingInfo = options.get(EditorOption.wrappingInfo); + const fontInfo = options.get(EditorOption.fontInfo); + const wrappingIndent = options.get(EditorOption.wrappingIndent); - if (this.lines.setWrappingSettings(conf.wrappingInfo.wrappingIndent, conf.wrappingInfo.wrappingColumn, conf.fontInfo.typicalFullwidthCharacterWidth / conf.fontInfo.typicalHalfwidthCharacterWidth)) { + if (this.lines.setWrappingSettings(wrappingIndent, wrappingInfo.wrappingColumn, fontInfo.typicalFullwidthCharacterWidth / fontInfo.typicalHalfwidthCharacterWidth)) { eventsCollector.emit(new viewEvents.ViewFlushedEvent()); eventsCollector.emit(new viewEvents.ViewLineMappingChangedEvent()); eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent()); @@ -161,7 +170,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel } } - if (e.readOnly) { + if (e.hasChanged(EditorOption.readOnly)) { // Must read again all decorations due to readOnly filtering this.decorations.reset(); eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent()); @@ -552,7 +561,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel } public getAllOverviewRulerDecorations(theme: ITheme): IOverviewRulerDecorations { - return this.lines.getAllOverviewRulerDecorations(this.editorId, this.configuration.editor.readOnly, theme); + return this.lines.getAllOverviewRulerDecorations(this.editorId, this.configuration.options.get(EditorOption.readOnly), theme); } public invalidateOverviewRulerColorCache(): void { @@ -666,7 +675,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel range = new Range(lineNumber, this.model.getLineMinColumn(lineNumber), lineNumber, this.model.getLineMaxColumn(lineNumber)); } - const fontInfo = this.configuration.editor.fontInfo; + const fontInfo = this.configuration.options.get(EditorOption.fontInfo); const colorMap = this._getColorMap(); const fontFamily = fontInfo.fontFamily === EDITOR_FONT_DEFAULTS.fontFamily ? fontInfo.fontFamily : `'${fontInfo.fontFamily}', ${EDITOR_FONT_DEFAULTS.fontFamily}`; diff --git a/src/vs/editor/contrib/bracketMatching/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/bracketMatching.ts index 675fa71bd8c..44d7bb7613a 100644 --- a/src/vs/editor/contrib/bracketMatching/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/bracketMatching.ts @@ -22,6 +22,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { registerColor } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant, themeColorFromId } from 'vs/platform/theme/common/themeService'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const overviewRulerBracketMatchForeground = registerColor('editorOverviewRuler.bracketMatchForeground', { dark: '#A0A0A0', light: '#A0A0A0', hc: '#A0A0A0' }, nls.localize('overviewRulerBracketMatchForeground', 'Overview ruler marker color for matching brackets.')); @@ -104,7 +105,7 @@ export class BracketMatchingController extends Disposable implements editorCommo this._lastVersionId = 0; this._decorations = []; this._updateBracketsSoon = this._register(new RunOnceScheduler(() => this._updateBrackets(), 50)); - this._matchBrackets = this._editor.getConfiguration().contribInfo.matchBrackets; + this._matchBrackets = this._editor.getOption(EditorOption.matchBrackets); this._updateBracketsSoon.schedule(); this._register(editor.onDidChangeCursorPosition((e) => { @@ -130,7 +131,7 @@ export class BracketMatchingController extends Disposable implements editorCommo this._updateBracketsSoon.schedule(); })); this._register(editor.onDidChangeConfiguration((e) => { - this._matchBrackets = this._editor.getConfiguration().contribInfo.matchBrackets; + this._matchBrackets = this._editor.getOption(EditorOption.matchBrackets); if (!this._matchBrackets && this._decorations.length > 0) { // Remove existing decorations if bracket matching is off this._decorations = this._editor.deltaDecorations(this._decorations, []); @@ -332,4 +333,4 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { title: nls.localize({ key: 'miGoToBracket', comment: ['&& denotes a mnemonic'] }, "Go to &&Bracket") }, order: 2 -}); \ No newline at end of file +}); diff --git a/src/vs/editor/contrib/clipboard/clipboard.ts b/src/vs/editor/contrib/clipboard/clipboard.ts index c0929f47d00..df241dc8643 100644 --- a/src/vs/editor/contrib/clipboard/clipboard.ts +++ b/src/vs/editor/contrib/clipboard/clipboard.ts @@ -16,6 +16,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { MenuId } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const CLIPBOARD_CONTEXT_MENU_GROUP = '9_cutcopypaste'; @@ -94,7 +95,7 @@ class ExecCommandCutAction extends ExecCommandAction { return; } - const emptySelectionClipboard = editor.getConfiguration().emptySelectionClipboard; + const emptySelectionClipboard = editor.getOption(EditorOption.emptySelectionClipboard); if (!emptySelectionClipboard && editor.getSelection().isEmpty()) { return; @@ -143,7 +144,7 @@ class ExecCommandCopyAction extends ExecCommandAction { return; } - const emptySelectionClipboard = editor.getConfiguration().emptySelectionClipboard; + const emptySelectionClipboard = editor.getOption(EditorOption.emptySelectionClipboard); if (!emptySelectionClipboard && editor.getSelection().isEmpty()) { return; @@ -209,7 +210,7 @@ class ExecCommandCopyWithSyntaxHighlightingAction extends ExecCommandAction { return; } - const emptySelectionClipboard = editor.getConfiguration().emptySelectionClipboard; + const emptySelectionClipboard = editor.getOption(EditorOption.emptySelectionClipboard); if (!emptySelectionClipboard && editor.getSelection().isEmpty()) { return; diff --git a/src/vs/editor/contrib/codeAction/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/codeActionCommands.ts index 1b76fa157ee..72af0135934 100644 --- a/src/vs/editor/contrib/codeAction/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/codeActionCommands.ts @@ -3,30 +3,32 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { Disposable } from 'vs/base/common/lifecycle'; import { escapeRegExpCharacters } from 'vs/base/common/strings'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, EditorCommand, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; +import { IPosition } from 'vs/editor/common/core/position'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { CodeAction } from 'vs/editor/common/modes'; +import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction'; import { CodeActionUi } from 'vs/editor/contrib/codeAction/codeActionUi'; import { MessageController } from 'vs/editor/contrib/message/messageController'; import * as nls from 'vs/nls'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IMarkerService } from 'vs/platform/markers/common/markers'; +import { INotificationService } from 'vs/platform/notification/common/notification'; import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { CodeActionModel, CodeActionsState, SUPPORTED_CODE_ACTIONS } from './codeActionModel'; import { CodeActionAutoApply, CodeActionFilter, CodeActionKind, CodeActionTrigger } from './codeActionTrigger'; -import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction'; -import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; -import { IPosition } from 'vs/editor/common/core/position'; function contextKeyForSupportedActions(kind: CodeActionKind) { return ContextKeyExpr.regex( @@ -56,6 +58,7 @@ export class QuickFixController extends Disposable implements IEditorContributio @IKeybindingService keybindingService: IKeybindingService, @ICommandService private readonly _commandService: ICommandService, @IBulkEditService private readonly _bulkEditService: IBulkEditService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { super(); @@ -107,21 +110,42 @@ export class QuickFixController extends Disposable implements IEditorContributio } private _applyCodeAction(action: CodeAction): Promise { - return applyCodeAction(action, this._bulkEditService, this._commandService, this._editor); + return this._instantiationService.invokeFunction(applyCodeAction, action, this._bulkEditService, this._commandService, this._editor); } } export async function applyCodeAction( + accessor: ServicesAccessor, action: CodeAction, bulkEditService: IBulkEditService, commandService: ICommandService, editor?: ICodeEditor, ): Promise { + const notificationService = accessor.get(INotificationService); if (action.edit) { await bulkEditService.apply(action.edit, { editor }); } if (action.command) { - await commandService.executeCommand(action.command.id, ...(action.command.arguments || [])); + try { + await commandService.executeCommand(action.command.id, ...(action.command.arguments || [])); + } catch (err) { + const message = asMessage(err); + notificationService.error( + typeof message === 'string' + ? message + : nls.localize('applyCodeActionFailed', "An unknown error occurred while applying the code action")); + + } + } +} + +function asMessage(err: any): string | undefined { + if (typeof err === 'string') { + return err; + } else if (err instanceof Error && typeof err.message === 'string') { + return err.message; + } else { + return undefined; } } diff --git a/src/vs/editor/contrib/codeAction/codeActionModel.ts b/src/vs/editor/contrib/codeAction/codeActionModel.ts index d1b33028aee..2af98e865aa 100644 --- a/src/vs/editor/contrib/codeAction/codeActionModel.ts +++ b/src/vs/editor/contrib/codeAction/codeActionModel.ts @@ -17,6 +17,7 @@ import { IMarkerService } from 'vs/platform/markers/common/markers'; import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { getCodeActions, CodeActionSet } from './codeAction'; import { CodeActionTrigger } from './codeActionTrigger'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const SUPPORTED_CODE_ACTIONS = new RawContextKey('supportedCodeAction', ''); @@ -192,7 +193,7 @@ export class CodeActionModel extends Disposable { const model = this._editor.getModel(); if (model && CodeActionProviderRegistry.has(model) - && !this._editor.getConfiguration().readOnly + && !this._editor.getOption(EditorOption.readOnly) ) { const supportedActions: string[] = []; for (const provider of CodeActionProviderRegistry.all(model)) { diff --git a/src/vs/editor/contrib/codeAction/lightBulbWidget.ts b/src/vs/editor/contrib/codeAction/lightBulbWidget.ts index 8575f354d5c..d5d8dac4981 100644 --- a/src/vs/editor/contrib/codeAction/lightBulbWidget.ts +++ b/src/vs/editor/contrib/codeAction/lightBulbWidget.ts @@ -14,6 +14,7 @@ import { TextModel } from 'vs/editor/common/model/textModel'; import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction'; import * as nls from 'vs/nls'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; namespace LightBulbState { @@ -78,7 +79,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget { // a bit of extra work to make sure the menu // doesn't cover the line-text const { top, height } = dom.getDomNodePagePosition(this._domNode); - const { lineHeight } = this._editor.getConfiguration(); + const lineHeight = this._editor.getOption(EditorOption.lineHeight); let pad = Math.floor(lineHeight / 3); if (this._state.widgetPosition.position !== null && this._state.widgetPosition.position.lineNumber < this._state.editorPosition.lineNumber) { @@ -106,7 +107,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget { })); this._register(this._editor.onDidChangeConfiguration(e => { // hide when told to do so - if (e.contribInfo && !this._editor.getConfiguration().contribInfo.lightbulbEnabled) { + if (e.hasChanged(EditorOption.lightbulb) && !this._editor.getOption(EditorOption.lightbulb).enabled) { this.hide(); } })); @@ -137,8 +138,8 @@ export class LightBulbWidget extends Disposable implements IContentWidget { return this.hide(); } - const config = this._editor.getConfiguration(); - if (!config.contribInfo.lightbulbEnabled) { + const options = this._editor.getOptions(); + if (!options.get(EditorOption.lightbulb).enabled) { return this.hide(); } @@ -149,9 +150,10 @@ export class LightBulbWidget extends Disposable implements IContentWidget { } const tabSize = model.getOptions().tabSize; + const fontInfo = options.get(EditorOption.fontInfo); const lineContent = model.getLineContent(lineNumber); const indent = TextModel.computeIndentLevel(lineContent, tabSize); - const lineHasSpace = config.fontInfo.spaceWidth * indent > 22; + const lineHasSpace = fontInfo.spaceWidth * indent > 22; const isFolded = (lineNumber: number) => { return lineNumber > 2 && this._editor.getTopForLineNumber(lineNumber) === this._editor.getTopForLineNumber(lineNumber - 1); }; @@ -162,7 +164,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget { effectiveLineNumber -= 1; } else if (!isFolded(lineNumber + 1)) { effectiveLineNumber += 1; - } else if (column * config.fontInfo.spaceWidth < 22) { + } else if (column * fontInfo.spaceWidth < 22) { // cannot show lightbulb above/below and showing // it inline would overlay the cursor... return this.hide(); diff --git a/src/vs/editor/contrib/codelens/codelensController.ts b/src/vs/editor/contrib/codelens/codelensController.ts index 726133c3f7f..6e89d47039c 100644 --- a/src/vs/editor/contrib/codelens/codelensController.ts +++ b/src/vs/editor/contrib/codelens/codelensController.ts @@ -17,6 +17,7 @@ import { CodeLensWidget, CodeLensHelper } from 'vs/editor/contrib/codelens/codel import { ICommandService } from 'vs/platform/commands/common/commands'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ICodeLensCache } from 'vs/editor/contrib/codelens/codeLensCache'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class CodeLensContribution implements editorCommon.IEditorContribution { @@ -40,13 +41,13 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { @INotificationService private readonly _notificationService: INotificationService, @ICodeLensCache private readonly _codeLensCache: ICodeLensCache ) { - this._isEnabled = this._editor.getConfiguration().contribInfo.codeLens; + this._isEnabled = this._editor.getOption(EditorOption.codeLens); this._globalToDispose.add(this._editor.onDidChangeModel(() => this._onModelChange())); this._globalToDispose.add(this._editor.onDidChangeModelLanguage(() => this._onModelChange())); this._globalToDispose.add(this._editor.onDidChangeConfiguration(() => { const prevIsEnabled = this._isEnabled; - this._isEnabled = this._editor.getConfiguration().contribInfo.codeLens; + this._isEnabled = this._editor.getOption(EditorOption.codeLens); if (prevIsEnabled !== this._isEnabled) { this._onModelChange(); } @@ -204,7 +205,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { } })); this._localToDispose.add(this._editor.onDidChangeConfiguration(e => { - if (e.fontInfo) { + if (e.hasChanged(EditorOption.fontInfo)) { for (const lens of this._lenses) { lens.updateHeight(); } diff --git a/src/vs/editor/contrib/codelens/codelensWidget.ts b/src/vs/editor/contrib/codelens/codelensWidget.ts index 5ae20b27edb..42cf0deb06e 100644 --- a/src/vs/editor/contrib/codelens/codelensWidget.ts +++ b/src/vs/editor/contrib/codelens/codelensWidget.ts @@ -16,6 +16,7 @@ import { editorCodeLensForeground } from 'vs/editor/common/view/editorColorRegis import { CodeLensItem } from 'vs/editor/contrib/codelens/codelens'; import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; class CodeLensViewZone implements editorBrowser.IViewZone { @@ -80,7 +81,9 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { } updateHeight(): void { - const { fontInfo, lineHeight } = this._editor.getConfiguration(); + const options = this._editor.getOptions(); + const fontInfo = options.get(EditorOption.fontInfo); + const lineHeight = options.get(EditorOption.lineHeight); this._domNode.style.height = `${Math.round(lineHeight * 1.1)}px`; this._domNode.style.lineHeight = `${lineHeight}px`; this._domNode.style.fontSize = `${Math.round(fontInfo.fontSize * 0.9)}px`; diff --git a/src/vs/editor/contrib/colorPicker/colorDetector.ts b/src/vs/editor/contrib/colorPicker/colorDetector.ts index 0ccf498c009..c1460b7650d 100644 --- a/src/vs/editor/contrib/colorPicker/colorDetector.ts +++ b/src/vs/editor/contrib/colorPicker/colorDetector.ts @@ -19,6 +19,7 @@ import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { ColorProviderRegistry } from 'vs/editor/common/modes'; import { IColorData, getColors } from 'vs/editor/contrib/colorPicker/color'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const MAX_DECORATORS = 500; @@ -84,7 +85,7 @@ export class ColorDetector extends Disposable implements IEditorContribution { } } - return this._editor.getConfiguration().contribInfo.colorDecorators; + return this._editor.getOption(EditorOption.colorDecorators); } getId(): string { diff --git a/src/vs/editor/contrib/contextmenu/contextmenu.ts b/src/vs/editor/contrib/contextmenu/contextmenu.ts index 2209b38da7f..e88f633d4ca 100644 --- a/src/vs/editor/contrib/contextmenu/contextmenu.ts +++ b/src/vs/editor/contrib/contextmenu/contextmenu.ts @@ -22,6 +22,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ITextModel } from 'vs/editor/common/model'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class ContextMenuController implements IEditorContribution { @@ -66,7 +67,7 @@ export class ContextMenuController implements IEditorContribution { return; } - if (!this._editor.getConfiguration().contribInfo.contextmenu) { + if (!this._editor.getOption(EditorOption.contextmenu)) { this._editor.focus(); // Ensure the cursor is at the position of the mouse click if (e.target.position && !this._editor.getSelection().containsPosition(e.target.position)) { @@ -104,7 +105,7 @@ export class ContextMenuController implements IEditorContribution { } public showContextMenu(anchor?: IAnchor | null): void { - if (!this._editor.getConfiguration().contribInfo.contextmenu) { + if (!this._editor.getOption(EditorOption.contextmenu)) { return; // Context menu is turned off through configuration } if (!this._editor.hasModel()) { @@ -147,7 +148,7 @@ export class ContextMenuController implements IEditorContribution { } // Disable hover - const oldHoverSetting = this._editor.getConfiguration().contribInfo.hover; + const oldHoverSetting = this._editor.getOption(EditorOption.hover); this._editor.updateOptions({ hover: { enabled: false diff --git a/src/vs/editor/contrib/dnd/dnd.ts b/src/vs/editor/contrib/dnd/dnd.ts index 70b3551b532..bbf3df37d01 100644 --- a/src/vs/editor/contrib/dnd/dnd.ts +++ b/src/vs/editor/contrib/dnd/dnd.ts @@ -19,6 +19,7 @@ import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { IModelDeltaDecoration } from 'vs/editor/common/model'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; function hasTriggerModifier(e: IKeyboardEvent | IMouseEvent): boolean { if (isMacintosh) { @@ -67,7 +68,7 @@ export class DragAndDropController extends Disposable implements editorCommon.IE } private onEditorKeyDown(e: IKeyboardEvent): void { - if (!this._editor.getConfiguration().dragAndDrop) { + if (!this._editor.getOption(EditorOption.dragAndDrop)) { return; } @@ -83,7 +84,7 @@ export class DragAndDropController extends Disposable implements editorCommon.IE } private onEditorKeyUp(e: IKeyboardEvent): void { - if (!this._editor.getConfiguration().dragAndDrop) { + if (!this._editor.getOption(EditorOption.dragAndDrop)) { return; } diff --git a/src/vs/editor/contrib/find/findController.ts b/src/vs/editor/contrib/find/findController.ts index 664bc8c8bf3..f5c7305872f 100644 --- a/src/vs/editor/contrib/find/findController.ts +++ b/src/vs/editor/contrib/find/findController.ts @@ -26,6 +26,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { INotificationService } from 'vs/platform/notification/common/notification'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const SEARCH_STRING_MAX_LENGTH = 524288; @@ -120,7 +121,7 @@ export class CommonFindController extends Disposable implements editorCommon.IEd if (shouldRestartFind) { this._start({ forceRevealReplace: false, - seedSearchStringFromSelection: false && this._editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection, + seedSearchStringFromSelection: false && this._editor.getOption(EditorOption.find).seedSearchStringFromSelection, seedSearchStringFromGlobalClipboard: false, shouldFocus: FindStartFocusAction.NoFocusChange, shouldAnimate: false, @@ -352,7 +353,7 @@ export class CommonFindController extends Disposable implements editorCommon.IEd } public getGlobalBufferTerm(): string { - if (this._editor.getConfiguration().contribInfo.find.globalFindClipboard + if (this._editor.getOption(EditorOption.find).globalFindClipboard && this._clipboardService && this._editor.hasModel() && !this._editor.getModel().isTooLargeForSyncing() @@ -363,7 +364,7 @@ export class CommonFindController extends Disposable implements editorCommon.IEd } public setGlobalBufferTerm(text: string) { - if (this._editor.getConfiguration().contribInfo.find.globalFindClipboard + if (this._editor.getOption(EditorOption.find).globalFindClipboard && this._clipboardService && this._editor.hasModel() && !this._editor.getModel().isTooLargeForSyncing() @@ -398,7 +399,7 @@ export class FindController extends CommonFindController implements IFindControl this._createFindWidget(); } - if (!this._widget!.getPosition() && this._editor.getConfiguration().contribInfo.find.autoFindInSelection) { + if (!this._widget!.getPosition() && this._editor.getOption(EditorOption.find).autoFindInSelection) { // not visible yet so we need to set search scope if `editor.find.autoFindInSelection` is `true` opts.updateSearchScope = true; } @@ -456,8 +457,8 @@ export class StartFindAction extends EditorAction { if (controller) { controller.start({ forceRevealReplace: false, - seedSearchStringFromSelection: editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection, - seedSearchStringFromGlobalClipboard: editor.getConfiguration().contribInfo.find.globalFindClipboard, + seedSearchStringFromSelection: editor.getOption(EditorOption.find).seedSearchStringFromSelection, + seedSearchStringFromGlobalClipboard: editor.getOption(EditorOption.find).globalFindClipboard, shouldFocus: FindStartFocusAction.FocusFindInput, shouldAnimate: true, updateSearchScope: false @@ -507,7 +508,7 @@ export abstract class MatchFindAction extends EditorAction { if (controller && !this._run(controller)) { controller.start({ forceRevealReplace: false, - seedSearchStringFromSelection: (controller.getState().searchString.length === 0) && editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection, + seedSearchStringFromSelection: (controller.getState().searchString.length === 0) && editor.getOption(EditorOption.find).seedSearchStringFromSelection, seedSearchStringFromGlobalClipboard: true, shouldFocus: FindStartFocusAction.NoFocusChange, shouldAnimate: true, @@ -619,7 +620,7 @@ export abstract class SelectionMatchFindAction extends EditorAction { if (!this._run(controller)) { controller.start({ forceRevealReplace: false, - seedSearchStringFromSelection: editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection, + seedSearchStringFromSelection: editor.getOption(EditorOption.find).seedSearchStringFromSelection, seedSearchStringFromGlobalClipboard: false, shouldFocus: FindStartFocusAction.NoFocusChange, shouldAnimate: true, @@ -698,7 +699,7 @@ export class StartFindReplaceAction extends EditorAction { } public run(accessor: ServicesAccessor | null, editor: ICodeEditor): void { - if (!editor.hasModel() || editor.getConfiguration().readOnly) { + if (!editor.hasModel() || editor.getOption(EditorOption.readOnly)) { return; } @@ -708,7 +709,7 @@ export class StartFindReplaceAction extends EditorAction { // we only seed search string from selection when the current selection is single line and not empty, // + the find input is not focused let seedSearchStringFromSelection = !currentSelection.isEmpty() - && currentSelection.startLineNumber === currentSelection.endLineNumber && editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection + && currentSelection.startLineNumber === currentSelection.endLineNumber && editor.getOption(EditorOption.find).seedSearchStringFromSelection && !findInputFocused; /* * if the existing search string in find widget is empty and we don't seed search string from selection, it means the Find Input is still empty, so we should focus the Find Input instead of Replace Input. @@ -725,7 +726,7 @@ export class StartFindReplaceAction extends EditorAction { controller.start({ forceRevealReplace: true, seedSearchStringFromSelection: seedSearchStringFromSelection, - seedSearchStringFromGlobalClipboard: editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection, + seedSearchStringFromGlobalClipboard: editor.getOption(EditorOption.find).seedSearchStringFromSelection, shouldFocus: shouldFocus, shouldAnimate: true, updateSearchScope: false diff --git a/src/vs/editor/contrib/find/findModel.ts b/src/vs/editor/contrib/find/findModel.ts index 90932abefc6..e039801431f 100644 --- a/src/vs/editor/contrib/find/findModel.ts +++ b/src/vs/editor/contrib/find/findModel.ts @@ -22,6 +22,7 @@ import { ReplaceAllCommand } from 'vs/editor/contrib/find/replaceAllCommand'; import { ReplacePattern, parseReplaceString } from 'vs/editor/contrib/find/replacePattern'; import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const CONTEXT_FIND_WIDGET_VISIBLE = new RawContextKey('findWidgetVisible', false); export const CONTEXT_FIND_WIDGET_NOT_VISIBLE: ContextKeyExpr = CONTEXT_FIND_WIDGET_VISIBLE.toNegated(); @@ -287,12 +288,12 @@ export class FindModelBoundToEditorModel { let position = new Position(lineNumber, column); - let prevMatch = model.findPreviousMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false); + let prevMatch = model.findPreviousMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false); if (prevMatch && prevMatch.range.isEmpty() && prevMatch.range.getStartPosition().equals(position)) { // Looks like we're stuck at this position, unacceptable! position = this._prevSearchPosition(position); - prevMatch = model.findPreviousMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false); + prevMatch = model.findPreviousMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false); } if (!prevMatch) { @@ -379,12 +380,12 @@ export class FindModelBoundToEditorModel { let position = new Position(lineNumber, column); - let nextMatch = model.findNextMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null, captureMatches); + let nextMatch = model.findNextMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, captureMatches); if (forceMove && nextMatch && nextMatch.range.isEmpty() && nextMatch.range.getStartPosition().equals(position)) { // Looks like we're stuck at this position, unacceptable! position = this._nextSearchPosition(position); - nextMatch = model.findNextMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null, captureMatches); + nextMatch = model.findNextMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, captureMatches); } if (!nextMatch) { @@ -438,7 +439,7 @@ export class FindModelBoundToEditorModel { private _findMatches(findScope: Range | null, captureMatches: boolean, limitResultCount: number): FindMatch[] { let searchRange = FindModelBoundToEditorModel._getSearchRange(this._editor.getModel(), findScope); - return this._editor.getModel().findMatches(this._state.searchString, searchRange, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null, captureMatches, limitResultCount); + return this._editor.getModel().findMatches(this._state.searchString, searchRange, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, captureMatches, limitResultCount); } public replaceAll(): void { @@ -459,7 +460,7 @@ export class FindModelBoundToEditorModel { } private _largeReplaceAll(): void { - const searchParams = new SearchParams(this._state.searchString, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null); + const searchParams = new SearchParams(this._state.searchString, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null); const searchData = searchParams.parseSearchRequest(); if (!searchData) { return; diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index b5b2afdff69..a05f0191e31 100644 --- a/src/vs/editor/contrib/find/findWidget.ts +++ b/src/vs/editor/contrib/find/findWidget.ts @@ -23,7 +23,7 @@ import { toDisposable } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import * as strings from 'vs/base/common/strings'; import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, IViewZone, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Range } from 'vs/editor/common/core/range'; import { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_REPLACE_INPUT_FOCUSED, FIND_IDS, MATCHES_LIMIT } from 'vs/editor/contrib/find/findModel'; import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState'; @@ -176,24 +176,24 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._tryUpdateWidgetWidth(); this._findInput.inputBox.layout(); - this._register(this._codeEditor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.readOnly) { - if (this._codeEditor.getConfiguration().readOnly) { + this._register(this._codeEditor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.readOnly)) { + if (this._codeEditor.getOption(EditorOption.readOnly)) { // Hide replace part if editor becomes read only this._state.change({ isReplaceRevealed: false }, false); } this._updateButtons(); } - if (e.layoutInfo) { + if (e.hasChanged(EditorOption.layoutInfo)) { this._tryUpdateWidgetWidth(); } - if (e.accessibilitySupport) { + if (e.hasChanged(EditorOption.accessibilitySupport)) { this.updateAccessibilitySupport(); } - if (e.contribInfo) { - const addExtraSpaceOnTop = this._codeEditor.getConfiguration().contribInfo.find.addExtraSpaceOnTop; + if (e.hasChanged(EditorOption.find)) { + const addExtraSpaceOnTop = this._codeEditor.getOption(EditorOption.find).addExtraSpaceOnTop; if (addExtraSpaceOnTop && !this._viewZone) { this._viewZone = new FindWidgetViewZone(0); this._showViewZone(); @@ -239,7 +239,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas })); this._codeEditor.addOverlayWidget(this); - if (this._codeEditor.getConfiguration().contribInfo.find.addExtraSpaceOnTop) { + if (this._codeEditor.getOption(EditorOption.find).addExtraSpaceOnTop) { this._viewZone = new FindWidgetViewZone(0); // Put it before the first line then users can scroll beyond the first line. } @@ -316,7 +316,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } if (e.isReplaceRevealed) { if (this._state.isReplaceRevealed) { - if (!this._codeEditor.getConfiguration().readOnly && !this._isReplaceVisible) { + if (!this._codeEditor.getOption(EditorOption.readOnly) && !this._isReplaceVisible) { this._isReplaceVisible = true; this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode); this._updateButtons(); @@ -457,7 +457,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._toggleReplaceBtn.toggleClass('expand', this._isReplaceVisible); this._toggleReplaceBtn.setExpanded(this._isReplaceVisible); - let canReplace = !this._codeEditor.getConfiguration().readOnly; + let canReplace = !this._codeEditor.getOption(EditorOption.readOnly); this._toggleReplaceBtn.setEnabled(this._isVisible && canReplace); } @@ -467,7 +467,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas const selection = this._codeEditor.getSelection(); const isSelection = selection ? (selection.startLineNumber !== selection.endLineNumber || selection.startColumn !== selection.endColumn) : false; - if (isSelection && this._codeEditor.getConfiguration().contribInfo.find.autoFindInSelection) { + if (isSelection && this._codeEditor.getOption(EditorOption.find).autoFindInSelection) { this._toggleSelectionFind.checked = true; } else { this._toggleSelectionFind.checked = false; @@ -488,7 +488,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._codeEditor.layoutOverlayWidget(this); let adjustEditorScrollTop = true; - if (this._codeEditor.getConfiguration().contribInfo.find.seedSearchStringFromSelection && selection) { + if (this._codeEditor.getOption(EditorOption.find).seedSearchStringFromSelection && selection) { const domNode = this._codeEditor.getDomNode(); if (domNode) { const editorCoords = dom.getDomNodePagePosition(domNode); @@ -535,7 +535,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } private _layoutViewZone() { - const addExtraSpaceOnTop = this._codeEditor.getConfiguration().contribInfo.find.addExtraSpaceOnTop; + const addExtraSpaceOnTop = this._codeEditor.getOption(EditorOption.find).addExtraSpaceOnTop; if (!addExtraSpaceOnTop) { this._removeViewZone(); @@ -563,7 +563,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas return; } - const addExtraSpaceOnTop = this._codeEditor.getConfiguration().contribInfo.find.addExtraSpaceOnTop; + const addExtraSpaceOnTop = this._codeEditor.getOption(EditorOption.find).addExtraSpaceOnTop; if (!addExtraSpaceOnTop) { return; @@ -643,7 +643,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas return; } - const editorContentWidth = this._codeEditor.getConfiguration().layoutInfo.contentWidth; + const layoutInfo = this._codeEditor.getLayoutInfo(); + const editorContentWidth = layoutInfo.contentWidth; if (editorContentWidth <= 0) { // for example, diff view original editor @@ -653,8 +654,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas dom.removeClass(this._domNode, 'hiddenEditor'); } - const editorWidth = this._codeEditor.getConfiguration().layoutInfo.width; - const minimapWidth = this._codeEditor.getConfiguration().layoutInfo.minimapWidth; + const editorWidth = layoutInfo.width; + const minimapWidth = layoutInfo.minimapWidth; let collapsedFindWidget = false; let reducedFindWidget = false; let narrowFindWidget = false; @@ -1188,7 +1189,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas if (!this._resized || currentWidth === FIND_WIDGET_INITIAL_WIDTH) { // 1. never resized before, double click should maximizes it // 2. users resized it already but its width is the same as default - width = this._codeEditor.getConfiguration().layoutInfo.width - 28 - this._codeEditor.getConfiguration().layoutInfo.minimapWidth - 15; + const layoutInfo = this._codeEditor.getLayoutInfo(); + width = layoutInfo.width - 28 - layoutInfo.minimapWidth - 15; this._resized = true; } else { /** @@ -1209,7 +1211,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } private updateAccessibilitySupport(): void { - const value = this._codeEditor.getConfiguration().accessibilitySupport; + const value = this._codeEditor.getOption(EditorOption.accessibilitySupport); this._findInput.setFocusInputOnOptionClick(value !== AccessibilitySupport.Enabled); } } diff --git a/src/vs/editor/contrib/folding/folding.ts b/src/vs/editor/contrib/folding/folding.ts index cd7cdbe1d13..f0ae51e1955 100644 --- a/src/vs/editor/contrib/folding/folding.ts +++ b/src/vs/editor/contrib/folding/folding.ts @@ -18,7 +18,7 @@ import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStat import { FoldingDecorationProvider } from './foldingDecorations'; import { FoldingRegions, FoldingRegion } from './foldingRanges'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IMarginData, IEmptyContentData } from 'vs/editor/browser/controller/mouseTarget'; import { HiddenRangeModel } from 'vs/editor/contrib/folding/hiddenRangeModel'; import { IRange } from 'vs/editor/common/core/range'; @@ -87,9 +87,10 @@ export class FoldingController extends Disposable implements IEditorContribution ) { super(); this.editor = editor; - this._isEnabled = this.editor.getConfiguration().contribInfo.folding; - this._autoHideFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls === 'mouseover'; - this._useFoldingProviders = this.editor.getConfiguration().contribInfo.foldingStrategy !== 'indentation'; + const options = this.editor.getOptions(); + this._isEnabled = options.get(EditorOption.folding); + this._autoHideFoldingControls = options.get(EditorOption.showFoldingControls) === 'mouseover'; + this._useFoldingProviders = options.get(EditorOption.foldingStrategy) !== 'indentation'; this.foldingModel = null; this.hiddenRangeModel = null; @@ -108,22 +109,23 @@ export class FoldingController extends Disposable implements IEditorContribution this._register(this.editor.onDidChangeModel(() => this.onModelChanged())); - this._register(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.contribInfo) { + this._register(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.folding) || e.hasChanged(EditorOption.showFoldingControls) || e.hasChanged(EditorOption.foldingStrategy)) { let oldIsEnabled = this._isEnabled; - this._isEnabled = this.editor.getConfiguration().contribInfo.folding; + const options = this.editor.getOptions(); + this._isEnabled = options.get(EditorOption.folding); this.foldingEnabled.set(this._isEnabled); if (oldIsEnabled !== this._isEnabled) { this.onModelChanged(); } let oldShowFoldingControls = this._autoHideFoldingControls; - this._autoHideFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls === 'mouseover'; + this._autoHideFoldingControls = options.get(EditorOption.showFoldingControls) === 'mouseover'; if (oldShowFoldingControls !== this._autoHideFoldingControls) { this.foldingDecorationProvider.autoHideFoldingControls = this._autoHideFoldingControls; this.onModelContentChanged(); } let oldUseFoldingProviders = this._useFoldingProviders; - this._useFoldingProviders = this.editor.getConfiguration().contribInfo.foldingStrategy !== 'indentation'; + this._useFoldingProviders = options.get(EditorOption.foldingStrategy) !== 'indentation'; if (oldUseFoldingProviders !== this._useFoldingProviders) { this.onFoldingStrategyChanged(); } diff --git a/src/vs/editor/contrib/format/formatActions.ts b/src/vs/editor/contrib/format/formatActions.ts index 8b2798a496d..1af6506e0d8 100644 --- a/src/vs/editor/contrib/format/formatActions.ts +++ b/src/vs/editor/contrib/format/formatActions.ts @@ -24,6 +24,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; class FormatOnType implements editorCommon.IEditorContribution { @@ -59,7 +60,7 @@ class FormatOnType implements editorCommon.IEditorContribution { this._callOnModel.clear(); // we are disabled - if (!this._editor.getConfiguration().contribInfo.formatOnType) { + if (!this._editor.getOption(EditorOption.formatOnType)) { return; } @@ -184,7 +185,7 @@ class FormatOnPaste implements editorCommon.IEditorContribution { this._callOnModel.clear(); // we are disabled - if (!this.editor.getConfiguration().contribInfo.formatOnPaste) { + if (!this.editor.getOption(EditorOption.formatOnPaste)) { return; } diff --git a/src/vs/editor/contrib/goToDefinition/clickLinkGesture.ts b/src/vs/editor/contrib/goToDefinition/clickLinkGesture.ts index 3b72a01a35c..f23c13dcd38 100644 --- a/src/vs/editor/contrib/goToDefinition/clickLinkGesture.ts +++ b/src/vs/editor/contrib/goToDefinition/clickLinkGesture.ts @@ -12,6 +12,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { Event, Emitter } from 'vs/base/common/event'; import * as platform from 'vs/base/common/platform'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; function hasModifier(e: { ctrlKey: boolean; shiftKey: boolean; altKey: boolean; metaKey: boolean }, modifier: 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey'): boolean { return !!e[modifier]; @@ -116,14 +117,14 @@ export class ClickLinkGesture extends Disposable { super(); this._editor = editor; - this._opts = createOptions(this._editor.getConfiguration().multiCursorModifier); + this._opts = createOptions(this._editor.getOption(EditorOption.multiCursorModifier)); this.lastMouseMoveEvent = null; this.hasTriggerKeyOnMouseDown = false; this._register(this._editor.onDidChangeConfiguration((e) => { - if (e.multiCursorModifier) { - const newOpts = createOptions(this._editor.getConfiguration().multiCursorModifier); + if (e.hasChanged(EditorOption.multiCursorModifier)) { + const newOpts = createOptions(this._editor.getOption(EditorOption.multiCursorModifier)); if (this._opts.equals(newOpts)) { return; } diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts index baad3f0bb17..6e29856e81e 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts @@ -30,6 +30,7 @@ import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefiniti import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { EditorStateCancellationTokenSource, CodeEditorStateFlag } from 'vs/editor/browser/core/editorState'; import { ISymbolNavigationService } from 'vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class DefinitionActionConfig { @@ -137,7 +138,7 @@ export class DefinitionAction extends EditorAction { const msg = model.getAriaMessage(); alert(msg); - const { gotoLocation } = editor.getConfiguration().contribInfo; + const gotoLocation = editor.getOption(EditorOption.gotoLocation); if (this._configuration.openInPeek || (gotoLocation.multiple === 'peek' && model.references.length > 1)) { this._openInPeek(editorService, editor, model); diff --git a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts index 9da6b13042f..39fe2e80364 100644 --- a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts +++ b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts @@ -26,6 +26,7 @@ import { IAction } from 'vs/base/common/actions'; import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/referencesWidget'; import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; class MessageWidget { @@ -122,7 +123,7 @@ class MessageWidget { this._editor.applyFontInfo(this._relatedBlock); if (isNonEmptyArray(relatedInformation)) { const relatedInformationNode = this._relatedBlock.appendChild(document.createElement('div')); - relatedInformationNode.style.paddingTop = `${Math.floor(this._editor.getConfiguration().lineHeight * 0.66)}px`; + relatedInformationNode.style.paddingTop = `${Math.floor(this._editor.getOption(EditorOption.lineHeight) * 0.66)}px`; this._lines += 1; for (const related of relatedInformation) { @@ -146,7 +147,7 @@ class MessageWidget { } } - const fontInfo = this._editor.getConfiguration().fontInfo; + const fontInfo = this._editor.getOption(EditorOption.fontInfo); const scrollWidth = Math.ceil(fontInfo.typicalFullwidthCharacterWidth * this._longestLineLength * 0.75); const scrollHeight = fontInfo.lineHeight * this._lines; this._scrollable.setScrollDimensions({ scrollWidth, scrollHeight }); diff --git a/src/vs/editor/contrib/hover/hover.ts b/src/vs/editor/contrib/hover/hover.ts index 583e4c65dee..215ddd5844c 100644 --- a/src/vs/editor/contrib/hover/hover.ts +++ b/src/vs/editor/contrib/hover/hover.ts @@ -11,7 +11,7 @@ import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IEmptyContentData } from 'vs/editor/browser/controller/mouseTarget'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Range } from 'vs/editor/common/core/range'; import { IEditorContribution, IScrollEvent } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; @@ -74,8 +74,8 @@ export class ModesHoverController implements IEditorContribution { this._hookEvents(); - this._didChangeConfigurationHandler = this._editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.contribInfo) { + this._didChangeConfigurationHandler = this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.hover)) { this._hideWidgets(); this._unhookEvents(); this._hookEvents(); @@ -86,7 +86,7 @@ export class ModesHoverController implements IEditorContribution { private _hookEvents(): void { const hideWidgetsEventHandler = () => this._hideWidgets(); - const hoverOpts = this._editor.getConfiguration().contribInfo.hover; + const hoverOpts = this._editor.getOption(EditorOption.hover); this._isHoverEnabled = hoverOpts.enabled; this._isHoverSticky = hoverOpts.sticky; if (this._isHoverEnabled) { @@ -147,7 +147,6 @@ export class ModesHoverController implements IEditorContribution { } private _onEditorMouseMove(mouseEvent: IEditorMouseEvent): void { - // const this._editor.getConfiguration().contribInfo.hover.sticky; let targetType = mouseEvent.target.type; if (this._isMouseDown && this._hoverClicked && this.contentWidget.isColorPickerVisible()) { @@ -165,7 +164,7 @@ export class ModesHoverController implements IEditorContribution { } if (targetType === MouseTargetType.CONTENT_EMPTY) { - const epsilon = this._editor.getConfiguration().fontInfo.typicalHalfwidthCharacterWidth / 2; + const epsilon = this._editor.getOption(EditorOption.fontInfo).typicalHalfwidthCharacterWidth / 2; const data = mouseEvent.target.detail; if (data && !data.isAfterLines && typeof data.horizontalDistanceToText === 'number' && data.horizontalDistanceToText < epsilon) { // Let hover kick in even when the mouse is technically in the empty area after a line, given the distance is small enough @@ -265,7 +264,7 @@ class ShowHoverAction extends EditorAction { } const position = editor.getPosition(); const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column); - const focus = editor.getConfiguration().accessibilitySupport === AccessibilitySupport.Enabled; + const focus = editor.getOption(EditorOption.accessibilitySupport) === AccessibilitySupport.Enabled; controller.showContentHover(range, HoverStartMode.Immediate, focus); } } diff --git a/src/vs/editor/contrib/hover/hoverWidgets.ts b/src/vs/editor/contrib/hover/hoverWidgets.ts index 13dff650038..9077e4a9eb0 100644 --- a/src/vs/editor/contrib/hover/hoverWidgets.ts +++ b/src/vs/editor/contrib/hover/hoverWidgets.ts @@ -8,15 +8,15 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { Widget } from 'vs/base/browser/ui/widget'; import { KeyCode } from 'vs/base/common/keyCodes'; -import * as editorBrowser from 'vs/editor/browser/editorBrowser'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { IContentWidget, ICodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -export class ContentHoverWidget extends Widget implements editorBrowser.IContentWidget { +export class ContentHoverWidget extends Widget implements IContentWidget { private readonly _id: string; - protected _editor: editorBrowser.ICodeEditor; + protected _editor: ICodeEditor; private _isVisible: boolean; private readonly _containerDomNode: HTMLElement; private readonly _domNode: HTMLElement; @@ -37,7 +37,7 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent toggleClass(this._containerDomNode, 'hidden', !this._isVisible); } - constructor(id: string, editor: editorBrowser.ICodeEditor) { + constructor(id: string, editor: ICodeEditor) { super(); this._id = id; this._editor = editor; @@ -61,8 +61,8 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent } }); - this._register(this._editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.fontInfo) { + this._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.fontInfo)) { this.updateFont(); } })); @@ -113,14 +113,14 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent } } - public getPosition(): editorBrowser.IContentWidgetPosition | null { + public getPosition(): IContentWidgetPosition | null { if (this.isVisible) { return { position: this._showAtPosition, range: this._showAtRange, preference: [ - editorBrowser.ContentWidgetPositionPreference.ABOVE, - editorBrowser.ContentWidgetPositionPreference.BELOW + ContentWidgetPositionPreference.ABOVE, + ContentWidgetPositionPreference.BELOW ] }; } @@ -152,7 +152,7 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent private layout(): void { const height = Math.max(this._editor.getLayoutInfo().height / 4, 250); - const { fontSize, lineHeight } = this._editor.getConfiguration().fontInfo; + const { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo); this._domNode.style.fontSize = `${fontSize}px`; this._domNode.style.lineHeight = `${lineHeight}px`; @@ -161,15 +161,15 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent } } -export class GlyphHoverWidget extends Widget implements editorBrowser.IOverlayWidget { +export class GlyphHoverWidget extends Widget implements IOverlayWidget { private readonly _id: string; - protected _editor: editorBrowser.ICodeEditor; + protected _editor: ICodeEditor; private _isVisible: boolean; private readonly _domNode: HTMLElement; protected _showAtLineNumber: number; - constructor(id: string, editor: editorBrowser.ICodeEditor) { + constructor(id: string, editor: ICodeEditor) { super(); this._id = id; this._editor = editor; @@ -182,8 +182,8 @@ export class GlyphHoverWidget extends Widget implements editorBrowser.IOverlayWi this._showAtLineNumber = -1; - this._register(this._editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.fontInfo) { + this._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.fontInfo)) { this.updateFont(); } })); @@ -218,7 +218,7 @@ export class GlyphHoverWidget extends Widget implements editorBrowser.IOverlayWi const editorLayout = this._editor.getLayoutInfo(); const topForLineNumber = this._editor.getTopForLineNumber(this._showAtLineNumber); const editorScrollTop = this._editor.getScrollTop(); - const lineHeight = this._editor.getConfiguration().lineHeight; + const lineHeight = this._editor.getOption(EditorOption.lineHeight); const nodeHeight = this._domNode.clientHeight; const top = topForLineNumber - editorScrollTop - ((nodeHeight - lineHeight) / 2); @@ -233,7 +233,7 @@ export class GlyphHoverWidget extends Widget implements editorBrowser.IOverlayWi this.isVisible = false; } - public getPosition(): editorBrowser.IOverlayWidgetPosition | null { + public getPosition(): IOverlayWidgetPosition | null { return null; } diff --git a/src/vs/editor/contrib/hover/modesContentHover.ts b/src/vs/editor/contrib/hover/modesContentHover.ts index d42f5153a1d..06877b671d5 100644 --- a/src/vs/editor/contrib/hover/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/modesContentHover.ts @@ -37,6 +37,7 @@ import { QuickFixAction, QuickFixController } from 'vs/editor/contrib/codeAction import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IIdentifiedSingleEditOperation } from 'vs/editor/common/model'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const $ = dom.$; @@ -222,7 +223,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { result => this._withResult(result, true), null, result => this._withResult(result, false), - this._editor.getConfiguration().contribInfo.hover.delay + this._editor.getOption(EditorOption.hover).delay ); this._register(dom.addStandardDisposableListener(this.getDomNode(), dom.EventType.FOCUS, () => { @@ -234,7 +235,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { dom.removeClass(this.getDomNode(), 'colorpicker-hover'); })); this._register(editor.onDidChangeConfiguration((e) => { - this._hoverOperation.setHoverTime(this._editor.getConfiguration().contribInfo.hover.delay); + this._hoverOperation.setHoverTime(this._editor.getOption(EditorOption.hover).delay); })); } @@ -365,7 +366,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { // create blank olor picker model and widget first to ensure it's positioned correctly. const model = new ColorPickerModel(color, [], 0); - const widget = new ColorPickerWidget(fragment, model, this._editor.getConfiguration().pixelRatio, this._themeService); + const widget = new ColorPickerWidget(fragment, model, this._editor.getOption(EditorOption.pixelRatio), this._themeService); getColorPresentations(editorModel, colorInfo, msg.provider, CancellationToken.None).then(colorPresentations => { model.colorPresentations = colorPresentations || []; diff --git a/src/vs/editor/contrib/indentation/indentation.ts b/src/vs/editor/contrib/indentation/indentation.ts index fd9fcee54ea..bbd4f5e563d 100644 --- a/src/vs/editor/contrib/indentation/indentation.ts +++ b/src/vs/editor/contrib/indentation/indentation.ts @@ -22,6 +22,7 @@ import { IndentConsts } from 'vs/editor/common/modes/supports/indentRules'; import { IModelService } from 'vs/editor/common/services/modelService'; import * as indentUtils from 'vs/editor/contrib/indentation/indentUtils'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export function getReindentEditOperations(model: ITextModel, startLineNumber: number, endLineNumber: number, inheritedIndent?: string): IIdentifiedSingleEditOperation[] { if (model.getLineCount() === 1 && model.getLineMaxColumn(1) === 1) { @@ -443,7 +444,7 @@ export class AutoIndentOnPaste implements IEditorContribution { this.callOnModel = dispose(this.callOnModel); // we are disabled - if (!this.editor.getConfiguration().autoIndent || this.editor.getConfiguration().contribInfo.formatOnPaste) { + if (!this.editor.getOption(EditorOption.autoIndent) || this.editor.getOption(EditorOption.formatOnPaste)) { return; } diff --git a/src/vs/editor/contrib/linesOperations/linesOperations.ts b/src/vs/editor/contrib/linesOperations/linesOperations.ts index 9fb95158f25..7f1d517236a 100644 --- a/src/vs/editor/contrib/linesOperations/linesOperations.ts +++ b/src/vs/editor/contrib/linesOperations/linesOperations.ts @@ -23,6 +23,7 @@ import { MoveLinesCommand } from 'vs/editor/contrib/linesOperations/moveLinesCom import { SortLinesCommand } from 'vs/editor/contrib/linesOperations/sortLinesCommand'; import { MenuId } from 'vs/platform/actions/common/actions'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; // copy lines @@ -111,7 +112,7 @@ abstract class AbstractMoveLinesAction extends EditorAction { let commands: ICommand[] = []; let selections = editor.getSelections() || []; - let autoIndent = editor.getConfiguration().autoIndent; + const autoIndent = editor.getOption(EditorOption.autoIndent); for (const selection of selections) { commands.push(new MoveLinesCommand(selection, this.down, autoIndent)); @@ -886,7 +887,7 @@ export abstract class AbstractCaseAction extends EditorAction { return; } - let wordSeparators = editor.getConfiguration().wordSeparators; + let wordSeparators = editor.getOption(EditorOption.wordSeparators); let commands: ICommand[] = []; diff --git a/src/vs/editor/contrib/links/links.ts b/src/vs/editor/contrib/links/links.ts index f9f19e5211c..1eee5898a96 100644 --- a/src/vs/editor/contrib/links/links.ts +++ b/src/vs/editor/contrib/links/links.ts @@ -24,6 +24,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IOpenerService } from 'vs/platform/opener/common/opener'; import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; function getHoverMessage(link: Link, useMetaKey: boolean): MarkdownString { const executeCmd = link.url && /^command:/i.test(link.url.toString()); @@ -139,9 +140,9 @@ class LinkDetector implements editorCommon.IEditorContribution { this.cleanUpActiveLinkDecoration(); })); - this.enabled = editor.getConfiguration().contribInfo.links; + this.enabled = editor.getOption(EditorOption.links); this.listenersToRemove.add(editor.onDidChangeConfiguration((e) => { - let enabled = editor.getConfiguration().contribInfo.links; + const enabled = editor.getOption(EditorOption.links); if (this.enabled === enabled) { // No change in our configuration option return; @@ -218,7 +219,7 @@ class LinkDetector implements editorCommon.IEditorContribution { } private updateDecorations(links: Link[]): void { - const useMetaKey = (this.editor.getConfiguration().multiCursorModifier === 'altKey'); + const useMetaKey = (this.editor.getOption(EditorOption.multiCursorModifier) === 'altKey'); let oldDecorations: string[] = []; let keys = Object.keys(this.currentOccurrences); for (let i = 0, len = keys.length; i < len; i++) { @@ -246,7 +247,7 @@ class LinkDetector implements editorCommon.IEditorContribution { } private _onEditorMouseMove(mouseEvent: ClickLinkMouseEvent, withKey: ClickLinkKeyboardEvent | null): void { - const useMetaKey = (this.editor.getConfiguration().multiCursorModifier === 'altKey'); + const useMetaKey = (this.editor.getOption(EditorOption.multiCursorModifier) === 'altKey'); if (this.isEnabled(mouseEvent, withKey)) { this.cleanUpActiveLinkDecoration(); // always remove previous link decoration as their can only be one const occurrence = this.getLinkOccurrence(mouseEvent.target.position); @@ -262,7 +263,7 @@ class LinkDetector implements editorCommon.IEditorContribution { } private cleanUpActiveLinkDecoration(): void { - const useMetaKey = (this.editor.getConfiguration().multiCursorModifier === 'altKey'); + const useMetaKey = (this.editor.getOption(EditorOption.multiCursorModifier) === 'altKey'); if (this.activeLinkDecorationId) { const occurrence = this.currentOccurrences[this.activeLinkDecorationId]; if (occurrence) { diff --git a/src/vs/editor/contrib/markdown/markdownRenderer.ts b/src/vs/editor/contrib/markdown/markdownRenderer.ts index 81f0b2ccc87..e8165ed3e7a 100644 --- a/src/vs/editor/contrib/markdown/markdownRenderer.ts +++ b/src/vs/editor/contrib/markdown/markdownRenderer.ts @@ -15,6 +15,7 @@ import { optional } from 'vs/platform/instantiation/common/instantiation'; import { Event, Emitter } from 'vs/base/common/event'; import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { TokenizationRegistry } from 'vs/editor/common/modes'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface IMarkdownRenderResult extends IDisposable { element: HTMLElement; @@ -57,7 +58,7 @@ export class MarkdownRenderer extends Disposable { } return tokenizeToString(value, undefined); }).then(code => { - return `${code}`; + return `${code}`; }); }, codeBlockRenderCallback: () => this._onDidRenderCodeBlock.fire(), diff --git a/src/vs/editor/contrib/multicursor/multicursor.ts b/src/vs/editor/contrib/multicursor/multicursor.ts index aee06c601d9..a76a1d62e96 100644 --- a/src/vs/editor/contrib/multicursor/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/multicursor.ts @@ -26,6 +26,7 @@ import { MenuId } from 'vs/platform/actions/common/actions'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { overviewRulerSelectionHighlightForeground } from 'vs/platform/theme/common/colorRegistry'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class InsertCursorAbove extends EditorAction { @@ -350,7 +351,7 @@ export class MultiCursorSession { const allSelections = this._editor.getSelections(); const lastAddedSelection = allSelections[allSelections.length - 1]; - const nextMatch = this._editor.getModel().findNextMatch(this.searchText, lastAddedSelection.getEndPosition(), false, this.matchCase, this.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false); + const nextMatch = this._editor.getModel().findNextMatch(this.searchText, lastAddedSelection.getEndPosition(), false, this.matchCase, this.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false); if (!nextMatch) { return null; @@ -401,7 +402,7 @@ export class MultiCursorSession { const allSelections = this._editor.getSelections(); const lastAddedSelection = allSelections[allSelections.length - 1]; - const previousMatch = this._editor.getModel().findPreviousMatch(this.searchText, lastAddedSelection.getStartPosition(), false, this.matchCase, this.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false); + const previousMatch = this._editor.getModel().findPreviousMatch(this.searchText, lastAddedSelection.getStartPosition(), false, this.matchCase, this.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false); if (!previousMatch) { return null; @@ -416,7 +417,7 @@ export class MultiCursorSession { this.findController.highlightFindOptions(); - return this._editor.getModel().findMatches(this.searchText, true, false, this.matchCase, this.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false, Constants.MAX_SAFE_SMALL_INTEGER); + return this._editor.getModel().findMatches(this.searchText, true, false, this.matchCase, this.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false, Constants.MAX_SAFE_SMALL_INTEGER); } } @@ -593,7 +594,7 @@ export class MultiCursorSelectionController extends Disposable implements IEdito // - and we're searching for a regex if (findState.isRevealed && findState.searchString.length > 0 && findState.isRegex) { - matches = this._editor.getModel().findMatches(findState.searchString, true, findState.isRegex, findState.matchCase, findState.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false, Constants.MAX_SAFE_SMALL_INTEGER); + matches = this._editor.getModel().findMatches(findState.searchString, true, findState.isRegex, findState.matchCase, findState.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false, Constants.MAX_SAFE_SMALL_INTEGER); } else { @@ -808,13 +809,13 @@ export class SelectionHighlighter extends Disposable implements IEditorContribut constructor(editor: ICodeEditor) { super(); this.editor = editor; - this._isEnabled = editor.getConfiguration().contribInfo.selectionHighlight; + this._isEnabled = editor.getOption(EditorOption.selectionHighlight); this.decorations = []; this.updateSoon = this._register(new RunOnceScheduler(() => this._update(), 300)); this.state = null; this._register(editor.onDidChangeConfiguration((e) => { - this._isEnabled = editor.getConfiguration().contribInfo.selectionHighlight; + this._isEnabled = editor.getOption(EditorOption.selectionHighlight); })); this._register(editor.onDidChangeCursorSelection((e: ICursorSelectionChangedEvent) => { @@ -928,7 +929,7 @@ export class SelectionHighlighter extends Disposable implements IEditorContribut } } - return new SelectionHighlighterState(r.searchText, r.matchCase, r.wholeWord ? editor.getConfiguration().wordSeparators : null); + return new SelectionHighlighterState(r.searchText, r.matchCase, r.wholeWord ? editor.getOption(EditorOption.wordSeparators) : null); } private _setState(state: SelectionHighlighterState | null): void { diff --git a/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts b/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts index 21cf0393170..6c3c9cb9ae6 100644 --- a/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts +++ b/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts @@ -12,6 +12,7 @@ import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursor import { CharacterSet } from 'vs/editor/common/core/characterClassifier'; import * as modes from 'vs/editor/common/modes'; import { provideSignatureHelp } from 'vs/editor/contrib/parameterHints/provideSignatureHelp'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface TriggerContext { readonly triggerKind: modes.SignatureHelpTriggerKind; @@ -125,7 +126,7 @@ export class ParameterHintsModel extends Disposable { const length = this.state.hints.signatures.length; const activeSignature = this.state.hints.activeSignature; const last = (activeSignature % length) === (length - 1); - const cycle = this.editor.getConfiguration().contribInfo.parameterHints.cycle; + const cycle = this.editor.getOption(EditorOption.parameterHints).cycle; // If there is only one signature, or we're on last signature of list if ((length < 2 || last) && !cycle) { @@ -144,7 +145,7 @@ export class ParameterHintsModel extends Disposable { const length = this.state.hints.signatures.length; const activeSignature = this.state.hints.activeSignature; const first = activeSignature === 0; - const cycle = this.editor.getConfiguration().contribInfo.parameterHints.cycle; + const cycle = this.editor.getOption(EditorOption.parameterHints).cycle; // If there is only one signature, or we're on first signature of list if ((length < 2 || first) && !cycle) { @@ -271,7 +272,7 @@ export class ParameterHintsModel extends Disposable { } private onEditorConfigurationChange(): void { - this.triggerOnType = this.editor.getConfiguration().contribInfo.parameterHints.enabled; + this.triggerOnType = this.editor.getOption(EditorOption.parameterHints).enabled; if (!this.triggerOnType) { this.cancel(); diff --git a/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts b/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts index 0efd0207cb6..696ff9f693a 100644 --- a/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts +++ b/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts @@ -11,7 +11,7 @@ import { Event } from 'vs/base/common/event'; import { IDisposable, Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import 'vs/css!./parameterHints'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import * as modes from 'vs/editor/common/modes'; import { IModeService } from 'vs/editor/common/services/modeService'; import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer'; @@ -105,14 +105,14 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, })); const updateFont = () => { - const fontInfo = this.editor.getConfiguration().fontInfo; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); this.element.style.fontSize = `${fontInfo.fontSize}px`; }; updateFont(); - this._register(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) - .filter(e => e.fontInfo) + this._register(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + .filter(e => e.hasChanged(EditorOption.fontInfo)) .on(updateFont, null)); this._register(this.editor.onDidLayoutChange(e => this.updateMaxHeight())); @@ -177,7 +177,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, const code = dom.append(this.signature, $('.code')); const hasParameters = signature.parameters.length > 0; - const fontInfo = this.editor.getConfiguration().fontInfo; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); code.style.fontSize = `${fontInfo.fontSize}px`; code.style.fontFamily = fontInfo.fontFamily; diff --git a/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts b/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts index 0ef1a5253c6..16d358dd7a4 100644 --- a/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts @@ -21,6 +21,7 @@ import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/con import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable } from 'vs/base/common/lifecycle'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const IPeekViewService = createDecorator('IPeekViewService'); @@ -216,7 +217,7 @@ export abstract class PeekViewWidget extends ZoneWidget { return; } - const headHeight = Math.ceil(this.editor.getConfiguration().lineHeight * 1.2); + const headHeight = Math.ceil(this.editor.getOption(EditorOption.lineHeight) * 1.2); const bodyHeight = heightInPixel - (headHeight + 2 /* the border-top/bottom width*/); this._doLayoutHead(headHeight, widthInPixel); diff --git a/src/vs/editor/contrib/referenceSearch/referencesModel.ts b/src/vs/editor/contrib/referenceSearch/referencesModel.ts index 35af7095f8b..36d54e60852 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesModel.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesModel.ts @@ -74,9 +74,9 @@ export class FilePreview implements IDisposable { const beforeRange = new Range(startLineNumber, word.startColumn, startLineNumber, startColumn); const afterRange = new Range(endLineNumber, endColumn, endLineNumber, Number.MAX_VALUE); - const before = model.getValueInRange(beforeRange).replace(/^\s+/, strings.empty); + const before = model.getValueInRange(beforeRange).replace(/^\s+/, ''); const inside = model.getValueInRange(range); - const after = model.getValueInRange(afterRange).replace(/\s+$/, strings.empty); + const after = model.getValueInRange(afterRange).replace(/\s+$/, ''); return { value: before + inside + after, diff --git a/src/vs/editor/contrib/rename/renameInputField.ts b/src/vs/editor/contrib/rename/renameInputField.ts index c285d9707cd..1113144c6c4 100644 --- a/src/vs/editor/contrib/rename/renameInputField.ts +++ b/src/vs/editor/contrib/rename/renameInputField.ts @@ -13,6 +13,7 @@ import { localize } from 'vs/nls'; import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { inputBackground, inputBorder, inputForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const CONTEXT_RENAME_INPUT_VISIBLE = new RawContextKey('renameInputVisible', false); @@ -40,7 +41,7 @@ export class RenameInputField implements IContentWidget, IDisposable { this._editor.addContentWidget(this); this._disposables.add(editor.onDidChangeConfiguration(e => { - if (e.fontInfo) { + if (e.hasChanged(EditorOption.fontInfo)) { this.updateFont(); } })); @@ -68,7 +69,7 @@ export class RenameInputField implements IContentWidget, IDisposable { this._inputField.type = 'text'; this._inputField.setAttribute('aria-label', localize('renameAriaLabel', "Rename input. Type new name and press Enter to commit.")); this._domNode = document.createElement('div'); - this._domNode.style.height = `${this._editor.getConfiguration().lineHeight}px`; + this._domNode.style.height = `${this._editor.getOption(EditorOption.lineHeight)}px`; this._domNode.className = 'monaco-editor rename-box'; this._domNode.appendChild(this._inputField); @@ -103,7 +104,7 @@ export class RenameInputField implements IContentWidget, IDisposable { return; } - const fontInfo = this._editor.getConfiguration().fontInfo; + const fontInfo = this._editor.getOption(EditorOption.fontInfo); this._inputField.style.fontFamily = fontInfo.fontFamily; this._inputField.style.fontWeight = fontInfo.fontWeight; this._inputField.style.fontSize = `${fontInfo.fontSize}px`; diff --git a/src/vs/editor/contrib/smartSelect/smartSelect.ts b/src/vs/editor/contrib/smartSelect/smartSelect.ts index 4fe561f4c29..43401ee00e8 100644 --- a/src/vs/editor/contrib/smartSelect/smartSelect.ts +++ b/src/vs/editor/contrib/smartSelect/smartSelect.ts @@ -165,7 +165,10 @@ class GrowSelectionAction extends AbstractSmartSelect { kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.RightArrow, - mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.RightArrow }, + mac: { + primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.RightArrow, + secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.RightArrow], + }, weight: KeybindingWeight.EditorContrib }, menubarOpts: { @@ -191,7 +194,10 @@ class ShrinkSelectionAction extends AbstractSmartSelect { kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.LeftArrow, - mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.LeftArrow }, + mac: { + primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.LeftArrow, + secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.LeftArrow], + }, weight: KeybindingWeight.EditorContrib }, menubarOpts: { diff --git a/src/vs/editor/contrib/snippet/snippetSession.ts b/src/vs/editor/contrib/snippet/snippetSession.ts index 63aa8a230eb..8bc84ccfd52 100644 --- a/src/vs/editor/contrib/snippet/snippetSession.ts +++ b/src/vs/editor/contrib/snippet/snippetSession.ts @@ -23,6 +23,7 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic import * as colors from 'vs/platform/theme/common/colorRegistry'; import { withNullAsUndefined } from 'vs/base/common/types'; import { ILabelService } from 'vs/platform/label/common/label'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; registerThemingParticipant((theme, collector) => { @@ -444,7 +445,7 @@ export class SnippetSession { snippet.resolveVariables(new CompositeSnippetVariableResolver([ modelBasedVariableResolver, - new ClipboardBasedVariableResolver(clipboardText, idx, indexedSelections.length), + new ClipboardBasedVariableResolver(clipboardText, idx, indexedSelections.length, editor.getOption(EditorOption.multiCursorPaste) === 'spread'), new SelectionBasedVariableResolver(model, selection), new CommentBasedVariableResolver(model), new TimeBasedVariableResolver, diff --git a/src/vs/editor/contrib/snippet/snippetVariables.ts b/src/vs/editor/contrib/snippet/snippetVariables.ts index a1c080d2b45..4f289c2af95 100644 --- a/src/vs/editor/contrib/snippet/snippetVariables.ts +++ b/src/vs/editor/contrib/snippet/snippetVariables.ts @@ -169,7 +169,8 @@ export class ClipboardBasedVariableResolver implements VariableResolver { constructor( private readonly _clipboardText: string | undefined, private readonly _selectionIdx: number, - private readonly _selectionCount: number + private readonly _selectionCount: number, + private readonly _spread: boolean ) { // } @@ -183,12 +184,16 @@ export class ClipboardBasedVariableResolver implements VariableResolver { return undefined; } - const lines = this._clipboardText.split(/\r\n|\n|\r/).filter(s => !isFalsyOrWhitespace(s)); - if (lines.length === this._selectionCount) { - return lines[this._selectionIdx]; - } else { - return this._clipboardText; + // `spread` is assigning each cursor a line of the clipboard + // text whenever there the line count equals the cursor count + // and when enabled + if (this._spread) { + const lines = this._clipboardText.split(/\r\n|\n|\r/).filter(s => !isFalsyOrWhitespace(s)); + if (lines.length === this._selectionCount) { + return lines[this._selectionIdx]; + } } + return this._clipboardText; } } export class CommentBasedVariableResolver implements VariableResolver { diff --git a/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts b/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts index b7d5c40b8bf..0189cc0de2e 100644 --- a/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts @@ -236,26 +236,28 @@ suite('Snippet Variables Resolver', function () { test('Add variable to insert value from clipboard to a snippet #40153', function () { - assertVariableResolve(new ClipboardBasedVariableResolver(undefined, 1, 0), 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver(undefined, 1, 0, true), 'CLIPBOARD', undefined); - assertVariableResolve(new ClipboardBasedVariableResolver(null!, 1, 0), 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver(null!, 1, 0, true), 'CLIPBOARD', undefined); - assertVariableResolve(new ClipboardBasedVariableResolver('', 1, 0), 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver('', 1, 0, true), 'CLIPBOARD', undefined); - assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0), 'CLIPBOARD', 'foo'); + assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0, true), 'CLIPBOARD', 'foo'); - assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0), 'foo', undefined); - assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0), 'cLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0, true), 'foo', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0, true), 'cLIPBOARD', undefined); }); test('Add variable to insert value from clipboard to a snippet #40153', function () { - assertVariableResolve(new ClipboardBasedVariableResolver('line1', 1, 2), 'CLIPBOARD', 'line1'); - assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2\nline3', 1, 2), 'CLIPBOARD', 'line1\nline2\nline3'); + assertVariableResolve(new ClipboardBasedVariableResolver('line1', 1, 2, true), 'CLIPBOARD', 'line1'); + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2\nline3', 1, 2, true), 'CLIPBOARD', 'line1\nline2\nline3'); - assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 1, 2), 'CLIPBOARD', 'line2'); - resolver = new ClipboardBasedVariableResolver('line1\nline2', 0, 2); - assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 0, 2), 'CLIPBOARD', 'line1'); + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 1, 2, true), 'CLIPBOARD', 'line2'); + resolver = new ClipboardBasedVariableResolver('line1\nline2', 0, 2, true); + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 0, 2, true), 'CLIPBOARD', 'line1'); + + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 0, 2, false), 'CLIPBOARD', 'line1\nline2'); }); diff --git a/src/vs/editor/contrib/suggest/completionModel.ts b/src/vs/editor/contrib/suggest/completionModel.ts index 9a806ddf3de..f1bbdb462f7 100644 --- a/src/vs/editor/contrib/suggest/completionModel.ts +++ b/src/vs/editor/contrib/suggest/completionModel.ts @@ -6,7 +6,7 @@ import { fuzzyScore, fuzzyScoreGracefulAggressive, FuzzyScorer, FuzzyScore, anyScore } from 'vs/base/common/filters'; import { CompletionItemProvider, CompletionItemKind } from 'vs/editor/common/modes'; import { CompletionItem } from './suggest'; -import { InternalSuggestOptions, EDITOR_DEFAULTS } from 'vs/editor/common/config/editorOptions'; +import { InternalSuggestOptions } from 'vs/editor/common/config/editorOptions'; import { WordDistance } from 'vs/editor/contrib/suggest/wordDistance'; import { CharCode } from 'vs/base/common/charCode'; import { compareIgnoreCase } from 'vs/base/common/strings'; @@ -60,7 +60,8 @@ export class CompletionModel { column: number, lineContext: LineContext, wordDistance: WordDistance, - options: InternalSuggestOptions = EDITOR_DEFAULTS.contribInfo.suggest + options: InternalSuggestOptions, + snippetSuggestions: 'top' | 'bottom' | 'inline' | 'none' ) { this._items = items; this._column = column; @@ -69,9 +70,9 @@ export class CompletionModel { this._refilterKind = Refilter.All; this._lineContext = lineContext; - if (options.snippets === 'top') { + if (snippetSuggestions === 'top') { this._snippetCompareFn = CompletionModel._compareCompletionItemsSnippetsUp; - } else if (options.snippets === 'bottom') { + } else if (snippetSuggestions === 'bottom') { this._snippetCompareFn = CompletionModel._compareCompletionItemsSnippetsDown; } } diff --git a/src/vs/editor/contrib/suggest/suggest.ts b/src/vs/editor/contrib/suggest/suggest.ts index d905bdb1a01..09f1b9a4d06 100644 --- a/src/vs/editor/contrib/suggest/suggest.ts +++ b/src/vs/editor/contrib/suggest/suggest.ts @@ -161,6 +161,10 @@ export function provideSuggestionItems( if (!suggestion.range) { suggestion.range = defaultRange; } + // fill in default sortText when missing + if (!suggestion.sortText) { + suggestion.sortText = suggestion.label; + } allSuggestions.push(new CompletionItem(position, suggestion, container, provider, model)); } diff --git a/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts index 20a7656532a..3831500a4f8 100644 --- a/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts +++ b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts @@ -8,6 +8,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ISelectedSuggestion, SuggestWidget } from './suggestWidget'; import { CharacterSet } from 'vs/editor/common/core/characterClassifier'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class CommitCharacterController { @@ -27,7 +28,7 @@ export class CommitCharacterController { this._disposables.add(editor.onWillType(text => { if (this._active) { const ch = text.charCodeAt(text.length - 1); - if (this._active.acceptCharacters.has(ch) && editor.getConfiguration().contribInfo.acceptSuggestionOnCommitCharacter) { + if (this._active.acceptCharacters.has(ch) && editor.getOption(EditorOption.acceptSuggestionOnCommitCharacter)) { accept(this._active.item); } } diff --git a/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts index a86c5148d2c..e8bc0699c82 100644 --- a/src/vs/editor/contrib/suggest/suggestController.ts +++ b/src/vs/editor/contrib/suggest/suggestController.ts @@ -35,6 +35,7 @@ import { isObject } from 'vs/base/common/types'; import { CommitCharacterController } from './suggestCommitCharacters'; import { IPosition } from 'vs/editor/common/core/position'; import { TrackedRangeStickiness, ITextModel } from 'vs/editor/common/model'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const _sticky = false; // for development purposes only @@ -129,7 +130,7 @@ export class SuggestController implements IEditorContribution { const endColumn = position.column; let value = true; if ( - this._editor.getConfiguration().contribInfo.acceptSuggestionOnEnter === 'smart' + this._editor.getOption(EditorOption.acceptSuggestionOnEnter) === 'smart' && this._model.state === State.Auto && !item.completion.command && !item.completion.additionalTextEdits @@ -182,7 +183,7 @@ export class SuggestController implements IEditorContribution { // Manage the acceptSuggestionsOnEnter context key let acceptSuggestionsOnEnter = SuggestContext.AcceptSuggestionsOnEnter.bindTo(_contextKeyService); let updateFromConfig = () => { - const { acceptSuggestionOnEnter } = this._editor.getConfiguration().contribInfo; + const acceptSuggestionOnEnter = this._editor.getOption(EditorOption.acceptSuggestionOnEnter); acceptSuggestionsOnEnter.set(acceptSuggestionOnEnter === 'on' || acceptSuggestionOnEnter === 'smart'); }; this._toDispose.add(this._editor.onDidChangeConfiguration(() => updateFromConfig())); diff --git a/src/vs/editor/contrib/suggest/suggestModel.ts b/src/vs/editor/contrib/suggest/suggestModel.ts index d34f911cea8..8ab8749f4f0 100644 --- a/src/vs/editor/contrib/suggest/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/suggestModel.ts @@ -20,6 +20,7 @@ import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2 import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import { WordDistance } from 'vs/editor/contrib/suggest/wordDistance'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface ICancelEvent { readonly retrigger: boolean; @@ -172,7 +173,7 @@ export class SuggestModel implements IDisposable { // --- handle configuration & precondition changes private _updateQuickSuggest(): void { - this._quickSuggestDelay = this._editor.getConfiguration().contribInfo.quickSuggestionsDelay; + this._quickSuggestDelay = this._editor.getOption(EditorOption.quickSuggestionsDelay); if (isNaN(this._quickSuggestDelay) || (!this._quickSuggestDelay && this._quickSuggestDelay !== 0) || this._quickSuggestDelay < 0) { this._quickSuggestDelay = 10; @@ -183,9 +184,9 @@ export class SuggestModel implements IDisposable { dispose(this._triggerCharacterListener); - if (this._editor.getConfiguration().readOnly + if (this._editor.getOption(EditorOption.readOnly) || !this._editor.hasModel() - || !this._editor.getConfiguration().contribInfo.suggestOnTriggerCharacters) { + || !this._editor.getOption(EditorOption.suggestOnTriggerCharacters)) { return; } @@ -277,7 +278,7 @@ export class SuggestModel implements IDisposable { if (this._state === State.Idle) { - if (this._editor.getConfiguration().contribInfo.quickSuggestions === false) { + if (this._editor.getOption(EditorOption.quickSuggestions) === false) { // not enabled return; } @@ -287,7 +288,7 @@ export class SuggestModel implements IDisposable { return; } - if (this._editor.getConfiguration().contribInfo.suggest.snippetsPreventQuickSuggestions && SnippetController2.get(this._editor).isInSnippet()) { + if (this._editor.getOption(EditorOption.suggest).snippetsPreventQuickSuggestions && SnippetController2.get(this._editor).isInSnippet()) { // no quick suggestion when in snippet mode return; } @@ -307,7 +308,7 @@ export class SuggestModel implements IDisposable { const model = this._editor.getModel(); const pos = this._editor.getPosition(); // validate enabled now - const { quickSuggestions } = this._editor.getConfiguration().contribInfo; + const quickSuggestions = this._editor.getOption(EditorOption.quickSuggestions); if (quickSuggestions === false) { return; } else if (quickSuggestions === true) { @@ -387,10 +388,11 @@ export class SuggestModel implements IDisposable { this._requestToken = new CancellationTokenSource(); // kind filter and snippet sort rules - const { contribInfo } = this._editor.getConfiguration(); + const suggestOptions = this._editor.getOption(EditorOption.suggest); + const snippetSuggestions = this._editor.getOption(EditorOption.snippetSuggestions); let itemKindFilter = new Set(); let snippetSortOrder = SnippetSortOrder.Inline; - switch (contribInfo.suggest.snippets) { + switch (snippetSuggestions) { case 'top': snippetSortOrder = SnippetSortOrder.Top; break; @@ -407,9 +409,9 @@ export class SuggestModel implements IDisposable { } // kind filter - for (const key in contribInfo.suggest.filteredTypes) { + for (const key in suggestOptions.filteredTypes) { const kind = completionKindFromString(key, true); - if (typeof kind !== 'undefined' && contribInfo.suggest.filteredTypes[key] === false) { + if (typeof kind !== 'undefined' && suggestOptions.filteredTypes[key] === false) { itemKindFilter.add(kind); } } @@ -449,7 +451,8 @@ export class SuggestModel implements IDisposable { characterCountDelta: ctx.column - this._context!.column }, wordDistance, - this._editor.getConfiguration().contribInfo.suggest + this._editor.getOption(EditorOption.suggest), + this._editor.getOption(EditorOption.snippetSuggestions) ); // store containers so that they can be disposed later diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 4bb095d5d41..fa7198d184c 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -16,7 +16,7 @@ import { List } from 'vs/base/browser/ui/list/listWidget'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { Context as SuggestContext, CompletionItem } from './suggest'; import { CompletionModel } from './completionModel'; @@ -124,11 +124,12 @@ class Renderer implements IListRenderer data.readMore.title = nls.localize('readMore', "Read More...{0}", this.triggerKeybindingLabel); const configureFont = () => { - const configuration = this.editor.getConfiguration(); - const fontFamily = configuration.fontInfo.fontFamily; - const fontSize = configuration.contribInfo.suggestFontSize || configuration.fontInfo.fontSize; - const lineHeight = configuration.contribInfo.suggestLineHeight || configuration.fontInfo.lineHeight; - const fontWeight = configuration.fontInfo.fontWeight; + const options = this.editor.getOptions(); + const fontInfo = options.get(EditorOption.fontInfo); + const fontFamily = fontInfo.fontFamily; + const fontSize = options.get(EditorOption.suggestFontSize) || fontInfo.fontSize; + const lineHeight = options.get(EditorOption.suggestLineHeight) || fontInfo.lineHeight; + const fontWeight = fontInfo.fontWeight; const fontSizePx = `${fontSize}px`; const lineHeightPx = `${lineHeight}px`; @@ -144,8 +145,8 @@ class Renderer implements IListRenderer configureFont(); - data.disposables.add(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) - .filter(e => e.fontInfo || e.contribInfo) + data.disposables.add(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + .filter(e => e.hasChanged(EditorOption.fontInfo) || e.hasChanged(EditorOption.suggestFontSize) || e.hasChanged(EditorOption.suggestLineHeight)) .on(configureFont, null)); return data; @@ -276,8 +277,8 @@ class SuggestionDetails { this.configureFont(); - Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) - .filter(e => e.fontInfo) + Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + .filter(e => e.hasChanged(EditorOption.fontInfo)) .on(this.configureFont, this, this.disposables); markdownRenderer.onDidRenderCodeBlock(() => this.scrollbar.scanDomNode(), this, this.disposables); @@ -389,11 +390,12 @@ class SuggestionDetails { } private configureFont() { - const configuration = this.editor.getConfiguration(); - const fontFamily = configuration.fontInfo.fontFamily; - const fontSize = configuration.contribInfo.suggestFontSize || configuration.fontInfo.fontSize; - const lineHeight = configuration.contribInfo.suggestLineHeight || configuration.fontInfo.lineHeight; - const fontWeight = configuration.fontInfo.fontWeight; + const options = this.editor.getOptions(); + const fontInfo = options.get(EditorOption.fontInfo); + const fontFamily = fontInfo.fontFamily; + const fontSize = options.get(EditorOption.suggestFontSize) || fontInfo.fontSize; + const lineHeight = options.get(EditorOption.suggestLineHeight) || fontInfo.lineHeight; + const fontWeight = fontInfo.fontWeight; const fontSizePx = `${fontSize}px`; const lineHeightPx = `${lineHeight}px`; @@ -500,7 +502,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate toggleClass(this.element, 'no-icons', !this.editor.getConfiguration().contribInfo.suggest.showIcons); + const applyIconStyle = () => toggleClass(this.element, 'no-icons', !this.editor.getOption(EditorOption.suggest).showIcons); applyIconStyle(); let renderer = instantiationService.createInstance(Renderer, this, this.editor, triggerKeybindingLabel); @@ -521,7 +523,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate this.onListSelection(e))); this.toDispose.add(this.list.onFocusChange(e => this.onListFocus(e))); this.toDispose.add(this.editor.onDidChangeCursorSelection(() => this.onCursorSelectionChanged())); - this.toDispose.add(this.editor.onDidChangeConfiguration(e => e.contribInfo && applyIconStyle())); + this.toDispose.add(this.editor.onDidChangeConfiguration(e => e.hasChanged(EditorOption.suggest) && applyIconStyle())); this.suggestWidgetVisible = SuggestContext.Visible.bindTo(contextKeyService); @@ -1051,7 +1053,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate e.contribInfo && this._update())); + this._register(this._editor.onDidChangeConfiguration(e => e.hasChanged(EditorOption.tabCompletion) && this._update())); this._update(); } @@ -34,7 +35,7 @@ export class WordContextKey extends Disposable { private _update(): void { // only update this when tab completions are enabled - const enabled = this._editor.getConfiguration().contribInfo.tabCompletion === 'on'; + const enabled = this._editor.getOption(EditorOption.tabCompletion) === 'on'; if (this._enabled === enabled) { return; } diff --git a/src/vs/editor/contrib/suggest/wordDistance.ts b/src/vs/editor/contrib/suggest/wordDistance.ts index e67bc3527c6..fb1901260d2 100644 --- a/src/vs/editor/contrib/suggest/wordDistance.ts +++ b/src/vs/editor/contrib/suggest/wordDistance.ts @@ -10,6 +10,7 @@ import { IPosition } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { CompletionItem, CompletionItemKind } from 'vs/editor/common/modes'; import { BracketSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/bracketSelections'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export abstract class WordDistance { @@ -19,7 +20,7 @@ export abstract class WordDistance { static async create(service: IEditorWorkerService, editor: ICodeEditor): Promise { - if (!editor.getConfiguration().contribInfo.suggest.localityBonus) { + if (!editor.getOption(EditorOption.suggest).localityBonus) { return WordDistance.None; } diff --git a/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts index 4fd4f5d2db0..11cbf87647c 100644 --- a/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts @@ -26,6 +26,7 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { activeContrastBorder, editorSelectionHighlight, editorSelectionHighlightBorder, overviewRulerSelectionHighlightForeground, registerColor } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant, themeColorFromId } from 'vs/platform/theme/common/themeService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const editorWordHighlight = registerColor('editor.wordHighlightBackground', { dark: '#575757B8', light: '#57575740', hc: null }, nls.localize('wordHighlight', 'Background color of a symbol during read-access, like reading a variable. The color must not be opaque so as not to hide underlying decorations.'), true); export const editorWordHighlightStrong = registerColor('editor.wordHighlightStrongBackground', { dark: '#004972B8', light: '#0e639c40', hc: null }, nls.localize('wordHighlightStrong', 'Background color of a symbol during write-access, like writing to a variable. The color must not be opaque so as not to hide underlying decorations.'), true); @@ -181,7 +182,7 @@ class WordHighlighter { this.editor = editor; this._hasWordHighlights = ctxHasWordHighlights.bindTo(contextKeyService); this._ignorePositionChangeEvent = false; - this.occurrencesHighlight = this.editor.getConfiguration().contribInfo.occurrencesHighlight; + this.occurrencesHighlight = this.editor.getOption(EditorOption.occurrencesHighlight); this.model = this.editor.getModel(); this.toUnhook.add(editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { @@ -202,7 +203,7 @@ class WordHighlighter { this._stopAll(); })); this.toUnhook.add(editor.onDidChangeConfiguration((e) => { - let newValue = this.editor.getConfiguration().contribInfo.occurrencesHighlight; + let newValue = this.editor.getOption(EditorOption.occurrencesHighlight); if (this.occurrencesHighlight !== newValue) { this.occurrencesHighlight = newValue; this._stopAll(); @@ -371,7 +372,7 @@ class WordHighlighter { let myRequestId = ++this.workerRequestTokenId; this.workerRequestCompleted = false; - this.workerRequest = computeOccurencesAtPosition(this.model, this.editor.getSelection(), this.editor.getConfiguration().wordSeparators); + this.workerRequest = computeOccurencesAtPosition(this.model, this.editor.getSelection(), this.editor.getOption(EditorOption.wordSeparators)); this.workerRequest.result.then(data => { if (myRequestId === this.workerRequestTokenId) { diff --git a/src/vs/editor/contrib/wordOperations/wordOperations.ts b/src/vs/editor/contrib/wordOperations/wordOperations.ts index a0e5e226cdd..5e77d1c0607 100644 --- a/src/vs/editor/contrib/wordOperations/wordOperations.ts +++ b/src/vs/editor/contrib/wordOperations/wordOperations.ts @@ -20,7 +20,7 @@ import { ITextModel } from 'vs/editor/common/model'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { EDITOR_DEFAULTS } from 'vs/editor/common/config/editorOptions'; +import { EditorOption, EditorOptions } from 'vs/editor/common/config/editorOptions'; export interface MoveWordOptions extends ICommandOptions { inSelectionMode: boolean; @@ -42,8 +42,7 @@ export abstract class MoveWordCommand extends EditorCommand { if (!editor.hasModel()) { return; } - const config = editor.getConfiguration(); - const wordSeparators = getMapForWordSeparators(config.wordSeparators); + const wordSeparators = getMapForWordSeparators(editor.getOption(EditorOption.wordSeparators)); const model = editor.getModel(); const selections = editor.getSelections(); @@ -190,7 +189,7 @@ export class CursorWordAccessibilityLeft extends WordLeftCommand { } protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position { - return super._move(getMapForWordSeparators(EDITOR_DEFAULTS.wordSeparators), model, position, wordNavigationType); + return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType); } } @@ -211,7 +210,7 @@ export class CursorWordAccessibilityLeftSelect extends WordLeftCommand { } protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position { - return super._move(getMapForWordSeparators(EDITOR_DEFAULTS.wordSeparators), model, position, wordNavigationType); + return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType); } } @@ -310,7 +309,7 @@ export class CursorWordAccessibilityRight extends WordRightCommand { } protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position { - return super._move(getMapForWordSeparators(EDITOR_DEFAULTS.wordSeparators), model, position, wordNavigationType); + return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType); } } @@ -331,7 +330,7 @@ export class CursorWordAccessibilityRightSelect extends WordRightCommand { } protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position { - return super._move(getMapForWordSeparators(EDITOR_DEFAULTS.wordSeparators), model, position, wordNavigationType); + return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType); } } @@ -354,8 +353,7 @@ export abstract class DeleteWordCommand extends EditorCommand { if (!editor.hasModel()) { return; } - const config = editor.getConfiguration(); - const wordSeparators = getMapForWordSeparators(config.wordSeparators); + const wordSeparators = getMapForWordSeparators(editor.getOption(EditorOption.wordSeparators)); const model = editor.getModel(); const selections = editor.getSelections(); diff --git a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts index 703706bf238..f464b2b14f3 100644 --- a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts @@ -11,7 +11,7 @@ import { IdGenerator } from 'vs/base/common/idGenerator'; import { DisposableStore } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, IViewZone, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser'; -import { EditorLayoutInfo } from 'vs/editor/common/config/editorOptions'; +import { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { ScrollType } from 'vs/editor/common/editorCommon'; @@ -334,7 +334,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { } private _decoratingElementsHeight(): number { - let lineHeight = this.editor.getConfiguration().lineHeight; + let lineHeight = this.editor.getOption(EditorOption.lineHeight); let result = 0; if (this.options.showArrow) { @@ -364,7 +364,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { // Render the widget as zone (rendering) and widget (lifecycle) const viewZoneDomNode = document.createElement('div'); viewZoneDomNode.style.overflow = 'hidden'; - const lineHeight = this.editor.getConfiguration().lineHeight; + const lineHeight = this.editor.getOption(EditorOption.lineHeight); // adjust heightInLines to viewport const maxHeightInLines = (this.editor.getLayoutInfo().height / lineHeight) * 0.8; @@ -505,7 +505,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { this._disposables.add(this._resizeSash.onDidChange((evt: ISashEvent) => { if (data) { - let lineDelta = (evt.currentY - data.startY) / this.editor.getConfiguration().lineHeight; + let lineDelta = (evt.currentY - data.startY) / this.editor.getOption(EditorOption.lineHeight); let roundedLineDelta = lineDelta < 0 ? Math.ceil(lineDelta) : Math.floor(lineDelta); let newHeightInLines = data.heightInLines + roundedLineDelta; diff --git a/src/vs/editor/editor.api.ts b/src/vs/editor/editor.api.ts index e535b3e4456..c113019ab2f 100644 --- a/src/vs/editor/editor.api.ts +++ b/src/vs/editor/editor.api.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { EDITOR_DEFAULTS, WrappingIndent } from 'vs/editor/common/config/editorOptions'; +import { EditorOptions, WrappingIndent } from 'vs/editor/common/config/editorOptions'; import { createMonacoBaseAPI } from 'vs/editor/common/standalone/standaloneBase'; import { createMonacoEditorAPI } from 'vs/editor/standalone/browser/standaloneEditor'; import { createMonacoLanguagesAPI } from 'vs/editor/standalone/browser/standaloneLanguages'; @@ -11,9 +11,10 @@ import { createMonacoLanguagesAPI } from 'vs/editor/standalone/browser/standalon const global: any = self; // Set defaults for standalone editor -(EDITOR_DEFAULTS).wrappingIndent = WrappingIndent.None; -(EDITOR_DEFAULTS.viewInfo).glyphMargin = false; -(EDITOR_DEFAULTS).autoIndent = false; +(EditorOptions.wrappingIndent).defaultValue = WrappingIndent.None; +(EditorOptions.glyphMargin).defaultValue = false; +(EditorOptions.autoIndent).defaultValue = false; +(EditorOptions.overviewRulerLanes).defaultValue = 2; const api = createMonacoBaseAPI(); api.editor = createMonacoEditorAPI(); diff --git a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts index 1981153c0c8..1b1104e5074 100644 --- a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts +++ b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts @@ -31,6 +31,7 @@ import { contrastBorder, editorWidgetBackground, widgetShadow, editorWidgetForeg import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { AccessibilityHelpNLS } from 'vs/editor/common/standaloneStrings'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const CONTEXT_ACCESSIBILITY_WIDGET_VISIBLE = new RawContextKey('accessibilityHelpWidgetVisible', false); @@ -163,7 +164,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { if (e.equals(KeyMod.CtrlCmd | KeyCode.KEY_H)) { alert(AccessibilityHelpNLS.openingDocs); - let url = (this._editor.getRawConfiguration()).accessibilityHelpUrl; + let url = (this._editor.getRawOptions()).accessibilityHelpUrl; if (typeof url === 'undefined') { url = 'https://go.microsoft.com/fwlink/?linkid=852450'; } @@ -223,7 +224,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { } private _buildContent() { - let opts = this._editor.getConfiguration(); + const options = this._editor.getOptions(); const selections = this._editor.getSelections(); let charactersSelected = 0; @@ -239,14 +240,14 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { let text = getSelectionLabel(selections, charactersSelected); - if (opts.wrappingInfo.inDiffEditor) { - if (opts.readOnly) { + if (options.get(EditorOption.inDiffEditor)) { + if (options.get(EditorOption.readOnly)) { text += AccessibilityHelpNLS.readonlyDiffEditor; } else { text += AccessibilityHelpNLS.editableDiffEditor; } } else { - if (opts.readOnly) { + if (options.get(EditorOption.readOnly)) { text += AccessibilityHelpNLS.readonlyEditor; } else { text += AccessibilityHelpNLS.editableEditor; @@ -258,7 +259,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { ? AccessibilityHelpNLS.changeConfigToOnMac : AccessibilityHelpNLS.changeConfigToOnWinLinux ); - switch (opts.accessibilitySupport) { + switch (options.get(EditorOption.accessibilitySupport)) { case AccessibilitySupport.Unknown: text += '\n\n - ' + turnOnMessage; break; @@ -272,7 +273,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { } - if (opts.tabFocusMode) { + if (options.get(EditorOption.tabFocusMode)) { text += '\n\n - ' + this._descriptionForCommand(ToggleTabFocusModeAction.ID, AccessibilityHelpNLS.tabFocusModeOnMsg, AccessibilityHelpNLS.tabFocusModeOnMsgNoKb); } else { text += '\n\n - ' + this._descriptionForCommand(ToggleTabFocusModeAction.ID, AccessibilityHelpNLS.tabFocusModeOffMsg, AccessibilityHelpNLS.tabFocusModeOffMsgNoKb); diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts index b36f6ecdc23..82ccd6a63f7 100644 --- a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts +++ b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts @@ -10,6 +10,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class IPadShowKeyboard extends Disposable implements IEditorContribution { @@ -29,7 +30,7 @@ export class IPadShowKeyboard extends Disposable implements IEditorContribution } private update(): void { - const shouldHaveWidget = (!this.editor.getConfiguration().readOnly); + const shouldHaveWidget = (!this.editor.getOption(EditorOption.readOnly)); if (!this.widget && shouldHaveWidget) { diff --git a/src/vs/editor/standalone/browser/standaloneEditor.ts b/src/vs/editor/standalone/browser/standaloneEditor.ts index 11b8580e4e2..a9457f62a30 100644 --- a/src/vs/editor/standalone/browser/standaloneEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneEditor.ts @@ -10,7 +10,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { OpenerService } from 'vs/editor/browser/services/openerService'; import { DiffNavigator } from 'vs/editor/browser/widget/diffNavigator'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import { Token } from 'vs/editor/common/core/token'; import * as editorCommon from 'vs/editor/common/editorCommon'; @@ -351,6 +351,7 @@ export function createMonacoEditorAPI(): typeof monaco.editor { remeasureFonts: remeasureFonts, // enums + AccessibilitySupport: standaloneEnums.AccessibilitySupport, ScrollbarVisibility: standaloneEnums.ScrollbarVisibility, WrappingIndent: standaloneEnums.WrappingIndent, OverviewRulerLane: standaloneEnums.OverviewRulerLane, @@ -370,14 +371,14 @@ export function createMonacoEditorAPI(): typeof monaco.editor { RenderLineNumbersType: standaloneEnums.RenderLineNumbersType, // classes - InternalEditorOptions: editorOptions.InternalEditorOptions, + ConfigurationChangedEvent: ConfigurationChangedEvent, BareFontInfo: BareFontInfo, FontInfo: FontInfo, TextModelResolvedOptions: TextModelResolvedOptions, FindMatch: FindMatch, // vars - EditorType: editorCommon.EditorType + EditorType: editorCommon.EditorType, }; } diff --git a/src/vs/editor/test/browser/controller/cursor.test.ts b/src/vs/editor/test/browser/controller/cursor.test.ts index eff8a24373f..984a1e23856 100644 --- a/src/vs/editor/test/browser/controller/cursor.test.ts +++ b/src/vs/editor/test/browser/controller/cursor.test.ts @@ -711,7 +711,7 @@ suite('Editor Controller - Cursor', () => { position: new Position(4, 4), viewPosition: new Position(4, 4), mouseColumn: 15, - setAnchorIfNotSet: false + doColumnSelect: true }); let expectedSelections = [ @@ -747,7 +747,7 @@ suite('Editor Controller - Cursor', () => { position: new Position(4, 1), viewPosition: new Position(4, 1), mouseColumn: 1, - setAnchorIfNotSet: false + doColumnSelect: true }); assertCursor(cursor, [ @@ -787,7 +787,7 @@ suite('Editor Controller - Cursor', () => { position: new Position(1, 1), viewPosition: new Position(1, 1), mouseColumn: 1, - setAnchorIfNotSet: false + doColumnSelect: true }); assertCursor(cursor, [ new Selection(10, 10, 10, 1), @@ -806,7 +806,7 @@ suite('Editor Controller - Cursor', () => { position: new Position(1, 1), viewPosition: new Position(1, 1), mouseColumn: 1, - setAnchorIfNotSet: false + doColumnSelect: true }); assertCursor(cursor, [ new Selection(10, 10, 10, 1), @@ -1566,6 +1566,37 @@ suite('Editor Controller - Regression tests', () => { }); }); + test('issue #43722: Multiline paste doesn\'t work anymore', () => { + usingCursor({ + text: [ + 'test', + 'test', + 'test', + 'test' + ], + }, (model, cursor) => { + cursor.setSelections('test', [ + new Selection(1, 1, 1, 5), + new Selection(2, 1, 2, 5), + new Selection(3, 1, 3, 5), + new Selection(4, 1, 4, 5), + ]); + + cursorCommand(cursor, H.Paste, { + text: 'aaa\r\nbbb\r\nccc\r\nddd\r\n', + pasteOnNewLine: false, + multicursorText: null + }); + + assert.equal(model.getValue(), [ + 'aaa', + 'bbb', + 'ccc', + 'ddd', + ].join('\n')); + }); + }); + test('issue #46440: (1) Pasting a multi-line selection pastes entire selection into every insertion point', () => { usingCursor({ text: [ diff --git a/src/vs/editor/test/browser/testCodeEditor.ts b/src/vs/editor/test/browser/testCodeEditor.ts index bf7ceae25a5..39a84d3acb2 100644 --- a/src/vs/editor/test/browser/testCodeEditor.ts +++ b/src/vs/editor/test/browser/testCodeEditor.ts @@ -91,7 +91,12 @@ export function withTestCodeEditor(text: string | string[] | null, options: Test export function createTestCodeEditor(options: TestCodeEditorCreationOptions): TestCodeEditor { + const model = options.model; + delete options.model; + const services: ServiceCollection = options.serviceCollection || new ServiceCollection(); + delete options.serviceCollection; + const instantiationService: IInstantiationService = new InstantiationService(services); if (!services.has(ICodeEditorService)) { @@ -119,6 +124,6 @@ export function createTestCodeEditor(options: TestCodeEditorCreationOptions): Te options, codeEditorWidgetOptions ); - editor.setModel(options.model); + editor.setModel(model); return editor; } diff --git a/src/vs/editor/test/common/config/commonEditorConfig.test.ts b/src/vs/editor/test/common/config/commonEditorConfig.test.ts index b35959ae2c2..0608fa6476e 100644 --- a/src/vs/editor/test/common/config/commonEditorConfig.test.ts +++ b/src/vs/editor/test/common/config/commonEditorConfig.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig'; -import { IEditorHoverOptions } from 'vs/editor/common/config/editorOptions'; +import { IEditorHoverOptions, EditorOption, ConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import { EditorZoom } from 'vs/editor/common/config/editorZoom'; import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; @@ -67,8 +67,10 @@ suite('Common Editor Config', () => { } function assertWrapping(config: TestConfiguration, isViewportWrapping: boolean, wrappingColumn: number): void { - assert.equal(config.editor.wrappingInfo.isViewportWrapping, isViewportWrapping); - assert.equal(config.editor.wrappingInfo.wrappingColumn, wrappingColumn); + const options = config.options; + const wrappingInfo = options.get(EditorOption.wrappingInfo); + assert.equal(wrappingInfo.isViewportWrapping, isViewportWrapping); + assert.equal(wrappingInfo.wrappingColumn, wrappingColumn); } test('wordWrap default', () => { @@ -184,8 +186,19 @@ suite('Common Editor Config', () => { }); let config = new TestConfiguration({ hover: hoverOptions }); - assert.equal(config.editor.contribInfo.hover.enabled, true); + assert.equal(config.options.get(EditorOption.hover).enabled, true); config.updateOptions({ hover: { enabled: false } }); - assert.equal(config.editor.contribInfo.hover.enabled, false); + assert.equal(config.options.get(EditorOption.hover).enabled, false); + }); + + test('does not emit event when nothing changes', () => { + const config = new TestConfiguration({ glyphMargin: true, roundedSelection: false }); + let event: ConfigurationChangedEvent | null = null; + config.onDidChange(e => event = e); + assert.equal(config.options.get(EditorOption.glyphMargin), true); + + config.updateOptions({ glyphMargin: true }); + config.updateOptions({ roundedSelection: false }); + assert.equal(event, null); }); }); diff --git a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts index f88e9e1e875..793ab31cf7f 100644 --- a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts +++ b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts @@ -4,12 +4,82 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { EditorLayoutInfo, EditorLayoutProvider, IEditorLayoutProviderOpts, RenderMinimap } from 'vs/editor/common/config/editorOptions'; +import { EditorLayoutInfo, EditorLayoutInfoComputer, RenderMinimap, EditorOption, EditorMinimapOptions, InternalEditorScrollbarOptions, EditorOptions, RenderLineNumbersType, InternalEditorRenderLineNumbersOptions } from 'vs/editor/common/config/editorOptions'; +import { ComputedEditorOptions } from 'vs/editor/common/config/commonEditorConfig'; + +interface IEditorLayoutProviderOpts { + readonly outerWidth: number; + readonly outerHeight: number; + + readonly showGlyphMargin: boolean; + readonly lineHeight: number; + + readonly showLineNumbers: boolean; + readonly lineNumbersMinChars: number; + readonly lineNumbersDigitCount: number; + + readonly lineDecorationsWidth: number; + + readonly typicalHalfwidthCharacterWidth: number; + readonly maxDigitWidth: number; + + readonly verticalScrollbarWidth: number; + readonly verticalScrollbarHasArrows: boolean; + readonly scrollbarArrowSize: number; + readonly horizontalScrollbarHeight: number; + + readonly minimap: boolean; + readonly minimapSide: 'left' | 'right'; + readonly minimapRenderCharacters: boolean; + readonly minimapMaxColumn: number; + readonly pixelRatio: number; +} suite('Editor ViewLayout - EditorLayoutProvider', () => { function doTest(input: IEditorLayoutProviderOpts, expected: EditorLayoutInfo): void { - let actual = EditorLayoutProvider.compute(input); + const options = new ComputedEditorOptions(); + options._write(EditorOption.glyphMargin, input.showGlyphMargin); + options._write(EditorOption.lineNumbersMinChars, input.lineNumbersMinChars); + options._write(EditorOption.lineDecorationsWidth, input.lineDecorationsWidth); + options._write(EditorOption.folding, false); + const minimapOptions: EditorMinimapOptions = { + enabled: input.minimap, + side: input.minimapSide, + renderCharacters: input.minimapRenderCharacters, + maxColumn: input.minimapMaxColumn, + showSlider: 'mouseover' + }; + options._write(EditorOption.minimap, minimapOptions); + const scrollbarOptions: InternalEditorScrollbarOptions = { + arrowSize: input.scrollbarArrowSize, + vertical: EditorOptions.scrollbar.defaultValue.vertical, + horizontal: EditorOptions.scrollbar.defaultValue.horizontal, + useShadows: EditorOptions.scrollbar.defaultValue.useShadows, + verticalHasArrows: input.verticalScrollbarHasArrows, + horizontalHasArrows: false, + handleMouseWheel: EditorOptions.scrollbar.defaultValue.handleMouseWheel, + horizontalScrollbarSize: input.horizontalScrollbarHeight, + horizontalSliderSize: EditorOptions.scrollbar.defaultValue.horizontalSliderSize, + verticalScrollbarSize: input.verticalScrollbarWidth, + verticalSliderSize: EditorOptions.scrollbar.defaultValue.verticalSliderSize, + }; + options._write(EditorOption.scrollbar, scrollbarOptions); + const lineNumbersOptions: InternalEditorRenderLineNumbersOptions = { + renderType: input.showLineNumbers ? RenderLineNumbersType.On : RenderLineNumbersType.Off, + renderFn: null + }; + options._write(EditorOption.lineNumbers, lineNumbersOptions); + + const actual = EditorLayoutInfoComputer.computeLayout(options, { + outerWidth: input.outerWidth, + outerHeight: input.outerHeight, + lineHeight: input.lineHeight, + lineNumbersDigitCount: input.lineNumbersDigitCount, + typicalHalfwidthCharacterWidth: input.typicalHalfwidthCharacterWidth, + maxDigitWidth: input.maxDigitWidth, + pixelRatio: input.pixelRatio, + }); assert.deepEqual(actual, expected); } diff --git a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts index 9b053429da8..d57bcaecded 100644 --- a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts +++ b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts @@ -19,6 +19,8 @@ import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer' import { ILineMapping, ISimpleModel, SplitLine, SplitLinesCollection } from 'vs/editor/common/viewModel/splitLinesCollection'; import { ViewLineData } from 'vs/editor/common/viewModel/viewModel'; import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; + suite('Editor ViewModel - SplitLinesCollection', () => { test('SplitLine', () => { @@ -88,15 +90,21 @@ suite('Editor ViewModel - SplitLinesCollection', () => { }); function withSplitLinesCollection(text: string, callback: (model: TextModel, linesCollection: SplitLinesCollection) => void): void { - let config = new TestConfiguration({}); + const config = new TestConfiguration({}); + const wrappingInfo = config.options.get(EditorOption.wrappingInfo); + const fontInfo = config.options.get(EditorOption.fontInfo); + const wordWrapBreakAfterCharacters = config.options.get(EditorOption.wordWrapBreakAfterCharacters); + const wordWrapBreakBeforeCharacters = config.options.get(EditorOption.wordWrapBreakBeforeCharacters); + const wordWrapBreakObtrusiveCharacters = config.options.get(EditorOption.wordWrapBreakObtrusiveCharacters); + const wrappingIndent = config.options.get(EditorOption.wrappingIndent); - let hardWrappingLineMapperFactory = new CharacterHardWrappingLineMapperFactory( - config.editor.wrappingInfo.wordWrapBreakBeforeCharacters, - config.editor.wrappingInfo.wordWrapBreakAfterCharacters, - config.editor.wrappingInfo.wordWrapBreakObtrusiveCharacters + const hardWrappingLineMapperFactory = new CharacterHardWrappingLineMapperFactory( + wordWrapBreakBeforeCharacters, + wordWrapBreakAfterCharacters, + wordWrapBreakObtrusiveCharacters ); - let model = TextModel.createFromString([ + const model = TextModel.createFromString([ 'int main() {', '\tprintf("Hello world!");', '}', @@ -105,13 +113,13 @@ suite('Editor ViewModel - SplitLinesCollection', () => { '}', ].join('\n')); - let linesCollection = new SplitLinesCollection( + const linesCollection = new SplitLinesCollection( model, hardWrappingLineMapperFactory, model.getOptions().tabSize, - config.editor.wrappingInfo.wrappingColumn, - config.editor.fontInfo.typicalFullwidthCharacterWidth / config.editor.fontInfo.typicalHalfwidthCharacterWidth, - config.editor.wrappingInfo.wrappingIndent + wrappingInfo.wrappingColumn, + fontInfo.typicalFullwidthCharacterWidth / fontInfo.typicalHalfwidthCharacterWidth, + wrappingIndent ); callback(model, linesCollection); @@ -732,25 +740,31 @@ suite('SplitLinesCollection', () => { }); function withSplitLinesCollection(model: TextModel, wordWrap: 'on' | 'off' | 'wordWrapColumn' | 'bounded', wordWrapColumn: number, callback: (splitLinesCollection: SplitLinesCollection) => void): void { - let configuration = new TestConfiguration({ + const configuration = new TestConfiguration({ wordWrap: wordWrap, wordWrapColumn: wordWrapColumn, wrappingIndent: 'indent' }); + const wrappingInfo = configuration.options.get(EditorOption.wrappingInfo); + const fontInfo = configuration.options.get(EditorOption.fontInfo); + const wordWrapBreakAfterCharacters = configuration.options.get(EditorOption.wordWrapBreakAfterCharacters); + const wordWrapBreakBeforeCharacters = configuration.options.get(EditorOption.wordWrapBreakBeforeCharacters); + const wordWrapBreakObtrusiveCharacters = configuration.options.get(EditorOption.wordWrapBreakObtrusiveCharacters); + const wrappingIndent = configuration.options.get(EditorOption.wrappingIndent); - let factory = new CharacterHardWrappingLineMapperFactory( - configuration.editor.wrappingInfo.wordWrapBreakBeforeCharacters, - configuration.editor.wrappingInfo.wordWrapBreakAfterCharacters, - configuration.editor.wrappingInfo.wordWrapBreakObtrusiveCharacters + const factory = new CharacterHardWrappingLineMapperFactory( + wordWrapBreakBeforeCharacters, + wordWrapBreakAfterCharacters, + wordWrapBreakObtrusiveCharacters ); - let linesCollection = new SplitLinesCollection( + const linesCollection = new SplitLinesCollection( model, factory, model.getOptions().tabSize, - configuration.editor.wrappingInfo.wrappingColumn, - configuration.editor.fontInfo.typicalFullwidthCharacterWidth / configuration.editor.fontInfo.typicalHalfwidthCharacterWidth, - configuration.editor.wrappingInfo.wrappingIndent + wrappingInfo.wrappingColumn, + fontInfo.typicalFullwidthCharacterWidth / fontInfo.typicalHalfwidthCharacterWidth, + wrappingIndent ); callback(linesCollection); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 6e0b1286ef0..52c82fe6d55 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2408,80 +2408,13 @@ declare namespace monaco.editor { readonly reason: CursorChangeReason; } - /** - * Configuration options for editor scrollbars - */ - export interface IEditorScrollbarOptions { + export enum AccessibilitySupport { /** - * The size of arrows (if displayed). - * Defaults to 11. + * This should be the browser case where it is not known if a screen reader is attached or no. */ - arrowSize?: number; - /** - * Render vertical scrollbar. - * Defaults to 'auto'. - */ - vertical?: 'auto' | 'visible' | 'hidden'; - /** - * Render horizontal scrollbar. - * Defaults to 'auto'. - */ - horizontal?: 'auto' | 'visible' | 'hidden'; - /** - * Cast horizontal and vertical shadows when the content is scrolled. - * Defaults to true. - */ - useShadows?: boolean; - /** - * Render arrows at the top and bottom of the vertical scrollbar. - * Defaults to false. - */ - verticalHasArrows?: boolean; - /** - * Render arrows at the left and right of the horizontal scrollbar. - * Defaults to false. - */ - horizontalHasArrows?: boolean; - /** - * Listen to mouse wheel events and react to them by scrolling. - * Defaults to true. - */ - handleMouseWheel?: boolean; - /** - * Height in pixels for the horizontal scrollbar. - * Defaults to 10 (px). - */ - horizontalScrollbarSize?: number; - /** - * Width in pixels for the vertical scrollbar. - * Defaults to 10 (px). - */ - verticalScrollbarSize?: number; - /** - * Width in pixels for the vertical slider. - * Defaults to `verticalScrollbarSize`. - */ - verticalSliderSize?: number; - /** - * Height in pixels for the horizontal slider. - * Defaults to `horizontalScrollbarSize`. - */ - horizontalSliderSize?: number; - } - - /** - * Configuration options for editor find widget - */ - export interface IEditorFindOptions { - /** - * Controls if we seed search string in the Find Widget with editor selection. - */ - seedSearchStringFromSelection?: boolean; - /** - * Controls if Find in Selection flag is turned on when multiple lines of text are selected in the editor. - */ - autoFindInSelection: boolean; - addExtraSpaceOnTop?: boolean; + Unknown = 0, + Disabled = 1, + Enabled = 2 } /** @@ -2499,134 +2432,14 @@ declare namespace monaco.editor { */ export type EditorAutoClosingOvertypeStrategy = 'always' | 'auto' | 'never'; - /** - * Configuration options for editor minimap - */ - export interface IEditorMinimapOptions { - /** - * Enable the rendering of the minimap. - * Defaults to true. - */ - enabled?: boolean; - /** - * Control the side of the minimap in editor. - * Defaults to 'right'. - */ - side?: 'right' | 'left'; - /** - * Control the rendering of the minimap slider. - * Defaults to 'mouseover'. - */ - showSlider?: 'always' | 'mouseover'; - /** - * Render the actual text on a line (as opposed to color blocks). - * Defaults to true. - */ - renderCharacters?: boolean; - /** - * Limit the width of the minimap to render at most a certain number of columns. - * Defaults to 120. - */ - maxColumn?: number; - } - - /** - * Configuration options for editor minimap - */ - export interface IEditorLightbulbOptions { - /** - * Enable the lightbulb code action. - * Defaults to true. - */ - enabled?: boolean; - } - - /** - * Configuration options for editor hover - */ - export interface IEditorHoverOptions { - /** - * Enable the hover. - * Defaults to true. - */ - enabled?: boolean; - /** - * Delay for showing the hover. - * Defaults to 300. - */ - delay?: number; - /** - * Is the hover sticky such that it can be clicked and its contents selected? - * Defaults to true. - */ - sticky?: boolean; - } - - /** - * Configuration options for parameter hints - */ - export interface IEditorParameterHintOptions { - /** - * Enable parameter hints. - * Defaults to true. - */ - enabled?: boolean; - /** - * Enable cycling of parameter hints. - * Defaults to false. - */ - cycle?: boolean; - } - - export interface ISuggestOptions { - /** - * Enable graceful matching. Defaults to true. - */ - filterGraceful?: boolean; - /** - * Prevent quick suggestions when a snippet is active. Defaults to true. - */ - snippetsPreventQuickSuggestions?: boolean; - /** - * Favours words that appear close to the cursor. - */ - localityBonus?: boolean; - /** - * Enable using global storage for remembering suggestions. - */ - shareSuggestSelections?: boolean; - /** - * Enable or disable icons in suggestions. Defaults to true. - */ - showIcons?: boolean; - /** - * Max suggestions to show in suggestions. Defaults to 12. - */ - maxVisibleSuggestions?: boolean; - /** - * Names of suggestion types to filter. - */ - filteredTypes?: Record; - } - - export interface IGotoLocationOptions { - /** - * Control how goto-command work when having multiple results. - */ - multiple?: 'peek' | 'gotoAndPeek' | 'goto'; - } - - /** - * Configuration map for codeActionsOnSave - */ - export interface ICodeActionsOnSaveOptions { - [kind: string]: boolean; - } - /** * Configuration options for the editor. */ export interface IEditorOptions { + /** + * This editor is used inside a diff editor. + */ + inDiffEditor?: boolean; /** * The aria label for the editor's textarea (when it is focused). */ @@ -2653,7 +2466,7 @@ declare namespace monaco.editor { * Otherwise, line numbers will not be rendered. * Defaults to true. */ - lineNumbers?: 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string); + lineNumbers?: LineNumbersType; /** * Controls the minimal number of visible leading and trailing lines surrounding the cursor. * Defaults to 0. @@ -2737,12 +2550,17 @@ declare namespace monaco.editor { * Control the cursor animation style, possible values are 'blink', 'smooth', 'phase', 'expand' and 'solid'. * Defaults to 'blink'. */ - cursorBlinking?: string; + cursorBlinking?: 'blink' | 'smooth' | 'phase' | 'expand' | 'solid'; /** * Zoom the font in the editor when using the mouse wheel in combination with holding Ctrl. * Defaults to false. */ mouseWheelZoom?: boolean; + /** + * Control the mouse pointer style, either 'text' or 'default' or 'copy' + * Defaults to 'text' + */ + mouseStyle?: 'text' | 'default' | 'copy'; /** * Enable smooth caret animation. * Defaults to false. @@ -2752,7 +2570,7 @@ declare namespace monaco.editor { * Control the cursor style, either 'block' or 'line'. * Defaults to 'line'. */ - cursorStyle?: string; + cursorStyle?: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin'; /** * Control the width of the cursor when cursorStyle is set to 'line' */ @@ -2826,7 +2644,7 @@ declare namespace monaco.editor { * Control indentation of wrapped lines. Can be: 'none', 'same', 'indent' or 'deepIndent'. * Defaults to 'same' in vscode and to 'none' in monaco-editor. */ - wrappingIndent?: string; + wrappingIndent?: 'none' | 'same' | 'indent' | 'deepIndent'; /** * Configure word wrapping characters. A break will be introduced before these characters. * Defaults to '{([+'. @@ -2886,6 +2704,11 @@ declare namespace monaco.editor { * Defaults to true */ multiCursorMergeOverlapping?: boolean; + /** + * Configure the behaviour when pasting a text with the line count equal to the cursor count. + * Defaults to 'spread'. + */ + multiCursorPaste?: 'spread' | 'full'; /** * Configure the editor's accessibility support. * Defaults to 'auto'. It is best to leave this to 'auto'. @@ -2903,14 +2726,10 @@ declare namespace monaco.editor { * Enable quick suggestions (shadow suggestions) * Defaults to true. */ - quickSuggestions?: boolean | { - other: boolean; - comments: boolean; - strings: boolean; - }; + quickSuggestions?: boolean | IQuickSuggestionsOptions; /** * Quick suggestions show delay (in ms) - * Defaults to 500 (ms) + * Defaults to 10 (ms) */ quickSuggestionsDelay?: number; /** @@ -2965,7 +2784,7 @@ declare namespace monaco.editor { * Accept suggestions on ENTER. * Defaults to 'on'. */ - acceptSuggestionOnEnter?: boolean | 'on' | 'smart' | 'off'; + acceptSuggestionOnEnter?: 'on' | 'smart' | 'off'; /** * Accept suggestions on provider defined characters. * Defaults to true. @@ -2983,10 +2802,6 @@ declare namespace monaco.editor { * Syntax highlighting is copied. */ copyWithSyntaxHighlighting?: boolean; - /** - * Enable word based suggestions. Defaults to 'true' - */ - wordBasedSuggestions?: boolean; /** * The history mode for suggestions. */ @@ -3004,7 +2819,7 @@ declare namespace monaco.editor { /** * Enable tab completion. */ - tabCompletion?: boolean | 'on' | 'off' | 'onlySnippets'; + tabCompletion?: 'on' | 'off' | 'onlySnippets'; /** * Enable selection highlight. * Defaults to true. @@ -3024,10 +2839,6 @@ declare namespace monaco.editor { * Control the behavior and rendering of the code action lightbulb. */ lightbulb?: IEditorLightbulbOptions; - /** - * Code action kinds to be run on save. - */ - codeActionsOnSave?: ICodeActionsOnSaveOptions; /** * Timeout for running code actions on save. */ @@ -3088,7 +2899,7 @@ declare namespace monaco.editor { /** * The font weight */ - fontWeight?: 'normal' | 'bold' | 'bolder' | 'lighter' | 'initial' | 'inherit' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; + fontWeight?: string; /** * The font size */ @@ -3138,34 +2949,10 @@ declare namespace monaco.editor { originalEditable?: boolean; } - export enum RenderMinimap { - None = 0, - Small = 1, - Large = 2, - SmallBlocks = 3, - LargeBlocks = 4 - } - /** - * Describes how to indent wrapped lines. + * An event describing that the configuration of the editor has changed. */ - export enum WrappingIndent { - /** - * No indentation => wrapped lines begin at column 1. - */ - None = 0, - /** - * Same => wrapped lines get the same indentation as the parent. - */ - Same = 1, - /** - * Indent => wrapped lines get +1 indentation toward the parent. - */ - Indent = 2, - /** - * DeepIndent => wrapped lines get +2 indentation toward the parent. - */ - DeepIndent = 3 + export class ConfigurationChangedEvent { } /** @@ -3228,187 +3015,58 @@ declare namespace monaco.editor { UnderlineThin = 6 } - export interface InternalEditorScrollbarOptions { - readonly arrowSize: number; - readonly vertical: ScrollbarVisibility; - readonly horizontal: ScrollbarVisibility; - readonly useShadows: boolean; - readonly verticalHasArrows: boolean; - readonly horizontalHasArrows: boolean; - readonly handleMouseWheel: boolean; - readonly horizontalScrollbarSize: number; - readonly horizontalSliderSize: number; - readonly verticalScrollbarSize: number; - readonly verticalSliderSize: number; - readonly mouseWheelScrollSensitivity: number; - readonly fastScrollSensitivity: number; + /** + * Configuration options for editor find widget + */ + export interface IEditorFindOptions { + /** + * Controls if we seed search string in the Find Widget with editor selection. + */ + seedSearchStringFromSelection?: boolean; + /** + * Controls if Find in Selection flag is turned on when multiple lines of text are selected in the editor. + */ + autoFindInSelection?: boolean; + addExtraSpaceOnTop?: boolean; } - export interface InternalEditorMinimapOptions { - readonly enabled: boolean; - readonly side: 'right' | 'left'; - readonly showSlider: 'always' | 'mouseover'; - readonly renderCharacters: boolean; - readonly maxColumn: number; - } - - export interface InternalEditorFindOptions { - readonly seedSearchStringFromSelection: boolean; - readonly autoFindInSelection: boolean; - readonly addExtraSpaceOnTop: boolean; - } - - export interface InternalEditorHoverOptions { - readonly enabled: boolean; - readonly delay: number; - readonly sticky: boolean; - } - - export interface InternalGoToLocationOptions { - readonly multiple: 'peek' | 'gotoAndPeek' | 'goto'; - } - - export interface InternalSuggestOptions { - readonly filterGraceful: boolean; - readonly snippets: 'top' | 'bottom' | 'inline' | 'none'; - readonly snippetsPreventQuickSuggestions: boolean; - readonly localityBonus: boolean; - readonly shareSuggestSelections: boolean; - readonly showIcons: boolean; - readonly maxVisibleSuggestions: number; - readonly filteredTypes: Record; - } - - export interface InternalParameterHintOptions { - readonly enabled: boolean; - readonly cycle: boolean; - } - - export interface EditorWrappingInfo { - readonly inDiffEditor: boolean; - readonly isDominatedByLongLines: boolean; - readonly isWordWrapMinified: boolean; - readonly isViewportWrapping: boolean; - readonly wrappingColumn: number; - readonly wrappingIndent: WrappingIndent; - readonly wordWrapBreakBeforeCharacters: string; - readonly wordWrapBreakAfterCharacters: string; - readonly wordWrapBreakObtrusiveCharacters: string; - } - - export enum RenderLineNumbersType { - Off = 0, - On = 1, - Relative = 2, - Interval = 3, - Custom = 4 - } - - export interface InternalEditorViewOptions { - readonly extraEditorClassName: string; - readonly disableMonospaceOptimizations: boolean; - readonly rulers: number[]; - readonly ariaLabel: string; - readonly renderLineNumbers: RenderLineNumbersType; - readonly renderCustomLineNumbers: ((lineNumber: number) => string) | null; - readonly cursorSurroundingLines: number; - readonly renderFinalNewline: boolean; - readonly selectOnLineNumbers: boolean; - readonly glyphMargin: boolean; - readonly revealHorizontalRightPadding: number; - readonly roundedSelection: boolean; - readonly overviewRulerLanes: number; - readonly overviewRulerBorder: boolean; - readonly cursorBlinking: TextEditorCursorBlinkingStyle; - readonly mouseWheelZoom: boolean; - readonly cursorSmoothCaretAnimation: boolean; - readonly cursorStyle: TextEditorCursorStyle; - readonly cursorWidth: number; - readonly hideCursorInOverviewRuler: boolean; - readonly scrollBeyondLastLine: boolean; - readonly scrollBeyondLastColumn: number; - readonly smoothScrolling: boolean; - readonly stopRenderingLineAfter: number; - readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all'; - readonly renderControlCharacters: boolean; - readonly fontLigatures: boolean; - readonly renderIndentGuides: boolean; - readonly highlightActiveIndentGuide: boolean; - readonly renderLineHighlight: 'none' | 'gutter' | 'line' | 'all'; - readonly scrollbar: InternalEditorScrollbarOptions; - readonly minimap: InternalEditorMinimapOptions; - readonly fixedOverflowWidgets: boolean; - } - - export interface EditorContribOptions { - readonly selectionClipboard: boolean; - readonly hover: InternalEditorHoverOptions; - readonly links: boolean; - readonly contextmenu: boolean; - readonly quickSuggestions: boolean | { - other: boolean; - comments: boolean; - strings: boolean; - }; - readonly quickSuggestionsDelay: number; - readonly parameterHints: InternalParameterHintOptions; - readonly formatOnType: boolean; - readonly formatOnPaste: boolean; - readonly suggestOnTriggerCharacters: boolean; - readonly acceptSuggestionOnEnter: 'on' | 'smart' | 'off'; - readonly acceptSuggestionOnCommitCharacter: boolean; - readonly wordBasedSuggestions: boolean; - readonly suggestSelection: 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix'; - readonly suggestFontSize: number; - readonly suggestLineHeight: number; - readonly tabCompletion: 'on' | 'off' | 'onlySnippets'; - readonly suggest: InternalSuggestOptions; - readonly gotoLocation: InternalGoToLocationOptions; - readonly selectionHighlight: boolean; - readonly occurrencesHighlight: boolean; - readonly codeLens: boolean; - readonly folding: boolean; - readonly foldingStrategy: 'auto' | 'indentation'; - readonly showFoldingControls: 'always' | 'mouseover'; - readonly matchBrackets: boolean; - readonly find: InternalEditorFindOptions; - readonly colorDecorators: boolean; - readonly lightbulbEnabled: boolean; - readonly codeActionsOnSave: ICodeActionsOnSaveOptions; - readonly codeActionsOnSaveTimeout: number; - } + export type EditorFindOptions = Readonly>; /** - * Internal configuration options (transformed or computed) for the editor. + * Configuration options for go to location */ - export class InternalEditorOptions { - readonly _internalEditorOptionsBrand: void; - readonly canUseLayerHinting: boolean; - readonly pixelRatio: number; - readonly editorClassName: string; - readonly lineHeight: number; - readonly readOnly: boolean; - readonly multiCursorModifier: 'altKey' | 'ctrlKey' | 'metaKey'; - readonly multiCursorMergeOverlapping: boolean; - readonly showUnused: boolean; - readonly wordSeparators: string; - readonly autoClosingBrackets: EditorAutoClosingStrategy; - readonly autoClosingQuotes: EditorAutoClosingStrategy; - readonly autoClosingOvertype: EditorAutoClosingOvertypeStrategy; - readonly autoSurround: EditorAutoSurroundStrategy; - readonly autoIndent: boolean; - readonly useTabStops: boolean; - readonly tabFocusMode: boolean; - readonly dragAndDrop: boolean; - readonly emptySelectionClipboard: boolean; - readonly copyWithSyntaxHighlighting: boolean; - readonly layoutInfo: EditorLayoutInfo; - readonly fontInfo: FontInfo; - readonly viewInfo: InternalEditorViewOptions; - readonly wrappingInfo: EditorWrappingInfo; - readonly contribInfo: EditorContribOptions; + export interface IGotoLocationOptions { + /** + * Control how goto-command work when having multiple results. + */ + multiple?: 'peek' | 'gotoAndPeek' | 'goto'; } + export type GoToLocationOptions = Readonly>; + + /** + * Configuration options for editor hover + */ + export interface IEditorHoverOptions { + /** + * Enable the hover. + * Defaults to true. + */ + enabled?: boolean; + /** + * Delay for showing the hover. + * Defaults to 300. + */ + delay?: number; + /** + * Is the hover sticky such that it can be clicked and its contents selected? + * Defaults to true. + */ + sticky?: boolean; + } + + export type EditorHoverOptions = Readonly>; + /** * A description for the overview ruler position. */ @@ -3431,6 +3089,14 @@ declare namespace monaco.editor { readonly right: number; } + export enum RenderMinimap { + None = 0, + Small = 1, + Large = 2, + SmallBlocks = 3, + LargeBlocks = 4 + } + /** * The internal layout details of the editor. */ @@ -3522,33 +3188,233 @@ declare namespace monaco.editor { } /** - * An event describing that the configuration of the editor has changed. + * Configuration options for editor lightbulb */ - export interface IConfigurationChangedEvent { - readonly canUseLayerHinting: boolean; - readonly pixelRatio: boolean; - readonly editorClassName: boolean; - readonly lineHeight: boolean; - readonly readOnly: boolean; - readonly accessibilitySupport: boolean; - readonly multiCursorModifier: boolean; - readonly multiCursorMergeOverlapping: boolean; - readonly wordSeparators: boolean; - readonly autoClosingBrackets: boolean; - readonly autoClosingQuotes: boolean; - readonly autoClosingOvertype: boolean; - readonly autoSurround: boolean; - readonly autoIndent: boolean; - readonly useTabStops: boolean; - readonly tabFocusMode: boolean; - readonly dragAndDrop: boolean; - readonly emptySelectionClipboard: boolean; - readonly copyWithSyntaxHighlighting: boolean; - readonly layoutInfo: boolean; - readonly fontInfo: boolean; - readonly viewInfo: boolean; - readonly wrappingInfo: boolean; - readonly contribInfo: boolean; + export interface IEditorLightbulbOptions { + /** + * Enable the lightbulb code action. + * Defaults to true. + */ + enabled?: boolean; + } + + export type EditorLightbulbOptions = Readonly>; + + /** + * Configuration options for editor minimap + */ + export interface IEditorMinimapOptions { + /** + * Enable the rendering of the minimap. + * Defaults to true. + */ + enabled?: boolean; + /** + * Control the side of the minimap in editor. + * Defaults to 'right'. + */ + side?: 'right' | 'left'; + /** + * Control the rendering of the minimap slider. + * Defaults to 'mouseover'. + */ + showSlider?: 'always' | 'mouseover'; + /** + * Render the actual text on a line (as opposed to color blocks). + * Defaults to true. + */ + renderCharacters?: boolean; + /** + * Limit the width of the minimap to render at most a certain number of columns. + * Defaults to 120. + */ + maxColumn?: number; + } + + export type EditorMinimapOptions = Readonly>; + + /** + * Configuration options for parameter hints + */ + export interface IEditorParameterHintOptions { + /** + * Enable parameter hints. + * Defaults to true. + */ + enabled?: boolean; + /** + * Enable cycling of parameter hints. + * Defaults to false. + */ + cycle?: boolean; + } + + export type InternalParameterHintOptions = Readonly>; + + /** + * Configuration options for quick suggestions + */ + export interface IQuickSuggestionsOptions { + other: boolean; + comments: boolean; + strings: boolean; + } + + export type ValidQuickSuggestionsOptions = boolean | Readonly>; + + export type LineNumbersType = 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string); + + export enum RenderLineNumbersType { + Off = 0, + On = 1, + Relative = 2, + Interval = 3, + Custom = 4 + } + + export interface InternalEditorRenderLineNumbersOptions { + readonly renderType: RenderLineNumbersType; + readonly renderFn: ((lineNumber: number) => string) | null; + } + + /** + * Configuration options for editor scrollbars + */ + export interface IEditorScrollbarOptions { + /** + * The size of arrows (if displayed). + * Defaults to 11. + */ + arrowSize?: number; + /** + * Render vertical scrollbar. + * Defaults to 'auto'. + */ + vertical?: 'auto' | 'visible' | 'hidden'; + /** + * Render horizontal scrollbar. + * Defaults to 'auto'. + */ + horizontal?: 'auto' | 'visible' | 'hidden'; + /** + * Cast horizontal and vertical shadows when the content is scrolled. + * Defaults to true. + */ + useShadows?: boolean; + /** + * Render arrows at the top and bottom of the vertical scrollbar. + * Defaults to false. + */ + verticalHasArrows?: boolean; + /** + * Render arrows at the left and right of the horizontal scrollbar. + * Defaults to false. + */ + horizontalHasArrows?: boolean; + /** + * Listen to mouse wheel events and react to them by scrolling. + * Defaults to true. + */ + handleMouseWheel?: boolean; + /** + * Height in pixels for the horizontal scrollbar. + * Defaults to 10 (px). + */ + horizontalScrollbarSize?: number; + /** + * Width in pixels for the vertical scrollbar. + * Defaults to 10 (px). + */ + verticalScrollbarSize?: number; + /** + * Width in pixels for the vertical slider. + * Defaults to `verticalScrollbarSize`. + */ + verticalSliderSize?: number; + /** + * Height in pixels for the horizontal slider. + * Defaults to `horizontalScrollbarSize`. + */ + horizontalSliderSize?: number; + } + + export interface InternalEditorScrollbarOptions { + readonly arrowSize: number; + readonly vertical: ScrollbarVisibility; + readonly horizontal: ScrollbarVisibility; + readonly useShadows: boolean; + readonly verticalHasArrows: boolean; + readonly horizontalHasArrows: boolean; + readonly handleMouseWheel: boolean; + readonly horizontalScrollbarSize: number; + readonly horizontalSliderSize: number; + readonly verticalScrollbarSize: number; + readonly verticalSliderSize: number; + } + + /** + * Configuration options for editor suggest widget + */ + export interface ISuggestOptions { + /** + * Enable graceful matching. Defaults to true. + */ + filterGraceful?: boolean; + /** + * Prevent quick suggestions when a snippet is active. Defaults to true. + */ + snippetsPreventQuickSuggestions?: boolean; + /** + * Favours words that appear close to the cursor. + */ + localityBonus?: boolean; + /** + * Enable using global storage for remembering suggestions. + */ + shareSuggestSelections?: boolean; + /** + * Enable or disable icons in suggestions. Defaults to true. + */ + showIcons?: boolean; + /** + * Max suggestions to show in suggestions. Defaults to 12. + */ + maxVisibleSuggestions?: number; + /** + * Names of suggestion types to filter. + */ + filteredTypes?: Record; + } + + export type InternalSuggestOptions = Readonly>; + + /** + * Describes how to indent wrapped lines. + */ + export enum WrappingIndent { + /** + * No indentation => wrapped lines begin at column 1. + */ + None = 0, + /** + * Same => wrapped lines get the same indentation as the parent. + */ + Same = 1, + /** + * Indent => wrapped lines get +1 indentation toward the parent. + */ + Indent = 2, + /** + * DeepIndent => wrapped lines get +2 indentation toward the parent. + */ + DeepIndent = 3 + } + + export interface EditorWrappingInfo { + readonly isDominatedByLongLines: boolean; + readonly isWordWrapMinified: boolean; + readonly isViewportWrapping: boolean; + readonly wrappingColumn: number; } /** @@ -3871,7 +3737,7 @@ declare namespace monaco.editor { * An event emitted when the configuration of the editor has changed. (e.g. `editor.updateOptions()`) * @event */ - onDidChangeConfiguration(listener: (e: IConfigurationChangedEvent) => void): IDisposable; + onDidChangeConfiguration(listener: (e: ConfigurationChangedEvent) => void): IDisposable; /** * An event emitted when the cursor position has changed. * @event @@ -3997,9 +3863,9 @@ declare namespace monaco.editor { */ setModel(model: ITextModel | null): void; /** - * Returns the current editor's configuration + * Returns the editor's configuration (without any validation or defaults). */ - getConfiguration(): InternalEditorOptions; + getRawOptions(): IEditorOptions; /** * Get value of the current model attached to this editor. * @see `ITextModel.getValue` @@ -4242,6 +4108,7 @@ declare namespace monaco.editor { readonly spaceWidth: number; readonly maxDigitWidth: number; } + export class BareFontInfo { readonly _bareFontInfoBrand: void; readonly zoomLevel: number; diff --git a/src/vs/platform/backup/test/electron-main/backupMainService.test.ts b/src/vs/platform/backup/test/electron-main/backupMainService.test.ts index 384fbaf9a7d..16891cc90cd 100644 --- a/src/vs/platform/backup/test/electron-main/backupMainService.test.ts +++ b/src/vs/platform/backup/test/electron-main/backupMainService.test.ts @@ -11,7 +11,7 @@ import * as path from 'vs/base/common/path'; import * as pfs from 'vs/base/node/pfs'; import { URI as Uri, URI } from 'vs/base/common/uri'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService'; import { IBackupWorkspacesFormat, ISerializedWorkspace, IWorkspaceBackupInfo } from 'vs/platform/backup/common/backup'; import { HotExitConfiguration } from 'vs/platform/files/common/files'; @@ -32,7 +32,7 @@ suite('BackupMainService', () => { const backupHome = path.join(parentDir, 'Backups'); const backupWorkspacesPath = path.join(backupHome, 'workspaces.json'); - const environmentService = new EnvironmentService(parseArgs(process.argv), process.execPath); + const environmentService = new EnvironmentService(parseArgs(process.argv, OPTIONS), process.execPath); class TestBackupMainService extends BackupMainService { diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 413381155d4..7f77b7a084d 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -25,7 +25,7 @@ export interface ParsedArgs { 'reuse-window'?: boolean; locale?: string; 'user-data-dir'?: string; - 'prof-startup'?: string; + 'prof-startup'?: boolean; 'prof-startup-prefix'?: string; 'prof-append-timers'?: string; verbose?: boolean; @@ -61,8 +61,8 @@ export interface ParsedArgs { 'disable-telemetry'?: boolean; 'export-default-configuration'?: string; 'install-source'?: string; - 'disable-updates'?: string; - 'disable-crash-reporter'?: string; + 'disable-updates'?: boolean; + 'disable-crash-reporter'?: boolean; 'skip-add-to-recently-opened'?: boolean; 'max-memory'?: string; 'file-write'?: boolean; @@ -71,17 +71,13 @@ export interface ParsedArgs { 'driver-verbose'?: boolean; remote?: string; 'disable-user-env-probe'?: boolean; - 'enable-remote-auto-shutdown'?: boolean; 'disable-inspect'?: boolean; 'force'?: boolean; - 'gitCredential'?: string; + // node flags - 'js-flags'?: boolean; + 'js-flags'?: string; 'disable-gpu'?: boolean; 'nolazy'?: boolean; - - // Web flags - 'web-user-data-dir'?: string; } export const IEnvironmentService = createDecorator('environmentService'); diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index c3cbae52fea..3c72aa15242 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -20,84 +20,103 @@ const helpCategories = { t: localize('troubleshooting', "Troubleshooting") }; -export interface Option { - id: keyof ParsedArgs; - type: 'boolean' | 'string' | 'string[]'; +export interface Option { + type: OptionType; alias?: string; deprecates?: string; // old deprecated id args?: string | string[]; description?: string; cat?: keyof typeof helpCategories; } -//_urls -export const options: Option[] = [ - { id: 'diff', type: 'boolean', cat: 'o', alias: 'd', args: ['file', 'file'], description: localize('diff', "Compare two files with each other.") }, - { id: 'add', type: 'boolean', cat: 'o', alias: 'a', args: 'folder', description: localize('add', "Add folder(s) to the last active window.") }, - { id: 'goto', type: 'boolean', cat: 'o', alias: 'g', args: 'file:line[:character]', description: localize('goto', "Open a file at the path on the specified line and character position.") }, - { id: 'new-window', type: 'boolean', cat: 'o', alias: 'n', description: localize('newWindow', "Force to open a new window.") }, - { id: 'reuse-window', type: 'boolean', cat: 'o', alias: 'r', description: localize('reuseWindow', "Force to open a file or folder in an already opened window.") }, - { id: 'wait', type: 'boolean', cat: 'o', alias: 'w', description: localize('wait', "Wait for the files to be closed before returning.") }, - { id: 'locale', type: 'string', cat: 'o', args: 'locale', description: localize('locale', "The locale to use (e.g. en-US or zh-TW).") }, - { id: 'user-data-dir', type: 'string', cat: 'o', args: 'dir', description: localize('userDataDir', "Specifies the directory that user data is kept in. Can be used to open multiple distinct instances of Code.") }, - { id: 'version', type: 'boolean', cat: 'o', alias: 'v', description: localize('version', "Print version.") }, - { id: 'help', type: 'boolean', cat: 'o', alias: 'h', description: localize('help', "Print usage.") }, - { id: 'telemetry', type: 'boolean', cat: 'o', description: localize('telemetry', "Shows all telemetry events which VS code collects.") }, - { id: 'folder-uri', type: 'string[]', cat: 'o', args: 'uri', description: localize('folderUri', "Opens a window with given folder uri(s)") }, - { id: 'file-uri', type: 'string[]', cat: 'o', args: 'uri', description: localize('fileUri', "Opens a window with given file uri(s)") }, - { id: 'extensions-dir', type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") }, - { id: 'list-extensions', type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") }, - { id: 'show-versions', type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extension.") }, - { id: 'category', type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extension.") }, - { id: 'install-extension', type: 'string[]', cat: 'e', args: 'extension-id | path-to-vsix', description: localize('installExtension', "Installs or updates the extension. Use `--force` argument to avoid prompts.") }, - { id: 'uninstall-extension', type: 'string[]', cat: 'e', args: 'extension-id', description: localize('uninstallExtension', "Uninstalls an extension.") }, - { id: 'enable-proposed-api', type: 'string[]', cat: 'e', args: 'extension-id', description: localize('experimentalApis', "Enables proposed API features for extensions. Can receive one or more extension IDs to enable individually.") }, +export type OptionDescriptions = { + [P in keyof T]: Option>; +}; - { id: 'verbose', type: 'boolean', cat: 't', description: localize('verbose', "Print verbose output (implies --wait).") }, - { id: 'log', type: 'string', cat: 't', args: 'level', description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.") }, - { id: 'status', type: 'boolean', alias: 's', cat: 't', description: localize('status', "Print process usage and diagnostics information.") }, - { id: 'prof-startup', type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup") }, - { id: 'disable-extensions', type: 'boolean', deprecates: 'disableExtensions', cat: 't', description: localize('disableExtensions', "Disable all installed extensions.") }, - { id: 'disable-extension', type: 'string[]', cat: 't', args: 'extension-id', description: localize('disableExtension', "Disable an extension.") }, +type OptionTypeName = + T extends boolean ? 'boolean' : + T extends string ? 'string' : + T extends string[] ? 'string[]' : + T extends undefined ? 'undefined' : + 'unknown'; - { id: 'inspect-extensions', type: 'string', deprecates: 'debugPluginHost', args: 'port', cat: 't', description: localize('inspect-extensions', "Allow debugging and profiling of extensions. Check the developer tools for the connection URI.") }, - { id: 'inspect-brk-extensions', type: 'string', deprecates: 'debugBrkPluginHost', args: 'port', cat: 't', description: localize('inspect-brk-extensions', "Allow debugging and profiling of extensions with the extension host being paused after start. Check the developer tools for the connection URI.") }, - { id: 'disable-gpu', type: 'boolean', cat: 't', description: localize('disableGPU', "Disable GPU hardware acceleration.") }, - { id: 'max-memory', type: 'string', cat: 't', description: localize('maxMemory', "Max memory size for a window (in Mbytes).") }, +export const OPTIONS: OptionDescriptions> = { + 'diff': { type: 'boolean', cat: 'o', alias: 'd', args: ['file', 'file'], description: localize('diff', "Compare two files with each other.") }, + 'add': { type: 'boolean', cat: 'o', alias: 'a', args: 'folder', description: localize('add', "Add folder(s) to the last active window.") }, + 'goto': { type: 'boolean', cat: 'o', alias: 'g', args: 'file:line[:character]', description: localize('goto', "Open a file at the path on the specified line and character position.") }, + 'new-window': { type: 'boolean', cat: 'o', alias: 'n', description: localize('newWindow', "Force to open a new window.") }, + 'reuse-window': { type: 'boolean', cat: 'o', alias: 'r', description: localize('reuseWindow', "Force to open a file or folder in an already opened window.") }, + 'wait': { type: 'boolean', cat: 'o', alias: 'w', description: localize('wait', "Wait for the files to be closed before returning.") }, + 'waitMarkerFilePath': { type: 'string' }, + 'locale': { type: 'string', cat: 'o', args: 'locale', description: localize('locale', "The locale to use (e.g. en-US or zh-TW).") }, + 'user-data-dir': { type: 'string', cat: 'o', args: 'dir', description: localize('userDataDir', "Specifies the directory that user data is kept in. Can be used to open multiple distinct instances of Code.") }, + 'version': { type: 'boolean', cat: 'o', alias: 'v', description: localize('version', "Print version.") }, + 'help': { type: 'boolean', cat: 'o', alias: 'h', description: localize('help', "Print usage.") }, + 'telemetry': { type: 'boolean', cat: 'o', description: localize('telemetry', "Shows all telemetry events which VS code collects.") }, + 'folder-uri': { type: 'string[]', cat: 'o', args: 'uri', description: localize('folderUri', "Opens a window with given folder uri(s)") }, + 'file-uri': { type: 'string[]', cat: 'o', args: 'uri', description: localize('fileUri', "Opens a window with given file uri(s)") }, - { id: 'remote', type: 'string' }, - { id: 'locate-extension', type: 'string[]' }, - { id: 'extensionDevelopmentPath', type: 'string[]' }, - { id: 'extensionTestsPath', type: 'string' }, - { id: 'extension-development-confirm-save', type: 'boolean' }, - { id: 'debugId', type: 'string' }, - { id: 'inspect-search', type: 'string', deprecates: 'debugSearch' }, - { id: 'inspect-brk-search', type: 'string', deprecates: 'debugBrkSearch' }, - { id: 'export-default-configuration', type: 'string' }, - { id: 'install-source', type: 'string' }, - { id: 'driver', type: 'string' }, - { id: 'logExtensionHostCommunication', type: 'boolean' }, - { id: 'skip-getting-started', type: 'boolean' }, - { id: 'skip-release-notes', type: 'boolean' }, - { id: 'sticky-quickopen', type: 'boolean' }, - { id: 'disable-restore-windows', type: 'boolean' }, - { id: 'disable-telemetry', type: 'boolean' }, - { id: 'disable-updates', type: 'boolean' }, - { id: 'disable-crash-reporter', type: 'boolean' }, - { id: 'skip-add-to-recently-opened', type: 'boolean' }, - { id: 'unity-launch', type: 'boolean' }, - { id: 'open-url', type: 'boolean' }, - { id: 'file-write', type: 'boolean' }, - { id: 'file-chmod', type: 'boolean' }, - { id: 'driver-verbose', type: 'boolean' }, - { id: 'force', type: 'boolean' }, - { id: 'trace-category-filter', type: 'string' }, - { id: 'trace-options', type: 'string' }, - { id: 'disable-inspect', type: 'boolean' }, + 'extensions-dir': { type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") }, + 'builtin-extensions-dir': { type: 'string' }, + 'list-extensions': { type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") }, + 'show-versions': { type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extension.") }, + 'category': { type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extension.") }, + 'install-extension': { type: 'string[]', cat: 'e', args: 'extension-id | path-to-vsix', description: localize('installExtension', "Installs or updates the extension. Use `--force` argument to avoid prompts.") }, + 'uninstall-extension': { type: 'string[]', cat: 'e', args: 'extension-id', description: localize('uninstallExtension', "Uninstalls an extension.") }, + 'enable-proposed-api': { type: 'string[]', cat: 'e', args: 'extension-id', description: localize('experimentalApis', "Enables proposed API features for extensions. Can receive one or more extension IDs to enable individually.") }, - { id: 'js-flags', type: 'string' }, // chrome js flags - { id: 'nolazy', type: 'boolean' }, // node inspect -]; + 'verbose': { type: 'boolean', cat: 't', description: localize('verbose', "Print verbose output (implies --wait).") }, + 'log': { type: 'string', cat: 't', args: 'level', description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.") }, + 'status': { type: 'boolean', alias: 's', cat: 't', description: localize('status', "Print process usage and diagnostics information.") }, + 'prof-startup': { type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup") }, + 'prof-append-timers': { type: 'string' }, + 'prof-startup-prefix': { type: 'string' }, + 'disable-extensions': { type: 'boolean', deprecates: 'disableExtensions', cat: 't', description: localize('disableExtensions', "Disable all installed extensions.") }, + 'disable-extension': { type: 'string[]', cat: 't', args: 'extension-id', description: localize('disableExtension', "Disable an extension.") }, + + 'inspect-extensions': { type: 'string', deprecates: 'debugPluginHost', args: 'port', cat: 't', description: localize('inspect-extensions', "Allow debugging and profiling of extensions. Check the developer tools for the connection URI.") }, + 'inspect-brk-extensions': { type: 'string', deprecates: 'debugBrkPluginHost', args: 'port', cat: 't', description: localize('inspect-brk-extensions', "Allow debugging and profiling of extensions with the extension host being paused after start. Check the developer tools for the connection URI.") }, + 'disable-gpu': { type: 'boolean', cat: 't', description: localize('disableGPU', "Disable GPU hardware acceleration.") }, + 'max-memory': { type: 'string', cat: 't', description: localize('maxMemory', "Max memory size for a window (in Mbytes).") }, + + 'remote': { type: 'string' }, + 'locate-extension': { type: 'string[]' }, + 'extensionDevelopmentPath': { type: 'string[]' }, + 'extensionTestsPath': { type: 'string' }, + 'extension-development-confirm-save': { type: 'boolean' }, + 'debugId': { type: 'string' }, + 'inspect-search': { type: 'string', deprecates: 'debugSearch' }, + 'inspect-brk-search': { type: 'string', deprecates: 'debugBrkSearch' }, + 'export-default-configuration': { type: 'string' }, + 'install-source': { type: 'string' }, + 'driver': { type: 'string' }, + 'logExtensionHostCommunication': { type: 'boolean' }, + 'skip-getting-started': { type: 'boolean' }, + 'skip-release-notes': { type: 'boolean' }, + 'sticky-quickopen': { type: 'boolean' }, + 'disable-restore-windows': { type: 'boolean' }, + 'disable-telemetry': { type: 'boolean' }, + 'disable-updates': { type: 'boolean' }, + 'disable-crash-reporter': { type: 'boolean' }, + 'disable-user-env-probe': { type: 'boolean' }, + 'skip-add-to-recently-opened': { type: 'boolean' }, + 'unity-launch': { type: 'boolean' }, + 'open-url': { type: 'boolean' }, + 'file-write': { type: 'boolean' }, + 'file-chmod': { type: 'boolean' }, + 'driver-verbose': { type: 'boolean' }, + 'force': { type: 'boolean' }, + 'trace': { type: 'boolean' }, + 'trace-category-filter': { type: 'string' }, + 'trace-options': { type: 'string' }, + 'disable-inspect': { type: 'boolean' }, + + 'js-flags': { type: 'string' }, // chrome js flags + 'nolazy': { type: 'boolean' }, // node inspect + '_urls': { type: 'string[]' }, + + _: { type: 'string[]' } // main arguments +}; export interface ErrorReporter { onUnknownOption(id: string): void; @@ -109,24 +128,27 @@ const ignoringReporter: ErrorReporter = { onMultipleValues: () => { } }; -export function parseArgs(args: string[], isOptionSupported = (_: Option) => true, errorReporter: ErrorReporter = ignoringReporter): ParsedArgs { +export function parseArgs(args: string[], options: OptionDescriptions, errorReporter: ErrorReporter = ignoringReporter): T { const alias: { [key: string]: string } = {}; const string: string[] = []; const boolean: string[] = []; - for (let o of options) { - if (isOptionSupported(o)) { - if (o.alias) { - alias[o.id] = o.alias; - } + for (let optionId in options) { + if (optionId[0] === '_') { + continue; + } + + const o = options[optionId]; + if (o.alias) { + alias[optionId] = o.alias; } if (o.type === 'string' || o.type === 'string[]') { - string.push(o.id); + string.push(optionId); if (o.deprecates) { string.push(o.deprecates); } } else if (o.type === 'boolean') { - boolean.push(o.id); + boolean.push(optionId); if (o.deprecates) { boolean.push(o.deprecates); } @@ -137,12 +159,17 @@ export function parseArgs(args: string[], isOptionSupported = (_: Option) => tru const cleanedArgs: any = {}; - for (const o of options) { + // https://github.com/microsoft/vscode/issues/58177 + cleanedArgs._ = parsedArgs._.filter(arg => arg.length > 0); + delete parsedArgs._; + + for (let optionId in options) { + const o = options[optionId]; if (o.alias) { delete parsedArgs[o.alias]; } - let val = parsedArgs[o.id]; + let val = parsedArgs[optionId]; if (o.deprecates && parsedArgs.hasOwnProperty(o.deprecates)) { if (!val) { val = parsedArgs[o.deprecates]; @@ -151,29 +178,21 @@ export function parseArgs(args: string[], isOptionSupported = (_: Option) => tru } if (val) { - if (isOptionSupported(o)) { - if (o.type === 'string[]') { - if (val && !Array.isArray(val)) { - val = [val]; - } - } else if (o.type === 'string') { - if (Array.isArray(val)) { - val = val.pop(); // take the last - errorReporter.onMultipleValues(o.id, val); - } + if (o.type === 'string[]') { + if (val && !Array.isArray(val)) { + val = [val]; + } + } else if (o.type === 'string') { + if (Array.isArray(val)) { + val = val.pop(); // take the last + errorReporter.onMultipleValues(optionId, val); } - cleanedArgs[o.id] = val; - } else { - errorReporter.onUnknownOption(o.id); } + cleanedArgs[optionId] = val; } - delete parsedArgs[o.id]; + delete parsedArgs[optionId]; } - // https://github.com/microsoft/vscode/issues/58177 - cleanedArgs._ = parsedArgs._.filter(arg => arg.length > 0); - delete parsedArgs._; - for (let key in parsedArgs) { errorReporter.onUnknownOption(key); } @@ -181,7 +200,7 @@ export function parseArgs(args: string[], isOptionSupported = (_: Option) => tru return cleanedArgs; } -function formatUsage(option: Option) { +function formatUsage(optionId: string, option: Option) { let args = ''; if (option.args) { if (Array.isArray(option.args)) { @@ -191,30 +210,37 @@ function formatUsage(option: Option) { } } if (option.alias) { - return `-${option.alias} --${option.id}${args}`; + return `-${option.alias} --${optionId}${args}`; } - return `--${option.id}${args}`; + return `--${optionId}${args}`; } // exported only for testing -export function formatOptions(docOptions: Option[], columns: number): string[] { - let usageTexts = docOptions.map(formatUsage); - let argLength = Math.max.apply(null, usageTexts.map(k => k.length)) + 2/*left padding*/ + 1/*right padding*/; +export function formatOptions(options: OptionDescriptions, columns: number): string[] { + let maxLength = 0; + let usageTexts: [string, string][] = []; + for (const optionId in options) { + const o = options[optionId]; + const usageText = formatUsage(optionId, o); + maxLength = Math.max(maxLength, usageText.length); + usageTexts.push([usageText, o.description!]); + } + let argLength = maxLength + 2/*left padding*/ + 1/*right padding*/; if (columns - argLength < 25) { // Use a condensed version on narrow terminals - return docOptions.reduce((r, o, i) => r.concat([` ${usageTexts[i]}`, ` ${o.description}`]), []); + return usageTexts.reduce((r, ut) => r.concat([` ${ut[0]}`, ` ${ut[1]}`]), []); } let descriptionColumns = columns - argLength - 1; let result: string[] = []; - docOptions.forEach((o, i) => { - let usage = usageTexts[i]; - let wrappedDescription = wrapText(o.description!, descriptionColumns); + for (const ut of usageTexts) { + let usage = ut[0]; + let wrappedDescription = wrapText(ut[1], descriptionColumns); let keyPadding = indent(argLength - usage.length - 2/*left padding*/); result.push(' ' + usage + keyPadding + wrappedDescription[0]); for (let i = 1; i < wrappedDescription.length; i++) { result.push(indent(argLength) + wrappedDescription[i]); } - }); + } return result; } @@ -233,7 +259,7 @@ function wrapText(text: string, columns: number): string[] { return lines; } -export function buildHelpMessage(productName: string, executableName: string, version: string, isOptionSupported = (_: Option) => true, isPipeSupported = true): string { +export function buildHelpMessage(productName: string, executableName: string, version: string, options: OptionDescriptions, isPipeSupported = true): string { const columns = (process.stdout).isTTY && (process.stdout).columns || 80; let help = [`${productName} ${version}`]; @@ -248,11 +274,23 @@ export function buildHelpMessage(productName: string, executableName: string, ve } help.push(''); } - for (let helpCategoryKey in helpCategories) { + const optionsByCategory: { [P in keyof typeof helpCategories]?: OptionDescriptions } = {}; + for (const optionId in options) { + const o = options[optionId]; + if (o.description && o.cat) { + let optionsByCat = optionsByCategory[o.cat]; + if (!optionsByCat) { + optionsByCategory[o.cat] = optionsByCat = {}; + } + optionsByCat[optionId] = o; + } + } + + for (let helpCategoryKey in optionsByCategory) { const key = helpCategoryKey; - let categoryOptions = options.filter(o => !!o.description && o.cat === key && isOptionSupported(o)); - if (categoryOptions.length) { + let categoryOptions = optionsByCategory[key]; + if (categoryOptions) { help.push(helpCategories[key]); help.push(...formatOptions(categoryOptions, columns)); help.push(''); diff --git a/src/vs/platform/environment/node/argvHelper.ts b/src/vs/platform/environment/node/argvHelper.ts index 74191bb01df..f656fa743b8 100644 --- a/src/vs/platform/environment/node/argvHelper.ts +++ b/src/vs/platform/environment/node/argvHelper.ts @@ -8,7 +8,7 @@ import { firstIndex } from 'vs/base/common/arrays'; import { localize } from 'vs/nls'; import { ParsedArgs } from '../common/environment'; import { MIN_MAX_MEMORY_SIZE_MB } from 'vs/platform/files/common/files'; -import { parseArgs, ErrorReporter } from 'vs/platform/environment/node/argv'; +import { parseArgs, ErrorReporter, OPTIONS } from 'vs/platform/environment/node/argv'; function parseAndValidate(cmdLineArgs: string[], reportWarnings: boolean): ParsedArgs { const errorReporter: ErrorReporter = { @@ -20,7 +20,7 @@ function parseAndValidate(cmdLineArgs: string[], reportWarnings: boolean): Parse } }; - const args = parseArgs(cmdLineArgs, undefined, reportWarnings ? errorReporter : undefined); + const args = parseArgs(cmdLineArgs, OPTIONS, reportWarnings ? errorReporter : undefined); if (args.goto) { args._.forEach(arg => assert(/^(\w:)?[^:]+(:\d*){0,2}$/.test(arg), localize('gotoValidation', "Arguments in `--goto` mode should be in the format of `FILE(:LINE(:CHARACTER))`."))); } diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index e0cc96ad33b..1c3df4cac7e 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -104,8 +104,6 @@ export class EnvironmentService implements IEnvironmentService { return parseUserDataDir(this._args, process); } - @memoize - get webUserDataHome(): URI { return URI.file(parsePathArg(this._args['web-user-data-dir'], process) || this.userDataPath); } get appNameLong(): string { return product.nameLong; } @@ -285,7 +283,7 @@ function parseDebugPort(debugArg: string | undefined, debugBrkArg: string | unde return { port, break: brk, debugId }; } -function parsePathArg(arg: string | undefined, process: NodeJS.Process): string | undefined { +export function parsePathArg(arg: string | undefined, process: NodeJS.Process): string | undefined { if (!arg) { return undefined; } diff --git a/src/vs/platform/environment/test/node/environmentService.test.ts b/src/vs/platform/environment/test/node/environmentService.test.ts index 39d83f414b3..d30dc8a688b 100644 --- a/src/vs/platform/environment/test/node/environmentService.test.ts +++ b/src/vs/platform/environment/test/node/environmentService.test.ts @@ -5,13 +5,13 @@ import * as assert from 'assert'; import * as path from 'vs/base/common/path'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { parseExtensionHostPort, parseUserDataDir } from 'vs/platform/environment/node/environmentService'; suite('EnvironmentService', () => { test('parseExtensionHostPort when built', () => { - const parse = (a: string[]) => parseExtensionHostPort(parseArgs(a), true); + const parse = (a: string[]) => parseExtensionHostPort(parseArgs(a, OPTIONS), true); assert.deepEqual(parse([]), { port: null, break: false, debugId: undefined }); assert.deepEqual(parse(['--debugPluginHost']), { port: null, break: false, debugId: undefined }); @@ -28,7 +28,7 @@ suite('EnvironmentService', () => { }); test('parseExtensionHostPort when unbuilt', () => { - const parse = (a: string[]) => parseExtensionHostPort(parseArgs(a), false); + const parse = (a: string[]) => parseExtensionHostPort(parseArgs(a, OPTIONS), false); assert.deepEqual(parse([]), { port: 5870, break: false, debugId: undefined }); assert.deepEqual(parse(['--debugPluginHost']), { port: 5870, break: false, debugId: undefined }); @@ -45,7 +45,7 @@ suite('EnvironmentService', () => { }); test('userDataPath', () => { - const parse = (a: string[], b: { cwd: () => string, env: { [key: string]: string } }) => parseUserDataDir(parseArgs(a), b); + const parse = (a: string[], b: { cwd: () => string, env: { [key: string]: string } }) => parseUserDataDir(parseArgs(a, OPTIONS), b); assert.equal(parse(['--user-data-dir', './dir'], { cwd: () => '/foo', env: {} }), path.resolve('/foo/dir'), 'should use cwd when --user-data-dir is specified'); @@ -55,11 +55,11 @@ suite('EnvironmentService', () => { // https://github.com/microsoft/vscode/issues/78440 test('careful with boolean file names', function () { - let actual = parseArgs(['-r', 'arg.txt']); + let actual = parseArgs(['-r', 'arg.txt'], OPTIONS); assert(actual['reuse-window']); assert.deepEqual(actual._, ['arg.txt']); - actual = parseArgs(['-r', 'true.txt']); + actual = parseArgs(['-r', 'true.txt'], OPTIONS); assert(actual['reuse-window']); assert.deepEqual(actual._, ['true.txt']); }); diff --git a/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts b/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts index f579807f76c..aa652515737 100644 --- a/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts +++ b/src/vs/platform/extensionManagement/test/node/extensionGalleryService.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import * as os from 'os'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { join } from 'vs/base/common/path'; import { mkdirp, RimRafMode, rimraf } from 'vs/base/node/pfs'; @@ -51,7 +51,7 @@ suite('Extension Gallery Service', () => { test('marketplace machine id', () => { const args = ['--user-data-dir', marketplaceHome]; - const environmentService = new EnvironmentService(parseArgs(args), process.execPath); + const environmentService = new EnvironmentService(parseArgs(args, OPTIONS), process.execPath); return resolveMarketplaceHeaders(pkg.version, environmentService, fileService).then(headers => { assert.ok(isUUID(headers['X-Market-User-Id'])); @@ -61,4 +61,4 @@ suite('Extension Gallery Service', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/platform/issue/electron-main/issueService.ts b/src/vs/platform/issue/electron-main/issueService.ts index 5bea35cbefc..3db9cd642a6 100644 --- a/src/vs/platform/issue/electron-main/issueService.ts +++ b/src/vs/platform/issue/electron-main/issueService.ts @@ -5,7 +5,7 @@ import { localize } from 'vs/nls'; import * as objects from 'vs/base/common/objects'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { IIssueService, IssueReporterData, IssueReporterFeatures, ProcessExplorerData } from 'vs/platform/issue/node/issue'; import { BrowserWindow, ipcMain, screen, Event, dialog } from 'electron'; import { ILaunchService } from 'vs/platform/launch/electron-main/launchService'; @@ -372,7 +372,7 @@ export class IssueService implements IIssueService { } function toLauchUrl(pathToHtml: string, windowConfiguration: T): string { - const environment = parseArgs(process.argv); + const environment = parseArgs(process.argv, OPTIONS); const config = objects.assign(environment, windowConfiguration); for (const keyValue of Object.keys(config)) { const key = keyValue as keyof typeof config; diff --git a/src/vs/platform/storage/test/node/storageService.test.ts b/src/vs/platform/storage/test/node/storageService.test.ts index 6cb2f835d76..e2c984125b9 100644 --- a/src/vs/platform/storage/test/node/storageService.test.ts +++ b/src/vs/platform/storage/test/node/storageService.test.ts @@ -12,7 +12,7 @@ import { tmpdir } from 'os'; import { mkdirp, rimraf, RimRafMode } from 'vs/base/node/pfs'; import { NullLogService } from 'vs/platform/log/common/log'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { InMemoryStorageDatabase } from 'vs/base/parts/storage/common/storage'; suite('StorageService', () => { @@ -86,7 +86,7 @@ suite('StorageService', () => { class StorageTestEnvironmentService extends EnvironmentService { constructor(private workspaceStorageFolderPath: string, private _extensionsPath: string) { - super(parseArgs(process.argv), process.execPath); + super(parseArgs(process.argv, OPTIONS), process.execPath); } get workspaceStorageHome(): string { @@ -117,4 +117,4 @@ suite('StorageService', () => { await storage.close(); await rimraf(storageDir, RimRafMode.MOVE); }); -}); \ No newline at end of file +}); diff --git a/src/vs/platform/url/node/urlIpc.ts b/src/vs/platform/url/common/urlIpc.ts similarity index 65% rename from src/vs/platform/url/node/urlIpc.ts rename to src/vs/platform/url/common/urlIpc.ts index 74e482f9817..b692e67dfd9 100644 --- a/src/vs/platform/url/node/urlIpc.ts +++ b/src/vs/platform/url/common/urlIpc.ts @@ -3,11 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; +import { IChannel, IServerChannel, IClientRouter, IConnectionHub, Client } from 'vs/base/parts/ipc/common/ipc'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { first } from 'vs/base/common/arrays'; export class URLServiceChannel implements IServerChannel { @@ -70,3 +72,37 @@ export class URLHandlerChannelClient implements IURLHandler { return this.channel.call('handleURL', uri.toJSON()); } } + +export class URLHandlerRouter implements IClientRouter { + + constructor(private next: IClientRouter) { } + + async routeCall(hub: IConnectionHub, command: string, arg?: any, cancellationToken?: CancellationToken): Promise> { + if (command !== 'handleURL') { + throw new Error(`Call not found: ${command}`); + } + + if (arg) { + const uri = URI.revive(arg); + + if (uri && uri.query) { + const match = /\bwindowId=([^&]+)/.exec(uri.query); + + if (match) { + const windowId = match[1]; + const connection = first(hub.connections, c => c.ctx === windowId); + + if (connection) { + return connection; + } + } + } + } + + return this.next.routeCall(hub, command, arg, cancellationToken); + } + + routeEvent(_: IConnectionHub, event: string): Promise> { + throw new Error(`Event not found: ${event}`); + } +} diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts index 16b3f1d60d7..2cad1c5f1f4 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts @@ -9,7 +9,7 @@ import * as os from 'os'; import * as path from 'vs/base/common/path'; import * as pfs from 'vs/base/node/pfs'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { WorkspacesMainService, IStoredWorkspace } from 'vs/platform/workspaces/electron-main/workspacesMainService'; import { WORKSPACE_EXTENSION, IWorkspaceIdentifier, IRawFileWorkspaceFolder, IWorkspaceFolderCreationData, IRawUriWorkspaceFolder, rewriteWorkspaceFileForNewLocation } from 'vs/platform/workspaces/common/workspaces'; import { NullLogService } from 'vs/platform/log/common/log'; @@ -47,7 +47,7 @@ suite('WorkspacesMainService', () => { return service.createUntitledWorkspaceSync(folders.map((folder, index) => ({ uri: URI.file(folder), name: names ? names[index] : undefined } as IWorkspaceFolderCreationData))); } - const environmentService = new TestEnvironmentService(parseArgs(process.argv), process.execPath); + const environmentService = new TestEnvironmentService(parseArgs(process.argv, OPTIONS), process.execPath); const logService = new NullLogService(); let service: TestWorkspacesMainService; diff --git a/src/vs/workbench/api/browser/mainThreadEditor.ts b/src/vs/workbench/api/browser/mainThreadEditor.ts index ff8e1cd5138..520801babe6 100644 --- a/src/vs/workbench/api/browser/mainThreadEditor.ts +++ b/src/vs/workbench/api/browser/mainThreadEditor.ts @@ -6,7 +6,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { RenderLineNumbersType, TextEditorCursorStyle, cursorStyleToString } from 'vs/editor/common/config/editorOptions'; +import { RenderLineNumbersType, TextEditorCursorStyle, cursorStyleToString, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IRange, Range } from 'vs/editor/common/core/range'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; @@ -58,9 +58,10 @@ export class MainThreadTextEditorProperties { let cursorStyle: TextEditorCursorStyle; let lineNumbers: RenderLineNumbersType; if (codeEditor) { - const codeEditorOpts = codeEditor.getConfiguration(); - cursorStyle = codeEditorOpts.viewInfo.cursorStyle; - lineNumbers = codeEditorOpts.viewInfo.renderLineNumbers; + const options = codeEditor.getOptions(); + const lineNumbersOpts = options.get(EditorOption.lineNumbers); + cursorStyle = options.get(EditorOption.cursorStyle); + lineNumbers = lineNumbersOpts.renderType; } else if (previousProperties) { cursorStyle = previousProperties.options.cursorStyle; lineNumbers = previousProperties.options.lineNumbers; diff --git a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts index 1bd75108c5a..c849ba99630 100644 --- a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts @@ -10,7 +10,6 @@ import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { trimTrailingWhitespace } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand'; -import { ICodeActionsOnSaveOptions } from 'vs/editor/common/config/editorOptions'; import { EditOperation } from 'vs/editor/common/core/editOperation'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; @@ -34,6 +33,10 @@ import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textF import { ISaveParticipant, SaveReason, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; import { ExtHostContext, ExtHostDocumentSaveParticipantShape, IExtHostContext } from '../common/extHost.protocol'; +export interface ICodeActionsOnSaveOptions { + [kind: string]: boolean; +} + export interface ISaveParticipantParticipant extends ISaveParticipant { // progressMessage: string; } @@ -243,7 +246,8 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { constructor( @IBulkEditService private readonly _bulkEditService: IBulkEditService, @ICommandService private readonly _commandService: ICommandService, - @IConfigurationService private readonly _configurationService: IConfigurationService + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { } async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise { @@ -309,7 +313,7 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { private async applyCodeActions(actionsToRun: readonly CodeAction[]) { for (const action of actionsToRun) { - await applyCodeAction(action, this._bulkEditService, this._commandService); + await this._instantiationService.invokeFunction(applyCodeAction, action, this._bulkEditService, this._commandService); } } diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 915c264daea..f863036452a 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -52,6 +52,7 @@ import { toLocalResource } from 'vs/base/common/resources'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; // Register String Editor Registry.as(EditorExtensions.Editors).registerEditor( @@ -412,12 +413,12 @@ editorCommands.setup(); // Touch Bar if (isMacintosh) { MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { - command: { id: NavigateBackwardsAction.ID, title: NavigateBackwardsAction.LABEL, iconLocation: { dark: URI.parse(require.toUrl('vs/workbench/browser/parts/editor/media/back-tb.png')) } }, + command: { id: NavigateBackwardsAction.ID, title: NavigateBackwardsAction.LABEL, iconLocation: { dark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/back-tb.png')) } }, group: 'navigation' }); MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { - command: { id: NavigateForwardAction.ID, title: NavigateForwardAction.LABEL, iconLocation: { dark: URI.parse(require.toUrl('vs/workbench/browser/parts/editor/media/forward-tb.png')) } }, + command: { id: NavigateForwardAction.ID, title: NavigateForwardAction.LABEL, iconLocation: { dark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/forward-tb.png')) } }, group: 'navigation' }); } @@ -447,7 +448,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands. MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All") }, group: '5_close', order: 10, when: ContextKeyExpr.has('config.workbench.editor.showTabs') }); MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: nls.localize('closeAllSaved', "Close Saved") }, group: '5_close', order: 20, when: ContextKeyExpr.has('config.workbench.editor.showTabs') }); -interface IEditorToolItem { id: string; title: string; iconDark: string; iconLight: string; } +interface IEditorToolItem { id: string; title: string; iconDark: URI; iconLight: URI; } function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | undefined, order: number, alternative?: IEditorToolItem): void { const item: IMenuItem = { @@ -455,8 +456,8 @@ function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | u id: primary.id, title: primary.title, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/browser/parts/editor/media/${primary.iconDark}`)), - light: URI.parse(require.toUrl(`vs/workbench/browser/parts/editor/media/${primary.iconLight}`)) + dark: primary.iconDark, + light: primary.iconLight } }, group: 'navigation', @@ -469,8 +470,8 @@ function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | u id: alternative.id, title: alternative.title, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/browser/parts/editor/media/${alternative.iconDark}`)), - light: URI.parse(require.toUrl(`vs/workbench/browser/parts/editor/media/${alternative.iconLight}`)) + dark: alternative.iconDark, + light: alternative.iconLight } }; } @@ -483,16 +484,16 @@ appendEditorToolItem( { id: SplitEditorAction.ID, title: nls.localize('splitEditorRight', "Split Editor Right"), - iconDark: 'split-editor-horizontal-dark.svg', - iconLight: 'split-editor-horizontal-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-horizontal-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-horizontal-light.svg')) }, ContextKeyExpr.not('splitEditorsVertically'), 100000, // towards the end { id: editorCommands.SPLIT_EDITOR_DOWN, title: nls.localize('splitEditorDown', "Split Editor Down"), - iconDark: 'split-editor-vertical-dark.svg', - iconLight: 'split-editor-vertical-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-vertical-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-vertical-light.svg')) } ); @@ -500,16 +501,16 @@ appendEditorToolItem( { id: SplitEditorAction.ID, title: nls.localize('splitEditorDown', "Split Editor Down"), - iconDark: 'split-editor-vertical-dark.svg', - iconLight: 'split-editor-vertical-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-vertical-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-vertical-light.svg')) }, ContextKeyExpr.has('splitEditorsVertically'), 100000, // towards the end { id: editorCommands.SPLIT_EDITOR_RIGHT, title: nls.localize('splitEditorRight', "Split Editor Right"), - iconDark: 'split-editor-horizontal-dark.svg', - iconLight: 'split-editor-horizontal-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-horizontal-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-horizontal-light.svg')) } ); @@ -518,16 +519,16 @@ appendEditorToolItem( { id: editorCommands.CLOSE_EDITOR_COMMAND_ID, title: nls.localize('close', "Close"), - iconDark: 'close-dark-alt.svg', - iconLight: 'close-light-alt.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-dark-alt.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-light-alt.svg')) }, ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ContextKeyExpr.not('groupActiveEditorDirty')), 1000000, // towards the far end { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All"), - iconDark: 'close-all-dark.svg', - iconLight: 'close-all-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-all-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-all-light.svg')) } ); @@ -535,16 +536,16 @@ appendEditorToolItem( { id: editorCommands.CLOSE_EDITOR_COMMAND_ID, title: nls.localize('close', "Close"), - iconDark: 'close-dirty-dark-alt.svg', - iconLight: 'close-dirty-light-alt.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-dirty-dark-alt.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-dirty-light-alt.svg')) }, ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ContextKeyExpr.has('groupActiveEditorDirty')), 1000000, // towards the far end { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All"), - iconDark: 'close-all-dark.svg', - iconLight: 'close-all-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-all-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-all-light.svg')) } ); @@ -553,8 +554,8 @@ appendEditorToolItem( { id: editorCommands.GOTO_PREVIOUS_CHANGE, title: nls.localize('navigate.prev.label', "Previous Change"), - iconDark: 'previous-diff-dark.svg', - iconLight: 'previous-diff-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/previous-diff-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/previous-diff-light.svg')) }, TextCompareEditorActiveContext, 10 @@ -565,8 +566,8 @@ appendEditorToolItem( { id: editorCommands.GOTO_NEXT_CHANGE, title: nls.localize('navigate.next.label', "Next Change"), - iconDark: 'next-diff-dark.svg', - iconLight: 'next-diff-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/next-diff-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/next-diff-light.svg')) }, TextCompareEditorActiveContext, 11 @@ -577,8 +578,8 @@ appendEditorToolItem( { id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, title: nls.localize('ignoreTrimWhitespace.label', "Ignore Trim Whitespace"), - iconDark: 'paragraph-dark.svg', - iconLight: 'paragraph-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-light.svg')) }, ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', true)), 20 @@ -589,8 +590,8 @@ appendEditorToolItem( { id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, title: nls.localize('showTrimWhitespace.label', "Show Trim Whitespace"), - iconDark: 'paragraph-disabled-dark.svg', - iconLight: 'paragraph-disabled-light.svg' + iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-disabled-dark.svg')), + iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-disabled-light.svg')) }, ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', false)), 20 diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index ed5bbacdd3e..67940979ba6 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -35,7 +35,7 @@ import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/c import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ITextFileService, SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; -import { IConfigurationChangedEvent, IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { deepClone } from 'vs/base/common/objects'; @@ -583,8 +583,8 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { if (activeCodeEditor) { // Hook Listener for Configuration changes - this.activeEditorListeners.add(activeCodeEditor.onDidChangeConfiguration((event: IConfigurationChangedEvent) => { - if (event.accessibilitySupport) { + this.activeEditorListeners.add(activeCodeEditor.onDidChangeConfiguration((event: ConfigurationChangedEvent) => { + if (event.hasChanged(EditorOption.accessibilitySupport)) { this.onScreenReaderModeChange(activeCodeEditor); } })); @@ -708,7 +708,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } } - screenReaderMode = (editorWidget.getConfiguration().accessibilitySupport === AccessibilitySupport.Enabled); + screenReaderMode = (editorWidget.getOption(EditorOption.accessibilitySupport) === AccessibilitySupport.Enabled); } if (screenReaderMode === false && this.screenReaderNotification) { @@ -758,7 +758,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { private onEOLChange(editorWidget: ICodeEditor | undefined): void { const info: StateDelta = { EOL: undefined }; - if (editorWidget && !editorWidget.getConfiguration().readOnly) { + if (editorWidget && !editorWidget.getOption(EditorOption.readOnly)) { const codeEditorModel = editorWidget.getModel(); if (codeEditorModel) { info.EOL = codeEditorModel.getEOL(); @@ -819,8 +819,7 @@ function isWritableCodeEditor(codeEditor: ICodeEditor | undefined): boolean { if (!codeEditor) { return false; } - const config = codeEditor.getConfiguration(); - return (!config.readOnly); + return !codeEditor.getOption(EditorOption.readOnly); } function isWritableBaseEditor(e: IBaseEditor): boolean { diff --git a/src/vs/workbench/browser/parts/editor/media/close-dirty-inverse-alt.svg b/src/vs/workbench/browser/parts/editor/media/close-dirty-inverse-alt.svg deleted file mode 100644 index 02dafab76fc..00000000000 --- a/src/vs/workbench/browser/parts/editor/media/close-dirty-inverse-alt.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor/media/close-dirty-inverse.svg b/src/vs/workbench/browser/parts/editor/media/close-dirty-inverse.svg deleted file mode 100644 index 02dafab76fc..00000000000 --- a/src/vs/workbench/browser/parts/editor/media/close-dirty-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css b/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css index edce36d6ec8..8bc05e970dd 100644 --- a/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css @@ -81,6 +81,7 @@ display: flex; flex: initial; opacity: 0.5; + padding-right: 8px; height: 35px; } diff --git a/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css b/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css index 0dbc324ad17..086b72fa8b9 100644 --- a/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css @@ -268,7 +268,7 @@ .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions { cursor: default; flex: initial; - padding-left: 4px; + padding: 0 8px 0 4px; height: 35px; } diff --git a/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css index fb9a8f4bf2f..9dc9bb2000f 100644 --- a/src/vs/workbench/browser/parts/panel/media/panelpart.css +++ b/src/vs/workbench/browser/parts/panel/media/panelpart.css @@ -13,7 +13,6 @@ } .monaco-workbench .part.panel .title { - padding-right: 0px; height: 35px; display: flex; flex-direction: row; diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index 5a65a51a76d..2fb6387d5c4 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -44,6 +44,7 @@ import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; const $ = dom.$; @@ -51,8 +52,8 @@ type Writeable = { -readonly [P in keyof T]: T[P] }; const backButton = { iconPath: { - dark: URI.parse(require.toUrl('vs/workbench/browser/parts/quickinput/media/arrow-left-dark.svg')), - light: URI.parse(require.toUrl('vs/workbench/browser/parts/quickinput/media/arrow-left-light.svg')) + dark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/quickinput/media/arrow-left-dark.svg')), + light: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/quickinput/media/arrow-left-light.svg')) }, tooltip: localize('quickInput.back', "Back"), handle: -1 // TODO diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index 4b9b68f9ccc..9d9ec42277d 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -597,16 +597,8 @@ export class CustomTreeView extends Disposable implements ITreeView { const tree = this.tree; if (tree) { this.refreshing = true; - const parents: Set = new Set(); - elements.forEach(element => { - if (element !== this.root) { - const parent = tree.getParentElement(element); - parents.add(parent); - } else { - parents.add(element); - } - }); - await Promise.all(Array.from(parents.values()).map(element => tree.updateChildren(element, true))); + await Promise.all(elements.map(element => tree.updateChildren(element, true))); + elements.map(element => tree.rerender(element)); this.refreshing = false; this.updateContentAreas(); if (this.focused) { diff --git a/src/vs/workbench/buildfile.web.js b/src/vs/workbench/buildfile.web.js index 47a84533025..ac2dec472bd 100644 --- a/src/vs/workbench/buildfile.web.js +++ b/src/vs/workbench/buildfile.web.js @@ -20,5 +20,6 @@ function createModuleDescription(name, exclude) { exports.collectModules = function () { return [ createModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer', ['vs/base/common/worker/simpleWorker', 'vs/editor/common/services/editorSimpleWorker']), + createModuleDescription('vs/code/browser/workbench/web.main', ['vs/workbench/workbench.web.api']), ]; }; diff --git a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts index a45ab650031..4e2253b8731 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts @@ -17,7 +17,7 @@ import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { EditorAction, EditorCommand, registerEditorAction, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ToggleTabFocusModeAction } from 'vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode'; @@ -185,13 +185,13 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { } private _buildContent() { - let opts = this._editor.getConfiguration(); + const options = this._editor.getOptions(); let text = nls.localize('introMsg', "Thank you for trying out VS Code's accessibility options."); text += '\n\n' + nls.localize('status', "Status:"); - const configuredValue = this._configurationService.getValue('editor').accessibilitySupport; - const actualValue = opts.accessibilitySupport; + const configuredValue = this._configurationService.getValue('editor').accessibilitySupport; + const actualValue = options.get(EditorOption.accessibilitySupport); const emergencyTurnOnMessage = ( platform.isMacintosh @@ -229,7 +229,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { const NLS_TAB_FOCUS_MODE_OFF = nls.localize('tabFocusModeOffMsg', "Pressing Tab in the current editor will insert the tab character. Toggle this behavior by pressing {0}."); const NLS_TAB_FOCUS_MODE_OFF_NO_KB = nls.localize('tabFocusModeOffMsgNoKb', "Pressing Tab in the current editor will insert the tab character. The command {0} is currently not triggerable by a keybinding."); - if (opts.tabFocusMode) { + if (options.get(EditorOption.tabFocusMode)) { text += '\n\n - ' + this._descriptionForCommand(ToggleTabFocusModeAction.ID, NLS_TAB_FOCUS_MODE_ON, NLS_TAB_FOCUS_MODE_ON_NO_KB); } else { text += '\n\n - ' + this._descriptionForCommand(ToggleTabFocusModeAction.ID, NLS_TAB_FOCUS_MODE_OFF, NLS_TAB_FOCUS_MODE_OFF_NO_KB); diff --git a/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts b/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts index 4c3a8ba75ff..ebf9955db2a 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts @@ -9,7 +9,7 @@ import * as process from 'vs/base/common/process'; import * as platform from 'vs/base/common/platform'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { Range } from 'vs/editor/common/core/range'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; @@ -24,11 +24,11 @@ export class SelectionClipboard extends Disposable implements IEditorContributio super(); if (platform.isLinux) { - let isEnabled = editor.getConfiguration().contribInfo.selectionClipboard; + let isEnabled = editor.getOption(EditorOption.selectionClipboard); - this._register(editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.contribInfo) { - isEnabled = editor.getConfiguration().contribInfo.selectionClipboard; + this._register(editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.selectionClipboard)) { + isEnabled = editor.getOption(EditorOption.selectionClipboard); } })); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts index eb15bf10a1f..83b3a7bb271 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts @@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri'; import { 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 { EDITOR_DEFAULTS, InternalEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { EditorOption, EditorOptions } from 'vs/editor/common/config/editorOptions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; @@ -19,6 +19,7 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { DefaultSettingsEditorContribution } from 'vs/workbench/contrib/preferences/browser/preferencesEditor'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; const transientWordWrapState = 'transientWordWrapState'; const isWordWrapMinifiedKey = 'isWordWrapMinified'; @@ -68,7 +69,7 @@ function readWordWrapState(model: ITextModel, configurationService: ITextResourc const _transientState = readTransientState(model, codeEditorService); return { configuredWordWrap: _configuredWordWrap, - configuredWordWrapMinified: (typeof _configuredWordWrapMinified === 'boolean' ? _configuredWordWrapMinified : EDITOR_DEFAULTS.wordWrapMinified), + configuredWordWrapMinified: (typeof _configuredWordWrapMinified === 'boolean' ? _configuredWordWrapMinified : EditorOptions.wordWrapMinified.defaultValue), transientState: _transientState }; } @@ -83,10 +84,9 @@ function toggleWordWrap(editor: ICodeEditor, state: IWordWrapState): IWordWrapSt }; } - const config = editor.getConfiguration(); let transientState: IWordWrapTransientState; - const actualWrappingInfo = config.wrappingInfo; + const actualWrappingInfo = editor.getOption(EditorOption.wrappingInfo); if (actualWrappingInfo.isWordWrapMinified) { // => wrapping due to minified file transientState = { @@ -139,8 +139,7 @@ class ToggleWordWrapAction extends EditorAction { if (!editor.hasModel()) { return; } - const editorConfiguration = editor.getConfiguration(); - if (editorConfiguration.wrappingInfo.inDiffEditor) { + if (editor.getOption(EditorOption.inDiffEditor)) { // Cannot change wrapping settings inside the diff editor const notificationService = accessor.get(INotificationService); notificationService.info(nls.localize('wordWrap.notInDiffEditor', "Cannot toggle word wrap in a diff editor.")); @@ -177,20 +176,22 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution ) { super(); - const configuration = this.editor.getConfiguration(); - const isWordWrapMinified = this.contextKeyService.createKey(isWordWrapMinifiedKey, this._isWordWrapMinified(configuration)); - const isDominatedByLongLines = this.contextKeyService.createKey(isDominatedByLongLinesKey, this._isDominatedByLongLines(configuration)); - const inDiffEditor = this.contextKeyService.createKey(inDiffEditorKey, this._inDiffEditor(configuration)); + const options = this.editor.getOptions(); + const wrappingInfo = options.get(EditorOption.wrappingInfo); + const isWordWrapMinified = this.contextKeyService.createKey(isWordWrapMinifiedKey, wrappingInfo.isWordWrapMinified); + const isDominatedByLongLines = this.contextKeyService.createKey(isDominatedByLongLinesKey, wrappingInfo.isDominatedByLongLines); + const inDiffEditor = this.contextKeyService.createKey(inDiffEditorKey, options.get(EditorOption.inDiffEditor)); let currentlyApplyingEditorConfig = false; this._register(editor.onDidChangeConfiguration((e) => { - if (!e.wrappingInfo) { + if (!e.hasChanged(EditorOption.wrappingInfo) && !e.hasChanged(EditorOption.inDiffEditor)) { return; } - const configuration = this.editor.getConfiguration(); - isWordWrapMinified.set(this._isWordWrapMinified(configuration)); - isDominatedByLongLines.set(this._isDominatedByLongLines(configuration)); - inDiffEditor.set(this._inDiffEditor(configuration)); + const options = this.editor.getOptions(); + const wrappingInfo = options.get(EditorOption.wrappingInfo); + isWordWrapMinified.set(wrappingInfo.isWordWrapMinified); + isDominatedByLongLines.set(wrappingInfo.isDominatedByLongLines); + inDiffEditor.set(options.get(EditorOption.inDiffEditor)); if (!currentlyApplyingEditorConfig) { // I am not the cause of the word wrap getting changed ensureWordWrapSettings(); @@ -216,8 +217,7 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution return; } - const configuration = this.editor.getConfiguration(); - if (this._inDiffEditor(configuration)) { + if (this.editor.getOption(EditorOption.inDiffEditor)) { return; } @@ -255,18 +255,6 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution }); } - private _isWordWrapMinified(config: InternalEditorOptions): boolean { - return config.wrappingInfo.isWordWrapMinified; - } - - private _isDominatedByLongLines(config: InternalEditorOptions): boolean { - return config.wrappingInfo.isDominatedByLongLines; - } - - private _inDiffEditor(config: InternalEditorOptions): boolean { - return config.wrappingInfo.inDiffEditor; - } - public getId(): string { return ToggleWordWrapController._ID; } @@ -289,8 +277,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: TOGGLE_WORD_WRAP_ID, title: nls.localize('unwrapMinified', "Disable wrapping for this file"), iconLocation: { - dark: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg')), - light: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg')) + dark: URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg')), + light: URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg')) } }, group: 'navigation', @@ -306,8 +294,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: TOGGLE_WORD_WRAP_ID, title: nls.localize('wrapMinified', "Enable wrapping for this file"), iconLocation: { - dark: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg')), - light: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg')) + dark: URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg')), + light: URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg')) } }, group: 'navigation', diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts index 0bd28e5fe58..8691a8105d5 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts @@ -44,6 +44,7 @@ import { ICommentService } from 'vs/workbench/contrib/comments/browser/commentSe import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/commentContextKeys'; import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget'; import { SimpleCommentEditor } from './simpleCommentEditor'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const COMMENTEDITOR_DECORATION_KEY = 'commenteditordecoration'; const COLLAPSE_ACTION_CLASS = 'expand-review-action'; @@ -128,7 +129,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._styleElement = dom.createStyleSheet(this.domNode); this._globalToDispose.add(this.themeService.onThemeChange(this._applyTheme, this)); this._globalToDispose.add(this.editor.onDidChangeConfiguration(e => { - if (e.fontInfo) { + if (e.hasChanged(EditorOption.fontInfo)) { this._applyTheme(this.themeService.getTheme()); } })); @@ -386,7 +387,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._disposables.add(this.editor.onMouseDown(e => this.onEditorMouseDown(e))); this._disposables.add(this.editor.onMouseUp(e => this.onEditorMouseUp(e))); - let headHeight = Math.ceil(this.editor.getConfiguration().lineHeight * 1.2); + let headHeight = Math.ceil(this.editor.getOption(EditorOption.lineHeight) * 1.2); this._headElement.style.height = `${headHeight}px`; this._headElement.style.lineHeight = this._headElement.style.height; @@ -692,8 +693,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget _refresh() { if (this._isExpanded && this._bodyElement) { let dimensions = dom.getClientArea(this._bodyElement); - const headHeight = Math.ceil(this.editor.getConfiguration().lineHeight * 1.2); - const lineHeight = this.editor.getConfiguration().lineHeight; + const headHeight = Math.ceil(this.editor.getOption(EditorOption.lineHeight) * 1.2); + const lineHeight = this.editor.getOption(EditorOption.lineHeight); const arrowHeight = Math.round(lineHeight / 3); const frameThickness = Math.round(lineHeight / 9) * 2; @@ -854,7 +855,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget content.push(`.monaco-editor .review-widget .body .comment-form .validation-error { color: ${errorForeground}; }`); } - const fontInfo = this.editor.getConfiguration().fontInfo; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); content.push(`.monaco-editor .review-widget .body code { font-family: ${fontInfo.fontFamily}; font-size: ${fontInfo.fontSize}px; diff --git a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index d5cfcfb4f19..631d8939f72 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts @@ -37,6 +37,7 @@ import { COMMENTEDITOR_DECORATION_KEY, ReviewZoneWidget } from 'vs/workbench/con import { ctxCommentEditorFocused, SimpleCommentEditor } from 'vs/workbench/contrib/comments/browser/simpleCommentEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const ID = 'editor.contrib.review'; @@ -590,18 +591,19 @@ export class ReviewController implements IEditorContribution { } this._commentInfos = commentInfos; - let lineDecorationsWidth: number = this.editor.getConfiguration().layoutInfo.decorationsWidth; + let lineDecorationsWidth: number = this.editor.getLayoutInfo().decorationsWidth; if (this._commentInfos.some(info => Boolean(info.commentingRanges && (Array.isArray(info.commentingRanges) ? info.commentingRanges : info.commentingRanges.ranges).length))) { if (!this._commentingRangeSpaceReserved) { this._commentingRangeSpaceReserved = true; let extraEditorClassName: string[] = []; - const configuredExtraClassName = this.editor.getRawConfiguration().extraEditorClassName; + const configuredExtraClassName = this.editor.getRawOptions().extraEditorClassName; if (configuredExtraClassName) { extraEditorClassName = configuredExtraClassName.split(' '); } - if (this.editor.getConfiguration().contribInfo.folding) { + const options = this.editor.getOptions(); + if (options.get(EditorOption.folding)) { lineDecorationsWidth -= 16; } lineDecorationsWidth += 9; diff --git a/src/vs/workbench/contrib/debug/browser/baseDebugView.ts b/src/vs/workbench/contrib/debug/browser/baseDebugView.ts index 67f2b1ade60..f9dee4d8ca9 100644 --- a/src/vs/workbench/contrib/debug/browser/baseDebugView.ts +++ b/src/vs/workbench/contrib/debug/browser/baseDebugView.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { IExpression, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; +import { IExpression, IDebugService, IExpressionContainer } from 'vs/workbench/contrib/debug/common/debug'; import { Expression, Variable, ExpressionContainer } from 'vs/workbench/contrib/debug/common/debugModel'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInputValidationOptions, InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; @@ -50,7 +50,7 @@ export function replaceWhitespace(value: string): string { return value.replace(/[\n\r\t]/g, char => map[char]); } -export function renderExpressionValue(expressionOrValue: IExpression | string, container: HTMLElement, options: IRenderValueOptions): void { +export function renderExpressionValue(expressionOrValue: IExpressionContainer | string, container: HTMLElement, options: IRenderValueOptions): void { let value = typeof expressionOrValue === 'string' ? expressionOrValue : expressionOrValue.value; // remove stale classes @@ -221,4 +221,4 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer(WorkbenchExtensions.Workbench).regi // Debug toolbar -const registerDebugToolBarItem = (id: string, title: string, icon: string, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => { +const registerDebugToolBarItem = (id: string, title: string, iconLightUri: URI, iconDarkUri: URI, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => { MenuRegistry.appendMenuItem(MenuId.DebugToolBar, { group: 'navigation', when, @@ -280,24 +281,24 @@ const registerDebugToolBarItem = (id: string, title: string, icon: string, order id, title, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}-dark.svg`)) + light: iconLightUri, + dark: iconDarkUri }, precondition } }); }; -registerDebugToolBarItem(CONTINUE_ID, CONTINUE_LABEL, 'continue', 10, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(PAUSE_ID, PAUSE_LABEL, 'pause', 10, CONTEXT_DEBUG_STATE.notEqualsTo('stopped')); -registerDebugToolBarItem(STOP_ID, STOP_LABEL, 'stop', 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated()); -registerDebugToolBarItem(DISCONNECT_ID, DISCONNECT_LABEL, 'disconnect', 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH); -registerDebugToolBarItem(STEP_OVER_ID, STEP_OVER_LABEL, 'step-over', 20, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(STEP_INTO_ID, STEP_INTO_LABEL, 'step-into', 30, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(STEP_OUT_ID, STEP_OUT_LABEL, 'step-out', 40, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(RESTART_SESSION_ID, RESTART_LABEL, 'restart', 60); -registerDebugToolBarItem(STEP_BACK_ID, nls.localize('stepBackDebug', "Step Back"), 'step-back', 50, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(REVERSE_CONTINUE_ID, nls.localize('reverseContinue', "Reverse"), 'reverse-continue', 60, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(CONTINUE_ID, CONTINUE_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-dark.svg')), 10, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(PAUSE_ID, PAUSE_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-dark.svg')), 10, CONTEXT_DEBUG_STATE.notEqualsTo('stopped')); +registerDebugToolBarItem(STOP_ID, STOP_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-dark.svg')), 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated()); +registerDebugToolBarItem(DISCONNECT_ID, DISCONNECT_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/disconnect-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/disconnect-dark.svg')), 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH); +registerDebugToolBarItem(STEP_OVER_ID, STEP_OVER_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-over-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-over-dark.svg')), 20, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(STEP_INTO_ID, STEP_INTO_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-into-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-into-dark.svg')), 30, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(STEP_OUT_ID, STEP_OUT_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-out-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-out-dark.svg')), 40, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(RESTART_SESSION_ID, RESTART_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-dark.svg')), 60); +registerDebugToolBarItem(STEP_BACK_ID, nls.localize('stepBackDebug', "Step Back"), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-back-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-back-dark.svg')), 50, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugToolBarItem(REVERSE_CONTINUE_ID, nls.localize('reverseContinue', "Reverse"), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/reverse-continue-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/reverse-continue-dark.svg')), 60, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); // Debug callstack context menu const registerDebugCallstackItem = (id: string, title: string, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr, group = 'navigation') => { @@ -537,12 +538,12 @@ MenuRegistry.appendMenuItem(MenuId.MenubarDebugMenu, { // Touch Bar if (isMacintosh) { - const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr | undefined, icon: string) => { + const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr | undefined, iconUri: URI) => { MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { command: { id, title, - iconLocation: { dark: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}`)) } + iconLocation: { dark: iconUri } }, when, group: '9_debug', @@ -550,13 +551,13 @@ if (isMacintosh) { }); }; - registerTouchBarEntry(StartAction.ID, StartAction.LABEL, 0, CONTEXT_IN_DEBUG_MODE.toNegated(), 'continue-tb.png'); - registerTouchBarEntry(RunAction.ID, RunAction.LABEL, 1, CONTEXT_IN_DEBUG_MODE.toNegated(), 'continue-without-debugging-tb.png'); - registerTouchBarEntry(CONTINUE_ID, CONTINUE_LABEL, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'continue-tb.png'); - registerTouchBarEntry(PAUSE_ID, PAUSE_LABEL, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), 'pause-tb.png'); - registerTouchBarEntry(STEP_OVER_ID, STEP_OUT_LABEL, 2, CONTEXT_IN_DEBUG_MODE, 'stepover-tb.png'); - registerTouchBarEntry(STEP_INTO_ID, STEP_INTO_LABEL, 3, CONTEXT_IN_DEBUG_MODE, 'stepinto-tb.png'); - registerTouchBarEntry(STEP_OUT_ID, STEP_OUT_LABEL, 4, CONTEXT_IN_DEBUG_MODE, 'stepout-tb.png'); - registerTouchBarEntry(RESTART_SESSION_ID, RESTART_LABEL, 5, CONTEXT_IN_DEBUG_MODE, 'restart-tb.png'); - registerTouchBarEntry(STOP_ID, STOP_LABEL, 6, CONTEXT_IN_DEBUG_MODE, 'stop-tb.png'); + registerTouchBarEntry(StartAction.ID, StartAction.LABEL, 0, CONTEXT_IN_DEBUG_MODE.toNegated(), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-tb.png'))); + registerTouchBarEntry(RunAction.ID, RunAction.LABEL, 1, CONTEXT_IN_DEBUG_MODE.toNegated(), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-without-debugging-tb.png'))); + registerTouchBarEntry(CONTINUE_ID, CONTINUE_LABEL, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-tb.png'))); + registerTouchBarEntry(PAUSE_ID, PAUSE_LABEL, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-tb.png'))); + registerTouchBarEntry(STEP_OVER_ID, STEP_OUT_LABEL, 2, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stepover-tb.png'))); + registerTouchBarEntry(STEP_INTO_ID, STEP_INTO_LABEL, 3, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stepinto-tb.png'))); + registerTouchBarEntry(STEP_OUT_ID, STEP_OUT_LABEL, 4, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stepout-tb.png'))); + registerTouchBarEntry(RESTART_SESSION_ID, RESTART_LABEL, 5, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-tb.png'))); + registerTouchBarEntry(STOP_ID, STOP_LABEL, 6, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-tb.png'))); } diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index 2074a14ab74..0758b523ae3 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -41,7 +41,7 @@ import { ContextSubMenu } from 'vs/base/browser/contextmenu'; import { memoize } from 'vs/base/common/decorators'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { getHover } from 'vs/editor/contrib/hover/getHover'; -import { IEditorHoverOptions } from 'vs/editor/common/config/editorOptions'; +import { IEditorHoverOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { CancellationToken } from 'vs/base/common/cancellation'; import { BreakpointWidget } from 'vs/workbench/contrib/debug/browser/breakpointWidget'; import { DebugHoverWidget } from 'vs/workbench/contrib/debug/browser/debugHover'; @@ -540,7 +540,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { if (this.configurationWidget) { this.configurationWidget.dispose(); } - if (model && LAUNCH_JSON_REGEX.test(model.uri.toString()) && !this.editor.getConfiguration().readOnly) { + if (model && LAUNCH_JSON_REGEX.test(model.uri.toString()) && !this.editor.getOption(EditorOption.readOnly)) { this.configurationWidget = this.instantiationService.createInstance(FloatingClickWidget, this.editor, nls.localize('addConfiguration', "Add Configuration..."), null); this.configurationWidget.render(); this.toDispose.push(this.configurationWidget.onClick(() => this.addLaunchConfiguration())); diff --git a/src/vs/workbench/contrib/debug/browser/debugHover.ts b/src/vs/workbench/contrib/debug/browser/debugHover.ts index e4f23037af0..2c7dd35cf15 100644 --- a/src/vs/workbench/contrib/debug/browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/browser/debugHover.ts @@ -9,7 +9,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import * as dom from 'vs/base/browser/dom'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { IContentWidget, ICodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; @@ -114,8 +114,8 @@ export class DebugHoverWidget implements IContentWidget { this.hide(); } })); - this.toDispose.push(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - if (e.fontInfo) { + this.toDispose.push(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.fontInfo)) { this.editor.applyFontInfo(this.domNode); } })); diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index 863fbb4e5bb..13898ad10bb 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -44,6 +44,7 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { IDebugService, State, IDebugSession, CONTEXT_DEBUG_TYPE, CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_MODE, IThread, IDebugConfiguration, VIEWLET_ID, REPL_ID, IConfig, ILaunch, IViewModel, IConfigurationManager, IDebugModel, IEnablement, IBreakpoint, IBreakpointData, ICompound, IGlobalConfig, IStackFrame, AdapterEndEvent, getStateLabel } from 'vs/workbench/contrib/debug/common/debug'; import { isExtensionHostDebugging } from 'vs/workbench/contrib/debug/common/debugUtils'; import { isErrorWithActions, createErrorWithActions } from 'vs/base/common/errorsWithActions'; +import { RunOnceScheduler } from 'vs/base/common/async'; import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; @@ -492,7 +493,16 @@ export class DebugService implements IDebugService { } private registerSessionListeners(session: IDebugSession): void { + const sessionRunningScheduler = new RunOnceScheduler(() => { + // Do not immediatly defocus the stack frame if the session is running + if (session.state === State.Running && this.viewModel.focusedSession === session) { + this.viewModel.setFocus(undefined, this.viewModel.focusedThread, session, false); + } + }, 200); this.toDispose.push(session.onDidChangeState(() => { + if (session.state === State.Running && this.viewModel.focusedSession === session) { + sessionRunningScheduler.schedule(); + } if (session === this.viewModel.focusedSession) { this.onStateChange(); } diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index babed65d991..6f78bd0df67 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -921,7 +921,9 @@ export class DebugSession implements IDebugSession { } async addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise { - await this.repl.addReplExpression(stackFrame, name); + const expressionEvaluated = this.repl.addReplExpression(stackFrame, name); + this._onDidChangeREPLElements.fire(); + await expressionEvaluated; this._onDidChangeREPLElements.fire(); // Evaluate all watch expressions and fetch variables again since repl evaluation might have changed some. variableSetEmitter.fire(); diff --git a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts index 0d038ec13c9..913eaefc26c 100644 --- a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts +++ b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts @@ -15,6 +15,7 @@ import { Color } from 'vs/base/common/color'; import { registerColor } from 'vs/platform/theme/common/colorRegistry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const $ = dom.$; // theming @@ -62,7 +63,7 @@ export class ExceptionWidget extends ZoneWidget { protected _fillContainer(container: HTMLElement): void { this.setCssClass('exception-widget'); // Set the font size and line height to the one from the editor configuration. - const fontInfo = this.editor.getConfiguration().fontInfo; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); container.style.fontSize = `${fontInfo.fontSize}px`; container.style.lineHeight = `${fontInfo.lineHeight}px`; @@ -89,7 +90,7 @@ export class ExceptionWidget extends ZoneWidget { // Reload the height with respect to the exception text content and relayout it to match the line count. this.container!.style.height = 'initial'; - const lineHeight = this.editor.getConfiguration().lineHeight; + const lineHeight = this.editor.getOption(EditorOption.lineHeight); const arrowHeight = Math.round(lineHeight / 3); const computedLinesNumber = Math.ceil((this.container!.offsetHeight + arrowHeight) / lineHeight); diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-disabled.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-disabled.svg deleted file mode 100644 index 75c0a500f4d..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-disabled.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-unverified.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-unverified.svg deleted file mode 100644 index 85a35a44ff6..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/breakpoint-conditional-unverified.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/disconnect-white.svg b/src/vs/workbench/contrib/debug/browser/media/disconnect-white.svg new file mode 100644 index 00000000000..42e2e75e091 --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/disconnect-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/repl.css b/src/vs/workbench/contrib/debug/browser/media/repl.css index 7268724a281..b0ab0e6e71b 100644 --- a/src/vs/workbench/contrib/debug/browser/media/repl.css +++ b/src/vs/workbench/contrib/debug/browser/media/repl.css @@ -48,11 +48,13 @@ cursor: text; } -.repl .repl-tree .output.expression > .value { +.repl .repl-tree .output.expression > .value, +.repl .repl-tree .evaluation-result.expression > .value { margin-left: 0px; } -.repl .repl-tree .output.expression > .annotation { +.repl .repl-tree .output.expression > .annotation, +.repl .repl-tree .evaluation-result.expression > .annotation { font-size: inherit; padding-left: 6px; } @@ -67,7 +69,7 @@ } /* Only show 'stale expansion' info when the element gets expanded. */ -.repl .repl-tree .input-output-pair > .output > .annotation::before { +.repl .repl-tree .evaluation-result > .annotation::before { content: ''; } @@ -134,7 +136,8 @@ .monaco-workbench .repl .repl-tree .output.expression .code-underline { text-decoration: underline; } /* Links */ -.monaco-workbench .repl .repl-tree .output.expression a { +.monaco-workbench .repl .repl-tree .output.expression a, +.monaco-workbench .repl .repl-tree .evaluation-result.expression a { text-decoration: underline; cursor: pointer; } diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 4412e5bc720..f00dc8c6d99 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -44,7 +44,8 @@ import { CompletionContext, CompletionList, CompletionProviderRegistry } from 'v import { first } from 'vs/base/common/arrays'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; -import { Variable, Expression, SimpleReplElement, RawObjectReplElement } from 'vs/workbench/contrib/debug/common/debugModel'; +import { Variable } from 'vs/workbench/contrib/debug/common/debugModel'; +import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { ITreeRenderer, ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -412,7 +413,8 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati [ this.instantiationService.createInstance(VariablesRenderer), this.instantiationService.createInstance(ReplSimpleElementsRenderer), - new ReplExpressionsRenderer(), + new ReplEvaluationInputsRenderer(), + new ReplEvaluationResultsRenderer(), new ReplRawObjectsRenderer() ], // https://github.com/microsoft/TypeScript/issues/32526 @@ -568,12 +570,13 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati // Repl tree -interface IExpressionTemplateData { - input: HTMLElement; - output: HTMLElement; +interface IReplEvaluationInputTemplateData { + label: HighlightedLabel; +} + +interface IReplEvaluationResultTemplateData { value: HTMLElement; annotation: HTMLElement; - label: HighlightedLabel; } interface ISimpleReplElementTemplateData { @@ -593,27 +596,46 @@ interface IRawObjectReplTemplateData { label: HighlightedLabel; } -class ReplExpressionsRenderer implements ITreeRenderer { - static readonly ID = 'expressionRepl'; +class ReplEvaluationInputsRenderer implements ITreeRenderer { + static readonly ID = 'replEvaluationInput'; get templateId(): string { - return ReplExpressionsRenderer.ID; + return ReplEvaluationInputsRenderer.ID; } - renderTemplate(container: HTMLElement): IExpressionTemplateData { - dom.addClass(container, 'input-output-pair'); - const input = dom.append(container, $('.input.expression')); + renderTemplate(container: HTMLElement): IReplEvaluationInputTemplateData { + const input = dom.append(container, $('.expression')); const label = new HighlightedLabel(input, false); - const output = dom.append(container, $('.output.expression')); + return { label }; + } + + renderElement(element: ITreeNode, index: number, templateData: IReplEvaluationInputTemplateData): void { + const evaluation = element.element; + templateData.label.set(evaluation.value, createMatches(element.filterData)); + } + + disposeTemplate(templateData: IReplEvaluationInputTemplateData): void { + // noop + } +} + +class ReplEvaluationResultsRenderer implements ITreeRenderer { + static readonly ID = 'replEvaluationResult'; + + get templateId(): string { + return ReplEvaluationResultsRenderer.ID; + } + + renderTemplate(container: HTMLElement): IReplEvaluationResultTemplateData { + const output = dom.append(container, $('.evaluation-result.expression')); const value = dom.append(output, $('span.value')); const annotation = dom.append(output, $('span')); - return { input, label, output, value, annotation }; + return { value, annotation }; } - renderElement(element: ITreeNode, index: number, templateData: IExpressionTemplateData): void { + renderElement(element: ITreeNode, index: number, templateData: IReplEvaluationResultTemplateData): void { const expression = element.element; - templateData.label.set(expression.name, createMatches(element.filterData)); renderExpressionValue(expression, templateData.value, { preserveWhitespace: !expression.hasChildren, showHover: false, @@ -625,7 +647,7 @@ class ReplExpressionsRenderer implements ITreeRenderer { const rowHeight = Math.ceil(1.4 * fontSize); const wordWrap = config.console.wordWrap; if (!wordWrap) { - return element instanceof Expression ? 2 * rowHeight : rowHeight; + return rowHeight; } // In order to keep scroll position we need to give a good approximation to the tree // For every 150 characters increase the number of lines needed - if (element instanceof Expression) { - let { name, value } = element; - let nameRows = countNumberOfLines(name) + Math.floor(name.length / 150); + if (element instanceof ReplEvaluationResult) { + let value = element.value; if (element.hasChildren) { - return (nameRows + 1) * rowHeight; + return rowHeight; } let valueRows = value ? (countNumberOfLines(value) + Math.floor(value.length / 150)) : 0; - return rowHeight * (nameRows + valueRows); + return rowHeight * valueRows; } - if (element instanceof SimpleReplElement) { + if (element instanceof SimpleReplElement || element instanceof ReplEvaluationInput) { let value = element.value; let valueRows = countNumberOfLines(value) + Math.floor(value.length / 150); @@ -788,8 +809,11 @@ class ReplDelegate implements IListVirtualDelegate { if (element instanceof Variable && element.name) { return VariablesRenderer.ID; } - if (element instanceof Expression) { - return ReplExpressionsRenderer.ID; + if (element instanceof ReplEvaluationResult) { + return ReplEvaluationResultsRenderer.ID; + } + if (element instanceof ReplEvaluationInput) { + return ReplEvaluationInputsRenderer.ID; } if (element instanceof SimpleReplElement || (element instanceof Variable && !element.name)) { // Variable with no name is a top level variable which should be rendered like a repl element #17404 @@ -836,10 +860,7 @@ class ReplAccessibilityProvider implements IAccessibilityProvider if (element instanceof Variable) { return nls.localize('replVariableAriaLabel', "Variable {0} has value {1}, read eval print loop, debug", element.name, element.value); } - if (element instanceof Expression) { - return nls.localize('replExpressionAriaLabel', "Expression {0} has value {1}, read eval print loop, debug", element.name, element.value); - } - if (element instanceof SimpleReplElement) { + if (element instanceof SimpleReplElement || element instanceof ReplEvaluationInput || element instanceof ReplEvaluationResult) { return nls.localize('replValueOutputAriaLabel', "{0}, read eval print loop, debug", element.value); } if (element instanceof RawObjectReplElement) { diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index 69cb45f57a3..f146ee3ca15 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -104,13 +104,13 @@ export interface IExpressionContainer extends ITreeElement { readonly hasChildren: boolean; getChildren(): Promise; readonly reference?: number; + readonly value: string; + readonly type?: string; + valueChanged?: boolean; } -export interface IExpression extends IReplElement, IExpressionContainer { +export interface IExpression extends IExpressionContainer { name: string; - readonly value: string; - valueChanged?: boolean; - readonly type?: string; } export interface IDebugger { diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts index b33ffe111af..ae2347115de 100644 --- a/src/vs/workbench/contrib/debug/common/debugModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugModel.ts @@ -10,13 +10,12 @@ import * as lifecycle from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import { generateUuid } from 'vs/base/common/uuid'; import { RunOnceScheduler } from 'vs/base/common/async'; -import severity from 'vs/base/common/severity'; -import { isObject, isString, isUndefinedOrNull } from 'vs/base/common/types'; +import { isString, isUndefinedOrNull } from 'vs/base/common/types'; import { distinct, lastIndex } from 'vs/base/common/arrays'; import { Range, IRange } from 'vs/editor/common/core/range'; import { - ITreeElement, IExpression, IExpressionContainer, IDebugSession, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IDebugModel, IReplElementSource, - IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IBreakpointData, IExceptionInfo, IReplElement, IBreakpointsChangeEvent, IBreakpointUpdateData, IBaseBreakpoint, State, IDataBreakpoint + ITreeElement, IExpression, IExpressionContainer, IDebugSession, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IDebugModel, + IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IBreakpointData, IExceptionInfo, IBreakpointsChangeEvent, IBreakpointUpdateData, IBaseBreakpoint, State, IDataBreakpoint } from 'vs/workbench/contrib/debug/common/debug'; import { Source, UNKNOWN_SOURCE_LABEL } from 'vs/workbench/contrib/debug/common/debugSource'; import { commonSuffixLength } from 'vs/base/common/strings'; @@ -25,75 +24,13 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ITextEditor } from 'vs/workbench/common/editor'; -export class SimpleReplElement implements IReplElement { - constructor( - private id: string, - public value: string, - public severity: severity, - public sourceData?: IReplElementSource, - ) { } - - toString(): string { - return this.value; - } - - getId(): string { - return this.id; - } -} - -export class RawObjectReplElement implements IExpression { - - private static readonly MAX_CHILDREN = 1000; // upper bound of children per value - - constructor(private id: string, public name: string, public valueObj: any, public sourceData?: IReplElementSource, public annotation?: string) { } - - getId(): string { - return this.id; - } - - get value(): string { - if (this.valueObj === null) { - return 'null'; - } else if (Array.isArray(this.valueObj)) { - return `Array[${this.valueObj.length}]`; - } else if (isObject(this.valueObj)) { - return 'Object'; - } else if (isString(this.valueObj)) { - return `"${this.valueObj}"`; - } - - return String(this.valueObj) || ''; - } - - get hasChildren(): boolean { - return (Array.isArray(this.valueObj) && this.valueObj.length > 0) || (isObject(this.valueObj) && Object.getOwnPropertyNames(this.valueObj).length > 0); - } - - getChildren(): Promise { - let result: IExpression[] = []; - if (Array.isArray(this.valueObj)) { - result = (this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN) - .map((v, index) => new RawObjectReplElement(`${this.id}:${index}`, String(index), v)); - } else if (isObject(this.valueObj)) { - result = Object.getOwnPropertyNames(this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN) - .map((key, index) => new RawObjectReplElement(`${this.id}:${index}`, key, this.valueObj[key])); - } - - return Promise.resolve(result); - } - - toString(): string { - return `${this.name}\n${this.value}`; - } -} - export class ExpressionContainer implements IExpressionContainer { public static allValues = new Map(); // Use chunks to support variable paging #9537 private static readonly BASE_CHUNK_SIZE = 100; + public type: string | undefined; public valueChanged = false; private _value: string = ''; protected children?: Promise; @@ -195,13 +132,43 @@ export class ExpressionContainer implements IExpressionContainer { toString(): string { return this.value; } + + async evaluateExpression( + expression: string, + session: IDebugSession | undefined, + stackFrame: IStackFrame | undefined, + context: string): Promise { + + if (!session || (!stackFrame && context !== 'repl')) { + this.value = context === 'repl' ? nls.localize('startDebugFirst', "Please start a debug session to evaluate expressions") : Expression.DEFAULT_VALUE; + this.reference = 0; + return false; + } + + this.session = session; + try { + const response = await session.evaluate(expression, stackFrame ? stackFrame.frameId : undefined, context); + if (response && response.body) { + this.value = response.body.result || ''; + this.reference = response.body.variablesReference; + this.namedVariables = response.body.namedVariables; + this.indexedVariables = response.body.indexedVariables; + this.type = response.body.type || this.type; + return true; + } + return false; + } catch (e) { + this.value = e.message || ''; + this.reference = 0; + return false; + } + } } export class Expression extends ExpressionContainer implements IExpression { static DEFAULT_VALUE = nls.localize('notAvailable', "not available"); public available: boolean; - public type: string | undefined; constructor(public name: string, id = generateUuid()) { super(undefined, 0, id); @@ -214,30 +181,7 @@ export class Expression extends ExpressionContainer implements IExpression { } async evaluate(session: IDebugSession | undefined, stackFrame: IStackFrame | undefined, context: string): Promise { - if (!session || (!stackFrame && context !== 'repl')) { - this.value = context === 'repl' ? nls.localize('startDebugFirst', "Please start a debug session to evaluate expressions") : Expression.DEFAULT_VALUE; - this.available = false; - this.reference = 0; - - return Promise.resolve(undefined); - } - - this.session = session; - try { - const response = await session.evaluate(this.name, stackFrame ? stackFrame.frameId : undefined, context); - this.available = !!(response && response.body); - if (response && response.body) { - this.value = response.body.result || ''; - this.reference = response.body.variablesReference; - this.namedVariables = response.body.namedVariables; - this.indexedVariables = response.body.indexedVariables; - this.type = response.body.type || this.type; - } - } catch (e) { - this.value = e.message || ''; - this.available = false; - this.reference = 0; - } + this.available = await this.evaluateExpression(this.name, session, stackFrame, context); } toString(): string { diff --git a/src/vs/workbench/contrib/debug/common/replModel.ts b/src/vs/workbench/contrib/debug/common/replModel.ts index dc981f59b67..4d60ecea55a 100644 --- a/src/vs/workbench/contrib/debug/common/replModel.ts +++ b/src/vs/workbench/contrib/debug/common/replModel.ts @@ -6,15 +6,105 @@ import * as nls from 'vs/nls'; import severity from 'vs/base/common/severity'; import { IReplElement, IStackFrame, IExpression, IReplElementSource, IDebugSession } from 'vs/workbench/contrib/debug/common/debug'; -import { Expression, SimpleReplElement, RawObjectReplElement } from 'vs/workbench/contrib/debug/common/debugModel'; -import { isUndefinedOrNull, isObject } from 'vs/base/common/types'; +import { ExpressionContainer } from 'vs/workbench/contrib/debug/common/debugModel'; +import { isString, isUndefinedOrNull, isObject } from 'vs/base/common/types'; import { basenameOrAuthority } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { endsWith } from 'vs/base/common/strings'; +import { generateUuid } from 'vs/base/common/uuid'; const MAX_REPL_LENGTH = 10000; let topReplElementCounter = 0; +export class SimpleReplElement implements IReplElement { + constructor( + private id: string, + public value: string, + public severity: severity, + public sourceData?: IReplElementSource, + ) { } + + toString(): string { + return this.value; + } + + getId(): string { + return this.id; + } +} + +export class RawObjectReplElement implements IExpression { + + private static readonly MAX_CHILDREN = 1000; // upper bound of children per value + + constructor(private id: string, public name: string, public valueObj: any, public sourceData?: IReplElementSource, public annotation?: string) { } + + getId(): string { + return this.id; + } + + get value(): string { + if (this.valueObj === null) { + return 'null'; + } else if (Array.isArray(this.valueObj)) { + return `Array[${this.valueObj.length}]`; + } else if (isObject(this.valueObj)) { + return 'Object'; + } else if (isString(this.valueObj)) { + return `"${this.valueObj}"`; + } + + return String(this.valueObj) || ''; + } + + get hasChildren(): boolean { + return (Array.isArray(this.valueObj) && this.valueObj.length > 0) || (isObject(this.valueObj) && Object.getOwnPropertyNames(this.valueObj).length > 0); + } + + getChildren(): Promise { + let result: IExpression[] = []; + if (Array.isArray(this.valueObj)) { + result = (this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN) + .map((v, index) => new RawObjectReplElement(`${this.id}:${index}`, String(index), v)); + } else if (isObject(this.valueObj)) { + result = Object.getOwnPropertyNames(this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN) + .map((key, index) => new RawObjectReplElement(`${this.id}:${index}`, key, this.valueObj[key])); + } + + return Promise.resolve(result); + } + + toString(): string { + return `${this.name}\n${this.value}`; + } +} + +export class ReplEvaluationInput implements IReplElement { + private id: string; + + constructor(public value: string) { + this.id = generateUuid(); + } + + toString(): string { + return this.value; + } + + getId(): string { + return this.id; + } +} + +export class ReplEvaluationResult extends ExpressionContainer implements IReplElement { + constructor() { + super(undefined, 0, generateUuid()); + } + + toString(): string { + return `${this.value}`; + } +} + export class ReplModel { private replElements: IReplElement[] = []; @@ -24,10 +114,11 @@ export class ReplModel { return this.replElements; } - addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise { - const expression = new Expression(name); - this.addReplElement(expression); - return expression.evaluate(this.session, stackFrame, 'repl'); + async addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise { + this.addReplElement(new ReplEvaluationInput(name)); + const result = new ReplEvaluationResult(); + await result.evaluateExpression(name, this.session, stackFrame, 'repl'); + this.addReplElement(result); } appendToRepl(data: string | IExpression, sev: severity, source?: IReplElementSource): void { diff --git a/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts index f93108d3341..e69860a2fac 100644 --- a/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts @@ -6,12 +6,12 @@ import * as assert from 'assert'; import { URI as uri } from 'vs/base/common/uri'; import severity from 'vs/base/common/severity'; -import { SimpleReplElement, DebugModel, Expression, RawObjectReplElement, StackFrame, Thread } from 'vs/workbench/contrib/debug/common/debugModel'; +import { DebugModel, Expression, StackFrame, Thread } from 'vs/workbench/contrib/debug/common/debugModel'; import * as sinon from 'sinon'; import { MockRawSession } from 'vs/workbench/contrib/debug/test/common/mockDebug'; import { Source } from 'vs/workbench/contrib/debug/common/debugSource'; import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession'; -import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel'; +import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplModel } from 'vs/workbench/contrib/debug/common/replModel'; import { IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug'; import { NullOpenerService } from 'vs/platform/opener/common/opener'; @@ -348,9 +348,7 @@ suite('Debug - Model', () => { assert.equal(replModel.getReplElements().length, 3); replModel.getReplElements().forEach(re => { - assert.equal((re).available, false); - assert.equal((re).name, 'myVariable'); - assert.equal((re).reference, 0); + assert.equal((re).value, 'myVariable'); }); replModel.removeReplExpressions(); diff --git a/src/vs/workbench/contrib/extensions/browser/media/clear-inverse.svg b/src/vs/workbench/contrib/extensions/browser/media/clear-inverse.svg deleted file mode 100644 index 85e7ec4bdaf..00000000000 --- a/src/vs/workbench/contrib/extensions/browser/media/clear-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts index 4c21e1e9181..d47550c32a9 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -21,6 +21,7 @@ import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron import { URI } from 'vs/base/common/uri'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; // Singletons registerSingleton(IExtensionHostProfileService, ExtensionHostProfileService, true); @@ -85,8 +86,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: DebugExtensionHostAction.ID, title: DebugExtensionHostAction.LABEL, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/start-dark.svg`)), - light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/start-light.svg`)), + dark: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/start-dark.svg`)), + light: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/start-light.svg`)), } }, group: 'navigation', @@ -98,8 +99,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: StartExtensionHostProfileAction.ID, title: StartExtensionHostProfileAction.LABEL, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/profile-start-dark.svg`)), - light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/profile-start-light.svg`)), + dark: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/profile-start-dark.svg`)), + light: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/profile-start-light.svg`)), } }, group: 'navigation', @@ -111,8 +112,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: StopExtensionHostProfileAction.ID, title: StopExtensionHostProfileAction.LABEL, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/profile-stop-dark.svg`)), - light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/profile-stop-light.svg`)), + dark: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/profile-stop-dark.svg`)), + light: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/profile-stop-light.svg`)), } }, group: 'navigation', @@ -124,8 +125,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: SaveExtensionHostProfileAction.ID, title: SaveExtensionHostProfileAction.LABEL, iconLocation: { - dark: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/save-dark.svg`)), - light: URI.parse(require.toUrl(`vs/workbench/contrib/extensions/browser/media/save-light.svg`)), + dark: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/save-dark.svg`)), + light: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/extensions/browser/media/save-light.svg`)), }, precondition: CONTEXT_EXTENSION_HOST_PROFILE_RECORDED }, diff --git a/src/vs/workbench/contrib/feedback/browser/media/smiley.svg b/src/vs/workbench/contrib/feedback/browser/media/smiley.svg deleted file mode 100644 index 6bc95278904..00000000000 --- a/src/vs/workbench/contrib/feedback/browser/media/smiley.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 40a0ec28bf2..698fb9170ad 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -26,6 +26,7 @@ import { Schemas } from 'vs/base/common/network'; import { SupportsWorkspacesContext, IsWebContext, RemoteFileDialogContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { OpenFileFolderAction, OpenLocalFileFolderCommand, OpenFileAction, OpenFolderAction, OpenLocalFileCommand, OpenLocalFolderCommand, OpenWorkspaceAction, SaveLocalFileCommand } from 'vs/workbench/browser/actions/workspaceActions'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; // Contribute Global Actions const category = { value: nls.localize('filesCategory', "File"), original: 'File' }; @@ -223,12 +224,12 @@ function appendEditorTitleContextMenuItem(id: string, title: string, when: Conte // Editor Title Menu for Conflict Resolution appendSaveConflictEditorTitleAction('workbench.files.action.acceptLocalChanges', nls.localize('acceptLocalChanges', "Use your changes and overwrite file contents"), { - light: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/check-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/check-dark.svg`)) + light: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/files/browser/media/check-light.svg`)), + dark: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/files/browser/media/check-dark.svg`)) }, -10, acceptLocalChangesCommand); appendSaveConflictEditorTitleAction('workbench.files.action.revertLocalChanges', nls.localize('revertLocalChanges', "Discard your changes and revert to file contents"), { - light: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/undo-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/undo-dark.svg`)) + light: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/files/browser/media/undo-light.svg`)), + dark: URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/files/browser/media/undo-dark.svg`)) }, -9, revertLocalChangesCommand); function appendSaveConflictEditorTitleAction(id: string, title: string, iconLocation: { dark: URI; light?: URI; }, order: number, command: ICommandHandler): void { diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index e204c90c0bc..cb3afb6e658 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -925,7 +925,7 @@ async function openExplorerAndCreate(accessor: ServicesAccessor, isFolder: boole folder.addChild(newStat); - const onSuccess = async (value: string) => { + const onSuccess = (value: string): Promise => { const createPromise = isFolder ? fileService.createFolder(resources.joinPath(folder.resource, value)) : textFileService.create(resources.joinPath(folder.resource, value)); return createPromise.then(created => { refreshIfSeparator(value, explorerService); @@ -943,8 +943,6 @@ async function openExplorerAndCreate(accessor: ServicesAccessor, isFolder: boole explorerService.setEditable(newStat, null); if (success) { onSuccess(value); - } else { - explorerService.select(folder.resource).then(undefined, onUnexpectedError); } } }); diff --git a/src/vs/workbench/contrib/files/browser/media/action-close.svg b/src/vs/workbench/contrib/files/browser/media/action-close.svg deleted file mode 100644 index fde34404d4e..00000000000 --- a/src/vs/workbench/contrib/files/browser/media/action-close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/files/browser/media/close-all-hc.svg b/src/vs/workbench/contrib/files/browser/media/close-all-hc.svg deleted file mode 100644 index 3cbd40ee697..00000000000 --- a/src/vs/workbench/contrib/files/browser/media/close-all-hc.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/contrib/files/browser/media/saveall.svg b/src/vs/workbench/contrib/files/browser/media/saveall.svg deleted file mode 100644 index 5f036a20f71..00000000000 --- a/src/vs/workbench/contrib/files/browser/media/saveall.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index 52583917ba0..fda43517833 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; import * as perf from 'vs/base/common/performance'; -import { Action, IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; +import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { memoize } from 'vs/base/common/decorators'; import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, ExplorerRootContext, ExplorerResourceReadonlyContext, IExplorerService, ExplorerResourceCut, ExplorerResourceMoveableToTrash } from 'vs/workbench/contrib/files/common/files'; import { NewFolderAction, NewFileAction, FileCopiedContext, RefreshExplorerView, CollapseExplorerView } from 'vs/workbench/contrib/files/browser/fileActions'; @@ -68,6 +68,7 @@ export class ExplorerView extends ViewletPanel { private shouldRefresh = true; private dragHandler!: DelayedDragHandler; private autoReveal = false; + private actions: IAction[] | undefined; constructor( options: IViewletPanelOptions, @@ -170,7 +171,12 @@ export class ExplorerView extends ViewletPanel { })); this._register(this.explorerService.onDidChangeRoots(() => this.setTreeInput())); - this._register(this.explorerService.onDidChangeItem(e => this.refresh(e.recursive, e.item))); + this._register(this.explorerService.onDidChangeItem(e => { + if (this.explorerService.isEditable(undefined)) { + this.tree.domFocus(); + } + this.refresh(e.recursive, e.item); + })); this._register(this.explorerService.onDidChangeEditable(async e => { const isEditing = !!this.explorerService.getEditableData(e); @@ -218,14 +224,16 @@ export class ExplorerView extends ViewletPanel { } getActions(): IAction[] { - const actions: Action[] = []; - - actions.push(this.instantiationService.createInstance(NewFileAction)); - actions.push(this.instantiationService.createInstance(NewFolderAction)); - actions.push(this.instantiationService.createInstance(RefreshExplorerView, RefreshExplorerView.ID, RefreshExplorerView.LABEL)); - actions.push(this.instantiationService.createInstance(CollapseExplorerView, CollapseExplorerView.ID, CollapseExplorerView.LABEL)); - - return actions; + if (!this.actions) { + this.actions = [ + this.instantiationService.createInstance(NewFileAction), + this.instantiationService.createInstance(NewFolderAction), + this.instantiationService.createInstance(RefreshExplorerView, RefreshExplorerView.ID, RefreshExplorerView.LABEL), + this.instantiationService.createInstance(CollapseExplorerView, CollapseExplorerView.ID, CollapseExplorerView.LABEL) + ]; + this.actions.forEach(a => this._register(a)); + } + return this.actions; } focus(): void { @@ -334,6 +342,13 @@ export class ExplorerView extends ViewletPanel { this._register(this.tree.onContextMenu(e => this.onContextMenu(e))); + this._register(this.tree.onDidScroll(e => { + let editable = this.explorerService.getEditable(); + if (e.scrollTopChanged && editable && this.tree.getRelativeTop(editable.stat) === null) { + editable.data.onFinish('', false); + } + })); + // save view state on shutdown this._register(this.storageService.onWillSaveState(() => { this.storageService.store(ExplorerView.TREE_VIEW_STATE_STORAGE_KEY, JSON.stringify(this.tree.getViewState()), StorageScope.WORKSPACE); diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index 0c368120dff..6061e787c25 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -228,43 +228,37 @@ export class FilesRenderer implements ITreeRenderer 0 && !stat.isDirectory ? lastDot : value.length }); - const done = once(async (success: boolean, blur: boolean) => { + const done = once((success: boolean, finishEditing: boolean) => { label.element.style.display = 'none'; const value = inputBox.value; dispose(toDispose); - container.removeChild(label.element); - editableData.onFinish(value, success); + label.element.remove(); + if (finishEditing) { + editableData.onFinish(value, success); + } }); - // It can happen that the tree re-renders this node. When that happens, - // we're gonna get a blur event first and only after an element disposable. - // Because of that, we should setTimeout the blur handler to differentiate - // between the blur happening because of a unrender or because of a user action. - let ignoreBlur = false; - const toDispose = [ inputBox, DOM.addStandardDisposableListener(inputBox.inputElement, DOM.EventType.KEY_DOWN, (e: IKeyboardEvent) => { if (e.equals(KeyCode.Enter)) { if (inputBox.validate()) { - done(true, false); + done(true, true); } } else if (e.equals(KeyCode.Escape)) { - done(false, false); + done(false, true); } }), DOM.addDisposableListener(inputBox.inputElement, DOM.EventType.BLUR, () => { - setTimeout(() => { - if (!ignoreBlur) { - done(inputBox.isInputValid(), true); - } - }, 0); + done(inputBox.isInputValid(), true); }), label, styler ]; - return toDisposable(() => ignoreBlur = true); + return toDisposable(() => { + done(false, false); + }); } disposeElement?(element: ITreeNode, index: number, templateData: IFileTemplateData): void { diff --git a/src/vs/workbench/contrib/files/common/explorerService.ts b/src/vs/workbench/contrib/files/common/explorerService.ts index 4f6f55899a1..1674c9448e1 100644 --- a/src/vs/workbench/contrib/files/common/explorerService.ts +++ b/src/vs/workbench/contrib/files/common/explorerService.ts @@ -140,6 +140,10 @@ export class ExplorerService implements IExplorerService { return !!this.cutItems && this.cutItems.indexOf(item) >= 0; } + getEditable(): { stat: ExplorerItem, data: IEditableData } | undefined { + return this.editable; + } + getEditableData(stat: ExplorerItem): IEditableData | undefined { return this.editable && this.editable.stat === stat ? this.editable.data : undefined; } diff --git a/src/vs/workbench/contrib/files/common/files.ts b/src/vs/workbench/contrib/files/common/files.ts index 4d4af35e7e9..8f5470bff77 100644 --- a/src/vs/workbench/contrib/files/common/files.ts +++ b/src/vs/workbench/contrib/files/common/files.ts @@ -51,6 +51,7 @@ export interface IExplorerService { readonly onDidCopyItems: Event<{ items: ExplorerItem[], cut: boolean, previouslyCutItems: ExplorerItem[] | undefined }>; setEditable(stat: ExplorerItem, data: IEditableData | null): void; + getEditable(): { stat: ExplorerItem, data: IEditableData } | undefined; getEditableData(stat: ExplorerItem): IEditableData | undefined; // If undefined is passed checks if any element is currently being edited. isEditable(stat: ExplorerItem | undefined): boolean; diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index bf6546b0d72..90158388b30 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -565,7 +565,7 @@ export class MarkerViewModel extends Disposable { true, () => { return this.openFileAtMarker(this.marker) - .then(() => applyCodeAction(codeAction, this.bulkEditService, this.commandService)); + .then(() => this.instantiationService.invokeFunction(applyCodeAction, codeAction, this.bulkEditService, this.commandService)); })); } diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts index d9b7e38db91..9b45e34dee4 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts @@ -30,6 +30,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { KeybindingParser } from 'vs/base/common/keybindingParser'; import Severity from 'vs/base/common/severity'; import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; const NLS_LAUNCH_MESSAGE = nls.localize('defineKeybinding.start', "Define Keybinding"); const NLS_KB_LAYOUT_ERROR_MESSAGE = nls.localize('defineKeybinding.kbLayoutErrorMessage', "You won't be able to produce this key combination under your current keyboard layout."); @@ -82,7 +83,7 @@ export class DefineKeybindingController extends Disposable implements editorComm this._createKeybindingDecorationRenderer(); // The button to define keybindings is shown only for the user keybindings.json - if (!this._editor.getConfiguration().readOnly) { + if (!this._editor.getOption(EditorOption.readOnly)) { this._createKeybindingWidgetRenderer(); } else { this._disposeKeybindingWidgetRenderer(); @@ -377,7 +378,7 @@ class DefineKeybindingCommand extends EditorCommand { } runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor): void { - if (!isInterestingEditorModel(editor) || editor.getConfiguration().readOnly) { + if (!isInterestingEditorModel(editor) || editor.getOption(EditorOption.readOnly)) { return; } const controller = DefineKeybindingController.get(editor); diff --git a/src/vs/workbench/contrib/preferences/browser/media/add.svg b/src/vs/workbench/contrib/preferences/browser/media/add.svg deleted file mode 100644 index bdecdb0e45b..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/add.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/add_inverse.svg b/src/vs/workbench/contrib/preferences/browser/media/add_inverse.svg deleted file mode 100644 index 3475c1e1963..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/add_inverse.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/clean-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/clean-dark.svg deleted file mode 100644 index 3770d63d5f9..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/clean-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/clean.svg b/src/vs/workbench/contrib/preferences/browser/media/clean.svg deleted file mode 100644 index f86ec7d627d..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/clean.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/collapsed-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/collapsed-dark.svg deleted file mode 100755 index cf5c3641aa7..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/collapsed-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/collapsed.svg b/src/vs/workbench/contrib/preferences/browser/media/collapsed.svg deleted file mode 100755 index 3a63808c358..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/collapsed.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/edit-json-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/edit-json-dark.svg deleted file mode 100644 index 9a725bb41fd..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/edit-json-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/edit-json-light.svg b/src/vs/workbench/contrib/preferences/browser/media/edit-json-light.svg deleted file mode 100644 index 1339da7ce21..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/edit-json-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/edit.svg b/src/vs/workbench/contrib/preferences/browser/media/edit.svg deleted file mode 100755 index ecde9240842..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/edit.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/edit_inverse.svg b/src/vs/workbench/contrib/preferences/browser/media/edit_inverse.svg deleted file mode 100755 index da956cb2c60..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/edit_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/ellipsis-inverse.svg b/src/vs/workbench/contrib/preferences/browser/media/ellipsis-inverse.svg deleted file mode 100644 index e3337557a23..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/ellipsis-inverse.svg +++ /dev/null @@ -1 +0,0 @@ -Ellipsis_bold_16x \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/ellipsis.svg b/src/vs/workbench/contrib/preferences/browser/media/ellipsis.svg deleted file mode 100644 index e3f85623356..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/ellipsis.svg +++ /dev/null @@ -1 +0,0 @@ -Ellipsis_bold_16x \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/expanded-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/expanded-dark.svg deleted file mode 100755 index 73d41e63990..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/expanded-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/expanded.svg b/src/vs/workbench/contrib/preferences/browser/media/expanded.svg deleted file mode 100755 index 75f73adbb02..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/expanded.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/open-file-inverse.svg b/src/vs/workbench/contrib/preferences/browser/media/open-file-inverse.svg deleted file mode 100644 index f6302185aa4..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/open-file-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/open-file.svg b/src/vs/workbench/contrib/preferences/browser/media/open-file.svg deleted file mode 100644 index d23a23c6b5f..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/open-file.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/regex-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/regex-dark.svg deleted file mode 100644 index c303032e6a9..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/regex-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/regex.svg b/src/vs/workbench/contrib/preferences/browser/media/regex.svg deleted file mode 100644 index c677843beef..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/regex.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css index faf363f6a3e..0bf606139f2 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css @@ -486,6 +486,7 @@ .settings-editor > .settings-body > .settings-tree-container .setting-item-new-extensions .settings-new-extensions-button { margin: auto; + margin-bottom: 15px; width: initial; padding: 4px 10px; } diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index 0d180c8c7a1..71d25b5291a 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -39,6 +39,7 @@ import { ExplorerRootContext, ExplorerFolderContext } from 'vs/workbench/contrib import { ILabelService } from 'vs/platform/label/common/label'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; Registry.as(EditorExtensions.Editors).registerEditor( new EditorDescriptor( @@ -366,6 +367,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); +const PREFERENCES_EDITOR_LIGHT_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)); +const PREFERENCES_EDITOR_DARK_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)); class PreferencesActionsContribution extends Disposable implements IWorkbenchContribution { constructor( @@ -381,8 +384,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon id: OpenGlobalKeybindingsAction.ID, title: OpenGlobalKeybindingsAction.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)) + light: PREFERENCES_EDITOR_LIGHT_ICON_URI, + dark: PREFERENCES_EDITOR_DARK_ICON_URI } }, when: ResourceContextKey.Resource.isEqualTo(environmentService.keybindingsResource.toString()), @@ -397,8 +400,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon id: commandId, title: OpenSettings2Action.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)) + light: PREFERENCES_EDITOR_LIGHT_ICON_URI, + dark: PREFERENCES_EDITOR_DARK_ICON_URI } }, when: ResourceContextKey.Resource.isEqualTo(environmentService.settingsResource.toString()), @@ -438,8 +441,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon id: commandId, title: OpenSettings2Action.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)) + light: PREFERENCES_EDITOR_LIGHT_ICON_URI, + dark: PREFERENCES_EDITOR_DARK_ICON_URI } }, when: ContextKeyExpr.and(ResourceContextKey.Resource.isEqualTo(this.preferencesService.workspaceSettingsResource!.toString()), WorkbenchStateContext.isEqualTo('workspace')), @@ -466,8 +469,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon id: commandId, title: OpenSettings2Action.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)) + light: PREFERENCES_EDITOR_LIGHT_ICON_URI, + dark: PREFERENCES_EDITOR_DARK_ICON_URI } }, when: ContextKeyExpr.and(ResourceContextKey.Resource.isEqualTo(this.preferencesService.getFolderSettingsResource(folder.uri)!.toString())), @@ -533,8 +536,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: OpenGlobalKeybindingsFileAction.ID, title: OpenGlobalKeybindingsFileAction.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`)) + light: PREFERENCES_EDITOR_LIGHT_ICON_URI, + dark: PREFERENCES_EDITOR_DARK_ICON_URI } }, when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR), diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts index 6eb21cf8e1a..2881d09fec2 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts @@ -31,6 +31,7 @@ import { IFilterResult, IPreferencesEditorModel, IPreferencesService, ISetting, import { DefaultSettingsEditorModel, SettingsEditorModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels'; import { IMarkerService, IMarkerData, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export interface IPreferencesRenderer extends IDisposable { readonly preferencesModel: IPreferencesEditorModel; @@ -690,7 +691,7 @@ class EditSettingRenderer extends Disposable { } private onConfigurationChanged(): void { - if (!this.editor.getConfiguration().viewInfo.glyphMargin) { + if (!this.editor.getOption(EditorOption.glyphMargin)) { this.editPreferenceWidgetForCursorPosition.hide(); this.editPreferenceWidgetForMouseMove.hide(); } @@ -740,7 +741,7 @@ class EditSettingRenderer extends Disposable { private showEditPreferencesWidget(editPreferencesWidget: EditPreferenceWidget, settings: IIndexedSetting[]) { const line = settings[0].valueRange.startLineNumber; - if (this.editor.getConfiguration().viewInfo.glyphMargin && this.marginFreeFromOtherDecorations(line)) { + if (this.editor.getOption(EditorOption.glyphMargin) && this.marginFreeFromOtherDecorations(line)) { editPreferencesWidget.show(line, nls.localize('editTtile', "Edit"), settings); const editPreferenceWidgetToHide = editPreferencesWidget === this.editPreferenceWidgetForCursorPosition ? this.editPreferenceWidgetForMouseMove : this.editPreferenceWidgetForCursorPosition; editPreferenceWidgetToHide.hide(); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts index f46b01947be..c683b6dab4c 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts @@ -33,6 +33,7 @@ import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/p import { PANEL_ACTIVE_TITLE_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND } from 'vs/workbench/common/theme'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class SettingsHeaderWidget extends Widget implements IViewZone { @@ -84,9 +85,10 @@ export class SettingsHeaderWidget extends Widget implements IViewZone { } private layout(): void { - const configuration = this.editor.getConfiguration(); - this.titleContainer.style.fontSize = configuration.fontInfo.fontSize + 'px'; - if (!configuration.contribInfo.folding) { + const options = this.editor.getOptions(); + const fontInfo = options.get(EditorOption.fontInfo); + this.titleContainer.style.fontSize = fontInfo.fontSize + 'px'; + if (!options.get(EditorOption.folding)) { this.titleContainer.style.paddingLeft = '6px'; } } @@ -199,17 +201,18 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone { } private layout(): void { - const configuration = this.editor.getConfiguration(); + const options = this.editor.getOptions(); + const fontInfo = options.get(EditorOption.fontInfo); const layoutInfo = this.editor.getLayoutInfo(); this._domNode.style.width = layoutInfo.contentWidth - layoutInfo.verticalScrollbarWidth + 'px'; - this.titleContainer.style.lineHeight = configuration.lineHeight + 3 + 'px'; - this.titleContainer.style.height = configuration.lineHeight + 3 + 'px'; - this.titleContainer.style.fontSize = configuration.fontInfo.fontSize + 'px'; + this.titleContainer.style.lineHeight = options.get(EditorOption.lineHeight) + 3 + 'px'; + this.titleContainer.style.height = options.get(EditorOption.lineHeight) + 3 + 'px'; + this.titleContainer.style.fontSize = fontInfo.fontSize + 'px'; this.icon.style.minWidth = `${this.getIconSize(16)}px`; } private getIconSize(minSize: number): number { - const fontSize = this.editor.getConfiguration().fontInfo.fontSize; + const fontSize = this.editor.getOption(EditorOption.fontInfo).fontSize; return fontSize > 8 ? Math.max(fontSize, minSize) : 12; } @@ -391,11 +394,7 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { this.update(); if (this._action.checked) { - if ((oldFolder || !this._folder) - || (!oldFolder || this._folder) - || (oldFolder && this._folder && (oldFolder as IWorkspaceFolder).uri.toString() === (this._folder as IWorkspaceFolder).uri.toString())) { - this._action.run(this._folder); - } + this._action.run(this._folder); } } @@ -517,7 +516,8 @@ export class SettingsTargetsWidget extends Widget { this.workspaceSettings = new Action('workspaceSettings', localize('workspaceSettings', "Workspace"), '.settings-tab', false, () => this.updateTarget(ConfigurationTarget.WORKSPACE)); this.workspaceSettings.tooltip = this.workspaceSettings.label; - const folderSettingsAction = new Action('folderSettings', localize('folderSettings', "Folder"), '.settings-tab', false, (folder: IWorkspaceFolder) => this.updateTarget(folder.uri)); + const folderSettingsAction = new Action('folderSettings', localize('folderSettings', "Folder"), '.settings-tab', false, + (folder: IWorkspaceFolder | null) => this.updateTarget(folder ? folder.uri : ConfigurationTarget.USER_LOCAL)); this.folderSettings = this.instantiationService.createInstance(FolderSettingsActionViewItem, folderSettingsAction); this.update(); diff --git a/src/vs/workbench/contrib/quickopen/browser/gotoLineHandler.ts b/src/vs/workbench/contrib/quickopen/browser/gotoLineHandler.ts index 3dcbb07c16c..59ef23bc2e1 100644 --- a/src/vs/workbench/contrib/quickopen/browser/gotoLineHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/gotoLineHandler.ts @@ -16,7 +16,7 @@ import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IRange } from 'vs/editor/common/core/range'; import { overviewRulerRangeHighlight } from 'vs/editor/common/view/editorColorRegistry'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; -import { IEditorOptions, RenderLineNumbersType } from 'vs/editor/common/config/editorOptions'; +import { IEditorOptions, RenderLineNumbersType, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -50,8 +50,9 @@ export class GotoLineAction extends QuickOpenAction { let restoreOptions: IEditorOptions | null = null; if (isCodeEditor(activeTextEditorWidget)) { - const config = activeTextEditorWidget.getConfiguration(); - if (config.viewInfo.renderLineNumbers === RenderLineNumbersType.Relative) { + const options = activeTextEditorWidget.getOptions(); + const lineNumbers = options.get(EditorOption.lineNumbers); + if (lineNumbers.renderType === RenderLineNumbersType.Relative) { activeTextEditorWidget.updateOptions({ lineNumbers: 'on' }); diff --git a/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts b/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts index 85362cb1aa9..60a0a3da383 100644 --- a/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts @@ -97,9 +97,11 @@ class OutlineModel extends QuickOpenModel { } }); - this.entries.sort(SymbolEntry.compareByRank); - - + // select comparator based on the presence of the colon-prefix + this.entries.sort(searchValuePos === 0 + ? SymbolEntry.compareByRank + : SymbolEntry.compareByKindAndRank + ); // Mark all type groups const visibleResults = this.getEntries(true); @@ -297,7 +299,7 @@ class SymbolEntry extends EditorQuickOpenEntryGroup { const kindB = NLS_SYMBOL_KIND_CACHE[b.getKind()] || FALLBACK_NLS_SYMBOL_KIND; let r = kindA.localeCompare(kindB); if (r === 0) { - r = this.compareByRank(a, b); + r = SymbolEntry.compareByRank(a, b); } return r; } diff --git a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts index 955579069d7..ec16eec903b 100644 --- a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts @@ -33,7 +33,7 @@ import { rot } from 'vs/base/common/numbers'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/referencesWidget'; import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; -import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IDiffEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Action, IAction, ActionRunner } from 'vs/base/common/actions'; import { IActionBarOptions, ActionsOrientation, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -223,7 +223,7 @@ class DirtyDiffWidget extends PeekViewWidget { const position = new Position(getModifiedEndLineNumber(change), 1); - const lineHeight = this.editor.getConfiguration().lineHeight; + const lineHeight = this.editor.getOption(EditorOption.lineHeight); const editorHeight = this.editor.getLayoutInfo().height; const editorHeightInLines = Math.floor(editorHeight / lineHeight); const height = Math.min(getChangeHeight(change) + /* padding */ 8, Math.floor(editorHeightInLines / 3)); diff --git a/src/vs/workbench/contrib/scm/browser/media/check-inverse.svg b/src/vs/workbench/contrib/scm/browser/media/check-inverse.svg deleted file mode 100644 index c225b2f597f..00000000000 --- a/src/vs/workbench/contrib/scm/browser/media/check-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/scm/browser/media/check.svg b/src/vs/workbench/contrib/scm/browser/media/check.svg deleted file mode 100644 index d45df06edf8..00000000000 --- a/src/vs/workbench/contrib/scm/browser/media/check.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index a87d4c5aa19..e4993dde0bd 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -1223,7 +1223,7 @@ export class SearchView extends ViewletPanel { return this.fileService.exists(fq.folder); }); - return Promise.resolve(folderQueriesExistP).then(existResults => { + return Promise.all(folderQueriesExistP).then(existResults => { // If no folders exist, show an error message about the first one const existingFolderQueries = query.folderQueries.filter((folderQuery, i) => existResults[i]); if (!query.folderQueries.length || existingFolderQueries.length) { diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index e2db0035eb2..634e3aaa00e 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -426,7 +426,7 @@ export class SearchWidget extends Widget { } try { // tslint:disable-next-line: no-unused-expression - new RegExp(value); + new RegExp(value, 'u'); } catch (e) { return { content: e.message }; } diff --git a/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts b/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts index 569598138e8..20f06e31a9e 100644 --- a/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts +++ b/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts @@ -19,6 +19,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Snippet } from './snippetsFile'; import { SnippetCompletion } from './snippetCompletionProvider'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class TabCompletionController implements editorCommon.IEditorContribution { @@ -42,7 +43,7 @@ export class TabCompletionController implements editorCommon.IEditorContribution ) { this._hasSnippets = TabCompletionController.ContextKey.bindTo(contextKeyService); this._configListener = this._editor.onDidChangeConfiguration(e => { - if (e.contribInfo) { + if (e.hasChanged(EditorOption.tabCompletion)) { this._update(); } }); @@ -59,7 +60,7 @@ export class TabCompletionController implements editorCommon.IEditorContribution } private _update(): void { - const enabled = this._editor.getConfiguration().contribInfo.tabCompletion === 'onlySnippets'; + const enabled = this._editor.getOption(EditorOption.tabCompletion) === 'onlySnippets'; if (this._enabled !== enabled) { this._enabled = enabled; if (!this._enabled) { diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 9fc55917fc8..2353b3f217d 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -278,6 +278,28 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this._register(lifecycleService.onBeforeShutdown(event => event.veto(this.beforeShutdown()))); this._onDidStateChange = this._register(new Emitter()); this.registerCommands(); + this.configurationResolverService.contributeVariable('defaultBuildTask', async (): Promise => { + let tasks = await this.getTasksForGroup(TaskGroup.Build); + if (tasks.length > 0) { + let { defaults, users } = this.splitPerGroupType(tasks); + if (defaults.length === 1) { + return defaults[0]._label; + } else if (defaults.length + users.length > 0) { + tasks = defaults.concat(users); + } + } + + let entry: TaskQuickPickEntry | null | undefined; + if (tasks && tasks.length > 0) { + entry = await this.showQuickPick(tasks, nls.localize('TaskService.pickBuildTaskForLabel', 'Select the build task')); + } + + let task: Task | undefined | null = entry ? entry.task : undefined; + if (!task) { + return undefined; + } + return task._label; + }); } public get onDidStateChange(): Event { diff --git a/src/vs/workbench/contrib/tasks/common/media/configure-hc.svg b/src/vs/workbench/contrib/tasks/common/media/configure-hc.svg new file mode 100644 index 00000000000..bd59cb81f6d --- /dev/null +++ b/src/vs/workbench/contrib/tasks/common/media/configure-hc.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/vs/workbench/contrib/tasks/common/media/task.contribution.css b/src/vs/workbench/contrib/tasks/common/media/task.contribution.css index 74394a3c971..2a617741ff6 100644 --- a/src/vs/workbench/contrib/tasks/common/media/task.contribution.css +++ b/src/vs/workbench/contrib/tasks/common/media/task.contribution.css @@ -7,7 +7,10 @@ background-image: url('configure-light.svg'); } -.vs-dark .monaco-workbench .quick-open-task-configure, -.hc-black .monaco-workbench .quick-open-task-configure { +.vs-dark .monaco-workbench .quick-open-task-configure { background-image: url('configure-dark.svg'); } + +.hc-black .monaco-workbench .quick-open-task-configure { + background-image: url('configure-hc.svg'); +} diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts index 9a0ed0de114..089c2bb1a46 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts @@ -26,7 +26,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { Event } from 'vs/base/common/event'; import { isObject } from 'vs/base/common/types'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { registerColor, focusBorder, textLinkForeground, textLinkActiveForeground, textPreformatForeground, contrastBorder, textBlockQuoteBackground, textBlockQuoteBorder } from 'vs/platform/theme/common/colorRegistry'; import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils'; @@ -312,7 +312,7 @@ export class WalkThroughPart extends BaseEditor { this.contentDisposables.push(editor); const updateHeight = (initial: boolean) => { - const lineHeight = editor.getConfiguration().lineHeight; + const lineHeight = editor.getOption(EditorOption.lineHeight); const height = `${Math.max(model.getLineCount() + 1, 4) * lineHeight}px`; if (div.style.height !== height) { div.style.height = height; @@ -329,7 +329,7 @@ export class WalkThroughPart extends BaseEditor { if (innerContent) { const targetTop = div.getBoundingClientRect().top; const containerTop = innerContent.getBoundingClientRect().top; - const lineHeight = editor.getConfiguration().lineHeight; + const lineHeight = editor.getOption(EditorOption.lineHeight); const lineTop = (targetTop + (e.position.lineNumber - 1) * lineHeight) - containerTop; const lineBottom = lineTop + lineHeight; const scrollDimensions = this.scrollbar.getScrollDimensions(); diff --git a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts index b4f37b1b276..80809f4d14d 100644 --- a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts +++ b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts @@ -21,7 +21,7 @@ import { FileService } from 'vs/platform/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; import { IFileService } from 'vs/platform/files/common/files'; import { hashPath, BackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; @@ -49,7 +49,7 @@ const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', hashPath(u class TestBackupEnvironmentService extends WorkbenchEnvironmentService { constructor(backupPath: string) { - super({ ...parseArgs(process.argv), ...{ backupPath, 'user-data-dir': userdataDir } } as IWindowConfiguration, process.execPath); + super({ ...parseArgs(process.argv, OPTIONS), ...{ backupPath, 'user-data-dir': userdataDir } } as IWindowConfiguration, process.execPath); } } diff --git a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts index 671a8064710..372826a2ae7 100644 --- a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts +++ b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts @@ -23,6 +23,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ILabelService } from 'vs/platform/label/common/label'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; abstract class Recording { @@ -414,7 +415,7 @@ export class BulkEditService implements IBulkEditService { } } - if (codeEditor && codeEditor.getConfiguration().readOnly) { + if (codeEditor && codeEditor.getOption(EditorOption.readOnly)) { // If the code editor is readonly still allow bulk edits to be applied #68549 codeEditor = undefined; } diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts index 11587ed86d2..c3fc2b97536 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts @@ -11,7 +11,7 @@ import * as fs from 'fs'; import * as json from 'vs/base/common/json'; import { Registry } from 'vs/platform/registry/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { TestTextFileService, workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices'; import * as uuid from 'vs/base/common/uuid'; @@ -46,7 +46,7 @@ import { FileUserDataProvider } from 'vs/workbench/services/userData/common/file class TestEnvironmentService extends WorkbenchEnvironmentService { constructor(private _appSettingsHome: URI) { - super(parseArgs(process.argv) as IWindowConfiguration, process.execPath); + super(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath); } get appSettingsHome() { return this._appSettingsHome; } diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts index ffd0eccd172..3fb4263663b 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts @@ -11,7 +11,7 @@ import * as os from 'os'; import { URI } from 'vs/base/common/uri'; import { Registry } from 'vs/platform/registry/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import * as pfs from 'vs/base/node/pfs'; import * as uuid from 'vs/base/common/uuid'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; @@ -51,7 +51,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ class TestEnvironmentService extends WorkbenchEnvironmentService { constructor(private _appSettingsHome: URI) { - super(parseArgs(process.argv) as IWindowConfiguration, process.execPath); + super(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath); } get appSettingsHome() { return this._appSettingsHome; } diff --git a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts index f5d0b60b07b..882b085ff97 100644 --- a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts @@ -86,12 +86,12 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR }, envVariables); } - public resolveWithInteractionReplace(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary): Promise { - // resolve any non-interactive variables - config = this.resolveAny(folder, config); + public async resolveWithInteractionReplace(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary): Promise { + // resolve any non-interactive variables and any contributed variables + config = await this.resolveAny(folder, config); // resolve input variables in the order in which they are encountered - return this.resolveWithInteraction(folder, config, section, variables).then(mapping => { + return this.resolveWithInteraction(folder, config, section, variables, true).then(mapping => { // finally substitute evaluated command variables (if there are any) if (!mapping) { return null; @@ -103,9 +103,9 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR }); } - public resolveWithInteraction(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary): Promise | undefined> { - // resolve any non-interactive variables - const resolved = this.resolveAnyMap(folder, config); + public async resolveWithInteraction(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary, skipContributed: boolean = false): Promise | undefined> { + // resolve any non-interactive variables and any contributed variables + const resolved = await this.resolveAnyMap(folder, config); config = resolved.newConfig; const allVariableMapping: Map = resolved.resolvedVariables; diff --git a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts index 5559fd26ea8..ea98be3d578 100644 --- a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts @@ -20,7 +20,7 @@ export interface IConfigurationResolverService { * Recursively resolves all variables in the given config and returns a copy of it with substituted values. * Command variables are only substituted if a "commandValueMapping" dictionary is given and if it contains an entry for the command. */ - resolveAny(folder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): any; + resolveAny(folder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise; /** * Recursively resolves all variables (including commands and user input) in the given config and returns a copy of it with substituted values. @@ -36,6 +36,12 @@ export interface IConfigurationResolverService { * Keys in the map will be of the format input:variableName or command:variableName. */ resolveWithInteraction(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary): Promise | undefined>; + + /** + * Contributes a variable that can be resolved later. Consumers that use resolveAny, resolveWithInteraction, + * and resolveWithInteractionReplace will have contributed variables resolved. + */ + contributeVariable(variable: string, resolution: () => Promise): void; } export interface PromptStringInputInfo { diff --git a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts index b9284cb24ad..469a3ea58b8 100644 --- a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts @@ -28,9 +28,12 @@ export interface IVariableResolveContext { export class AbstractVariableResolverService implements IConfigurationResolverService { static VARIABLE_REGEXP = /\$\{(.*?)\}/g; + static VARIABLE_REGEXP_SINGLE = /\$\{(.*?)\}/; _serviceBrand: undefined; + private _contributedVariables: Map Promise> = new Map(); + constructor( private _context: IVariableResolveContext, private _envVariables: IProcessEnvironment @@ -50,8 +53,7 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return this.recursiveResolve(root ? root.uri : undefined, value); } - public resolveAnyBase(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary, resolvedVariables?: Map): any { - + private async resolveAnyBase(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary, resolvedVariables?: Map): Promise { const result = objects.deepClone(config) as any; // hoist platform specific attributes to top level @@ -69,16 +71,16 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe delete result.linux; // substitute all variables recursively in string values - return this.recursiveResolve(workspaceFolder ? workspaceFolder.uri : undefined, result, commandValueMapping, resolvedVariables); + return this.recursiveResolvePromise(workspaceFolder ? workspaceFolder.uri : undefined, result, commandValueMapping, resolvedVariables); } - public resolveAny(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): any { + public resolveAny(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise { return this.resolveAnyBase(workspaceFolder, config, commandValueMapping); } - public resolveAnyMap(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): { newConfig: any, resolvedVariables: Map } { + protected async resolveAnyMap(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise<{ newConfig: any, resolvedVariables: Map }> { const resolvedVariables = new Map(); - const newConfig = this.resolveAnyBase(workspaceFolder, config, commandValueMapping, resolvedVariables); + const newConfig = await this.resolveAnyBase(workspaceFolder, config, commandValueMapping, resolvedVariables); return { newConfig, resolvedVariables }; } @@ -90,6 +92,14 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe throw new Error('resolveWithInteraction not implemented.'); } + public contributeVariable(variable: string, resolution: () => Promise): void { + if (this._contributedVariables.has(variable)) { + throw new Error('Variable ' + variable + ' is contributed twice.'); + } else { + this._contributedVariables.set(variable, resolution); + } + } + private recursiveResolve(folderUri: uri | undefined, value: any, commandValueMapping?: IStringDictionary, resolvedVariables?: Map): any { if (types.isString(value)) { return this.resolveString(folderUri, value, commandValueMapping, resolvedVariables); @@ -106,6 +116,23 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return value; } + private async recursiveResolvePromise(folderUri: uri | undefined, value: any, commandValueMapping?: IStringDictionary, resolvedVariables?: Map): Promise { + if (types.isString(value)) { + return this.resolveStringPromise(folderUri, value, commandValueMapping, resolvedVariables); + } else if (types.isArray(value)) { + return Promise.all(value.map(s => this.recursiveResolvePromise(folderUri, s, commandValueMapping, resolvedVariables))); + } else if (types.isObject(value)) { + let result: IStringDictionary | string[]> = Object.create(null); + const keys = Object.keys(value); + for (let key of keys) { + const replaced = await this.resolveStringPromise(folderUri, key, commandValueMapping, resolvedVariables); + result[replaced] = await this.recursiveResolvePromise(folderUri, value[key], commandValueMapping, resolvedVariables); + } + return result; + } + return value; + } + private resolveString(folderUri: uri | undefined, value: string, commandValueMapping: IStringDictionary | undefined, resolvedVariables?: Map): string { // loop through all variables occurrences in 'value' @@ -123,6 +150,37 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return replaced; } + private async resolveStringPromise(folderUri: uri | undefined, value: string, commandValueMapping: IStringDictionary | undefined, resolvedVariables?: Map): Promise { + // loop through all variables occurrences in 'value' + const matches = value.match(AbstractVariableResolverService.VARIABLE_REGEXP); + const replaces: Map = new Map(); + if (!matches) { + return value; + } + for (const match of matches) { + const evaluate = await this.evaluateSingleContributedVariable(match, match.match(AbstractVariableResolverService.VARIABLE_REGEXP_SINGLE)![1]); + if (evaluate !== match) { + replaces.set(match, evaluate); + } + } + + const replaced = value.replace(AbstractVariableResolverService.VARIABLE_REGEXP, (match: string, variable: string) => { + + let resolvedValue = this.evaluateSingleVariable(match, variable, folderUri, commandValueMapping); + if ((resolvedValue === match) && (replaces.has(match))) { + resolvedValue = replaces.get(match)!; + } + + if (resolvedVariables) { + resolvedVariables.set(variable, resolvedValue); + } + + return resolvedValue; + }); + + return replaced; + } + private evaluateSingleVariable(match: string, variable: string, folderUri: uri | undefined, commandValueMapping: IStringDictionary | undefined): string { // try to separate variable arguments from variable name @@ -271,6 +329,16 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe } } + private async evaluateSingleContributedVariable(match: string, variable: string): Promise { + if (this._contributedVariables.has(variable)) { + const contributedValue: string | undefined = await this._contributedVariables.get(variable)!(); + if (contributedValue !== undefined) { + return contributedValue; + } + } + return match; + } + private resolveFromMap(match: string, argument: string | undefined, commandValueMapping: IStringDictionary | undefined, prefix: string): string { if (argument && commandValueMapping) { const v = commandValueMapping[prefix + ':' + argument]; diff --git a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts index 49a80b64df0..6b29d49b2eb 100644 --- a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts @@ -487,6 +487,19 @@ suite('Configuration Resolver Service', () => { assert.equal(2, mockCommandService.callCount); }); }); + test('contributed variable', () => { + const buildTask = 'npm: compile'; + const variable = 'defaultBuildTask'; + const configuration = { + 'name': '${' + variable + '}', + }; + configurationResolverService!.contributeVariable(variable, async () => { return buildTask; }); + return configurationResolverService!.resolveAny(workspace, configuration).then(result => { + assert.deepEqual(result, { + 'name': `${buildTask}` + }); + }); + }); }); diff --git a/src/vs/workbench/services/credentials/browser/credentialsService.ts b/src/vs/workbench/services/credentials/browser/credentialsService.ts index 3bc3637a2b6..d4b425e4adc 100644 --- a/src/vs/workbench/services/credentials/browser/credentialsService.ts +++ b/src/vs/workbench/services/credentials/browser/credentialsService.ts @@ -25,7 +25,7 @@ export class BrowserCredentialsService implements ICredentialsService { if (environmentService.options && environmentService.options.credentialsProvider) { this.credentialsProvider = environmentService.options.credentialsProvider; } else { - this.credentialsProvider = new LocalStorageCredentialsProvider(); + this.credentialsProvider = new InMemoryCredentialsProvider(); } } @@ -56,80 +56,44 @@ interface ICredential { password: string; } -class LocalStorageCredentialsProvider implements ICredentialsProvider { +class InMemoryCredentialsProvider implements ICredentialsProvider { - static readonly CREDENTIALS_OPENED_KEY = 'credentials.provider'; - - private _credentials: ICredential[] | undefined; - private get credentials(): ICredential[] { - if (!this._credentials) { - try { - const serializedCredentials = window.localStorage.getItem(LocalStorageCredentialsProvider.CREDENTIALS_OPENED_KEY); - if (serializedCredentials) { - this._credentials = JSON.parse(serializedCredentials); - } - } catch (error) { - // ignore - } - - if (!Array.isArray(this._credentials)) { - this._credentials = []; - } - } - - return this._credentials; - } - - private save(): void { - window.localStorage.setItem(LocalStorageCredentialsProvider.CREDENTIALS_OPENED_KEY, JSON.stringify(this.credentials)); - } + private credentials: ICredential[] = []; async getPassword(service: string, account: string): Promise { - return this.doGetPassword(service, account); - } + const credential = this.doFindPassword(service, account); - private async doGetPassword(service: string, account?: string): Promise { - for (const credential of this.credentials) { - if (credential.service === service) { - if (typeof account !== 'string' || account === credential.account) { - return credential.password; - } - } - } - - return null; + return credential ? credential.password : null; } async setPassword(service: string, account: string, password: string): Promise { this.deletePassword(service, account); - this.credentials.push({ service, account, password }); - - this.save(); } async deletePassword(service: string, account: string): Promise { - let found = false; - - this._credentials = this.credentials.filter(credential => { - if (credential.service === service && credential.account === account) { - found = true; - - return false; - } - - return true; - }); - - if (found) { - this.save(); + const credential = this.doFindPassword(service, account); + if (credential) { + this.credentials = this.credentials.splice(this.credentials.indexOf(credential), 1); } - return found; + return !!credential; } async findPassword(service: string): Promise { - return this.doGetPassword(service); + const credential = this.doFindPassword(service); + + return credential ? credential.password : null; + } + + private doFindPassword(service: string, account?: string): ICredential | null { + for (const credential of this.credentials) { + if (credential.service === service && (typeof account !== 'string' || credential.account === account)) { + return credential; + } + } + + return null; } async findCredentials(service: string): Promise> { diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index 4ae911b01ff..ef234672a77 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -46,14 +46,14 @@ import { Schemas } from 'vs/base/common/network'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { URI } from 'vs/base/common/uri'; import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; class TestEnvironmentService extends WorkbenchEnvironmentService { constructor(private _appSettingsHome: URI) { - super(parseArgs(process.argv) as IWindowConfiguration, process.execPath); + super(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath); } get appSettingsHome() { return this._appSettingsHome; } diff --git a/src/vs/workbench/services/preferences/common/preferencesModels.ts b/src/vs/workbench/services/preferences/common/preferencesModels.ts index 2f334c3ca5a..e0f621a144a 100644 --- a/src/vs/workbench/services/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/services/preferences/common/preferencesModels.ts @@ -1043,6 +1043,13 @@ export function createValidator(prop: IConfigurationPropertySchema): (value: any const stringArrayValue = value as string[]; + if (prop.uniqueItems) { + if (new Set(stringArrayValue).size < stringArrayValue.length) { + message += nls.localize('validations.stringArrayUniqueItems', 'Array has duplicate items'); + message += '\n'; + } + } + if (prop.minItems && stringArrayValue.length < prop.minItems) { message += nls.localize('validations.stringArrayMinItem', 'Array must have at least {0} items', prop.minItems); message += '\n'; diff --git a/src/vs/workbench/services/preferences/test/common/preferencesModel.test.ts b/src/vs/workbench/services/preferences/test/common/preferencesModel.test.ts index b02e29c0c96..9fbfb467a2b 100644 --- a/src/vs/workbench/services/preferences/test/common/preferencesModel.test.ts +++ b/src/vs/workbench/services/preferences/test/common/preferencesModel.test.ts @@ -328,4 +328,10 @@ suite('Preferences Model test', () => { arr.rejects(['a']).withMessage(`err: must be friendly`); }); + + test('uniqueItems', () => { + const arr = new ArrayTester({ type: 'array', items: { type: 'string' }, uniqueItems: true }); + + arr.rejects(['a', 'a']).withMessage(`Array has duplicate items`); + }); }); diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index 539de46fea9..a608d90765f 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -158,9 +158,8 @@ export abstract class TextFileService extends Disposable implements ITextFileSer // since a backup did not happen, we have to confirm for the dirty files now return this.confirmBeforeShutdown(); - }, errors => { - const firstError = errors[0]; - this.notificationService.error(nls.localize('files.backup.failSave', "Files that are dirty could not be written to the backup location (Error: {0}). Try saving your files first and then exit.", firstError.message)); + }, error => { + this.notificationService.error(nls.localize('files.backup.failSave', "Files that are dirty could not be written to the backup location (Error: {0}). Try saving your files first and then exit.", error.message)); return true; // veto, the backups failed }); diff --git a/src/vs/workbench/services/url/browser/urlService.ts b/src/vs/workbench/services/url/browser/urlService.ts index dfbca795c40..b073447fc26 100644 --- a/src/vs/workbench/services/url/browser/urlService.ts +++ b/src/vs/workbench/services/url/browser/urlService.ts @@ -5,17 +5,10 @@ import { IURLService } from 'vs/platform/url/common/url'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { AbstractURLService } from 'vs/platform/url/common/urlService'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Event } from 'vs/base/common/event'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { IRequestService } from 'vs/platform/request/common/request'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { streamToBuffer } from 'vs/base/common/buffer'; -import { ILogService } from 'vs/platform/log/common/log'; -import { generateUuid } from 'vs/base/common/uuid'; export interface IURLCallbackProvider { @@ -47,130 +40,30 @@ export class BrowserURLService extends AbstractURLService { _serviceBrand: undefined; - private provider: IURLCallbackProvider; + private provider: IURLCallbackProvider | undefined; constructor( - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IInstantiationService instantiationService: IInstantiationService + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService ) { super(); - this.provider = environmentService.options && environmentService.options.urlCallbackProvider ? environmentService.options.urlCallbackProvider : instantiationService.createInstance(SelfhostURLCallbackProvider); + this.provider = environmentService.options!.urlCallbackProvider; this.registerListeners(); } private registerListeners(): void { - this._register(this.provider.onCallback(uri => this.open(uri))); + if (this.provider) { + this._register(this.provider.onCallback(uri => this.open(uri))); + } } create(options?: Partial): URI { - return this.provider.create(options); - } -} - -class SelfhostURLCallbackProvider extends Disposable implements IURLCallbackProvider { - - static FETCH_INTERVAL = 500; // fetch every 500ms - static FETCH_TIMEOUT = 5 * 60 * 1000; // ...but stop after 5min - - static QUERY_KEYS = { - REQUEST_ID: 'vscode-requestId', - SCHEME: 'vscode-scheme', - AUTHORITY: 'vscode-authority', - PATH: 'vscode-path', - QUERY: 'vscode-query', - FRAGMENT: 'vscode-fragment' - }; - - private readonly _onCallback: Emitter = this._register(new Emitter()); - readonly onCallback: Event = this._onCallback.event; - - constructor( - @IRequestService private readonly requestService: IRequestService, - @ILogService private readonly logService: ILogService - ) { - super(); - } - - create(options?: Partial): URI { - const queryValues: Map = new Map(); - - const requestId = generateUuid(); - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId); - - const { scheme, authority, path, query, fragment } = options ? options : { scheme: undefined, authority: undefined, path: undefined, query: undefined, fragment: undefined }; - - if (scheme) { - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.SCHEME, scheme); + if (this.provider) { + return this.provider.create(options); } - if (authority) { - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.AUTHORITY, authority); - } - - if (path) { - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.PATH, path); - } - - if (query) { - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.QUERY, query); - } - - if (fragment) { - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.FRAGMENT, fragment); - } - - // Start to poll on the callback being fired - this.periodicFetchCallback(requestId, Date.now()); - - return this.doCreateUri('/callback', queryValues); - } - - private async periodicFetchCallback(requestId: string, startTime: number): Promise { - - // Ask server for callback results - const queryValues: Map = new Map(); - queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId); - - const result = await this.requestService.request({ - url: this.doCreateUri('/fetch-callback', queryValues).toString(true) - }, CancellationToken.None); - - // Check for callback results - const content = await streamToBuffer(result.stream); - if (content.byteLength > 0) { - try { - this._onCallback.fire(URI.revive(JSON.parse(content.toString()))); - } catch (error) { - this.logService.error(error); - } - - return; // done - } - - // Continue fetching unless we hit the timeout - if (Date.now() - startTime < SelfhostURLCallbackProvider.FETCH_TIMEOUT) { - setTimeout(() => this.periodicFetchCallback(requestId, startTime), SelfhostURLCallbackProvider.FETCH_INTERVAL); - } - } - - private doCreateUri(path: string, queryValues: Map): URI { - let query: string | undefined = undefined; - - if (queryValues) { - let index = 0; - queryValues.forEach((value, key) => { - if (!query) { - query = ''; - } - - const prefix = (index++ === 0) ? '' : '&'; - query += `${prefix}${key}=${encodeURIComponent(value)}`; - }); - } - - return URI.parse(window.location.href).with({ path, query }); + return URI.parse('unsupported://'); } } diff --git a/src/vs/workbench/services/url/electron-browser/urlService.ts b/src/vs/workbench/services/url/electron-browser/urlService.ts index b4a20ed825f..e9a8a6f1ec2 100644 --- a/src/vs/workbench/services/url/electron-browser/urlService.ts +++ b/src/vs/workbench/services/url/electron-browser/urlService.ts @@ -4,13 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; -import { URI } from 'vs/base/common/uri'; +import { URI, UriComponents } from 'vs/base/common/uri'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -import { URLServiceChannelClient, URLHandlerChannel } from 'vs/platform/url/node/urlIpc'; +import { URLServiceChannelClient, URLHandlerChannel } from 'vs/platform/url/common/urlIpc'; import { URLService } from 'vs/platform/url/node/urlService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import product from 'vs/platform/product/node/product'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IWindowService } from 'vs/platform/windows/common/windows'; export class RelayURLService extends URLService implements IURLHandler { @@ -18,7 +19,8 @@ export class RelayURLService extends URLService implements IURLHandler { constructor( @IMainProcessService mainProcessService: IMainProcessService, - @IOpenerService openerService: IOpenerService + @IOpenerService openerService: IOpenerService, + @IWindowService private windowService: IWindowService ) { super(); @@ -28,6 +30,19 @@ export class RelayURLService extends URLService implements IURLHandler { openerService.registerOpener(this); } + create(options?: Partial): URI { + const uri = super.create(options); + + let query = uri.query; + if (!query) { + query = `windowId=${encodeURIComponent(this.windowService.windowId)}`; + } else { + query += `&windowId=${encodeURIComponent(this.windowService.windowId)}`; + } + + return uri.with({ query }); + } + async open(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise { if (resource.scheme !== product.urlProtocol) { return false; diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 4014dc4da45..689930dc68b 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -30,7 +30,7 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { ITextFileStreamContent, ITextFileService, IResourceEncoding, IReadTextFileOptions } from 'vs/workbench/services/textfile/common/textfiles'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -91,7 +91,7 @@ export function createFileInput(instantiationService: IInstantiationService, res return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); } -export const TestEnvironmentService = new WorkbenchEnvironmentService(parseArgs(process.argv) as IWindowConfiguration, process.execPath); +export const TestEnvironmentService = new WorkbenchEnvironmentService(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath); export class TestContextService implements IWorkspaceContextService { public _serviceBrand: undefined; diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 0ffdec8e834..2c625970c96 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -222,7 +222,6 @@ import 'vs/workbench/contrib/themes/browser/themes.contribution'; import 'vs/workbench/contrib/watermark/browser/watermark'; // Welcome -import 'vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution'; import 'vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay'; // Call Hierarchy diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 27ef543f040..562a0195477 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -136,6 +136,7 @@ import 'vs/workbench/contrib/cli/node/cli.contribution'; import 'vs/workbench/contrib/themes/test/electron-browser/themes.test.contribution'; // Welcome +import 'vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution'; import 'vs/workbench/contrib/welcome/gettingStarted/electron-browser/gettingStarted.contribution'; import 'vs/workbench/contrib/welcome/page/browser/welcomePage.contribution'; diff --git a/test/automation/src/debug.ts b/test/automation/src/debug.ts index 4a74b9d98b0..89579828be8 100644 --- a/test/automation/src/debug.ts +++ b/test/automation/src/debug.ts @@ -28,7 +28,7 @@ const STACK_FRAME = `${VIEWLET} .monaco-list-row .stack-frame`; const SPECIFIC_STACK_FRAME = (filename: string) => `${STACK_FRAME} .file[title*="${filename}"]`; const VARIABLE = `${VIEWLET} .debug-variables .monaco-list-row .expression`; const CONSOLE_OUTPUT = `.repl .output.expression .value`; -const CONSOLE_INPUT_OUTPUT = `.repl .input-output-pair .output.expression .value`; +const CONSOLE_EVALUATION_RESULT = `.repl .evaluation-result.expression .value`; const REPL_FOCUSED = '.repl-input-wrapper .monaco-editor textarea'; @@ -132,8 +132,8 @@ export class Debug extends Viewlet { // Wait for the keys to be picked up by the editor model such that repl evalutes what just got typed await this.editor.waitForEditorContents('debug:replinput', s => s.indexOf(text) >= 0); await this.code.dispatchKeybinding('enter'); - await this.code.waitForElement(CONSOLE_INPUT_OUTPUT); - await this.waitForOutput(output => accept(output[output.length - 1] || '')); + await this.code.waitForElements(CONSOLE_EVALUATION_RESULT, false, + elements => !!elements.length && accept(elements[elements.length - 1].textContent)); } // Different node versions give different number of variables. As a workaround be more relaxed when checking for variable count diff --git a/yarn.lock b/yarn.lock index ab352df288e..4e6e637d8f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3697,10 +3697,10 @@ gulp-symdest@^1.1.1: queue "^3.1.0" vinyl-fs "^2.4.3" -gulp-tsb@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/gulp-tsb/-/gulp-tsb-4.0.0.tgz#3e5a0d191cb070f1c936f70e8a41c54ce2e0b5a0" - integrity sha512-Y1csbJ0g2ihZr2aYv7O3VR/IwBzgcK3pCrga3yJ1ZWi3Tx3hAd51Lra74VnLxfekK7aZAxqw7Y9QOmxNs8LW8w== +gulp-tsb@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/gulp-tsb/-/gulp-tsb-4.0.2.tgz#8717a18f1ce032147e010028f0a59863bd552b96" + integrity sha512-xF88h0vFH8JkunSnmVrYfrR3LGTMAY+KTkHHF/S9BAOCsdaC83/hv4EmpcLxev7B+2yd3+xcitlsDFMBSo/gSw== dependencies: ansi-colors "^1.0.1" fancy-log "^1.3.2" @@ -8866,10 +8866,10 @@ vscode-proxy-agent@0.4.0: https-proxy-agent "2.2.1" socks-proxy-agent "4.0.1" -vscode-ripgrep@^1.5.6: - version "1.5.6" - resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.6.tgz#93bf5c99ca5f8248950a305e224f6ca153c30af4" - integrity sha512-WRIM9XpUj6dsfdAmuI3ANbmT1ysPUVsYy/2uCLDHJa9kbiB4T7uGvFnnc0Rgx2qQnyRAwL7PeWaFgUljPPxf2g== +vscode-ripgrep@^1.5.7: + version "1.5.7" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.7.tgz#acb6b548af488a4bca5d0f1bb5faf761343289ce" + integrity sha512-/Vsz/+k8kTvui0q3O74pif9FK0nKopgFTiGNVvxicZANxtSA8J8gUE9GQ/4dpi7D/2yI/YVORszwVskFbz46hQ== vscode-sqlite3@4.0.8: version "4.0.8" @@ -9158,10 +9158,10 @@ xterm-addon-web-links@0.1.0-beta10: resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== -xterm@3.15.0-beta101: - version "3.15.0-beta101" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta101.tgz#38ffa0df5a3e9bdcb1818e74fe59b2f98b0fff69" - integrity sha512-HRa7+FDqQ8iWBTvb1Ni+uMGILnu6k9mF7JHMHRHfWxFoQlSoGYCyfdyXlJjk68YN8GsEQREmrII6cPLiQizdEQ== +xterm@3.15.0-beta108: + version "3.15.0-beta108" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta108.tgz#d113f6d1e4d4b7645ab3ff002c81a4dba8a78a28" + integrity sha512-btZXgI9BeawFzitw3EZvFPsH3kfBgJS55LOdz9DjEany3y9FfvmnVhq7wn4x1PmTU/djHobGGhMNemxptk+ryg== y18n@^3.2.1: version "3.2.1"