diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 6bcd29db94a..f7ee69cd279 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -102,23 +102,28 @@ steps: condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - script: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. set -e APP_ROOT=$(agent.builddirectory)/VSCode-darwin APP_NAME="`ls $APP_ROOT | head -n 1`" INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin" \ ./scripts/test-integration.sh --build --tfs "Integration Tests" displayName: Run integration tests condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) -- script: | - set -e - cd test/smoke - yarn compile - cd - - yarn smoketest --web --headless - continueOnError: true - displayName: Run web smoke tests - condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) +# Web Smoke Tests disabled due to https://github.com/microsoft/vscode/issues/80308 +# - script: | +# set -e +# cd test/smoke +# yarn compile +# cd - +# yarn smoketest --web --headless +# continueOnError: true +# displayName: Run web smoke tests +# condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - script: | set -e diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index 83e40784649..0d01ba8a608 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -105,10 +105,14 @@ steps: condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - script: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. set -e APP_ROOT=$(agent.builddirectory)/VSCode-linux-x64 APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName") INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-x64" \ DISPLAY=:10 ./scripts/test-integration.sh --build --tfs "Integration Tests" # yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-x64" displayName: Run integration tests diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 794dd8e3b99..76e1f6a927a 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -104,6 +104,7 @@ steps: AZURE_WEBVIEW_STORAGE_ACCESS_KEY="$(vscode-webview-storage-key)" \ ./build/azure-pipelines/common/publish-webview.sh displayName: Publish Webview + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) - script: | set -e diff --git a/build/azure-pipelines/publish-types/publish-types.yml b/build/azure-pipelines/publish-types/publish-types.yml index d377226366a..6808054b3f1 100644 --- a/build/azure-pipelines/publish-types/publish-types.yml +++ b/build/azure-pipelines/publish-types/publish-types.yml @@ -15,6 +15,22 @@ steps: inputs: versionSpec: "1.x" +- bash: | + TAG_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`) + CHANNEL="G1C14HJ2F" + + if [ "$TAG_VERSION" == "1.999.0" ]; then + MESSAGE=". Someone pushed 1.999.0 tag. Please delete it ASAP from remote and local." + + curl -X POST -H "Authorization: Bearer $(SLACK_TOKEN)" \ + -H 'Content-type: application/json; charset=utf-8' \ + --data '{"channel":"'"$CHANNEL"'", "link_names": true, "text":"'"$MESSAGE"'"}' \ + https://slack.com/api/chat.postMessage + + exit 1 + fi + displayName: Check 1.999.0 tag + - bash: | # Install build dependencies (cd build && yarn) diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 2c40ee3113d..ae36c8cbe84 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -113,12 +113,15 @@ steps: condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - powershell: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json $AppNameShort = $AppProductJson.nameShort - exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; .\scripts\test-integration.bat --build --tfs "Integration Tests" } + exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)"; .\scripts\test-integration.bat --build --tfs "Integration Tests" } displayName: Run integration tests condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index e4f7b58d50a..ca28c413a71 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -21,7 +21,6 @@ const nlsDev = require('vscode-nls-dev'); const root = path.dirname(__dirname); const commit = util.getVersion(root); const plumber = require('gulp-plumber'); -const _ = require('underscore'); const ext = require('./lib/extensions'); const extensionsPath = path.join(path.dirname(__dirname), 'extensions'); @@ -37,16 +36,16 @@ const tasks = compilations.map(function (tsconfigFile) { const absolutePath = path.join(extensionsPath, tsconfigFile); const relativeDirname = path.dirname(tsconfigFile); - const tsconfig = require(absolutePath); - const tsOptions = _.assign({}, tsconfig.extends ? require(path.join(extensionsPath, relativeDirname, tsconfig.extends)).compilerOptions : {}, tsconfig.compilerOptions); - tsOptions.verbose = false; - tsOptions.sourceMap = true; + const overrideOptions = {}; + overrideOptions.sourceMap = true; const name = relativeDirname.replace(/\//g, '-'); 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); @@ -63,12 +62,12 @@ const tasks = compilations.map(function (tsconfigFile) { function createPipeline(build, emitError) { const reporter = createReporter(); - tsOptions.inlineSources = !!build; - tsOptions.base = path.dirname(absolutePath); + overrideOptions.inlineSources = Boolean(build); + overrideOptions.base = path.dirname(absolutePath); - const compilation = tsb.create(tsOptions, null, null, err => reporter(err.toString())); + 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 @@ -98,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()) @@ -115,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)) @@ -125,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()) @@ -160,4 +163,4 @@ const compileExtensionsBuildTask = task.define('compile-extensions-build', task. )); gulp.task(compileExtensionsBuildTask); -exports.compileExtensionsBuildTask = compileExtensionsBuildTask; \ No newline at end of file +exports.compileExtensionsBuildTask = compileExtensionsBuildTask; diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 6bb695db68c..baa2b749486 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -49,7 +49,6 @@ const nodeModules = ['electron', 'original-fs'] const vscodeEntryPoints = _.flatten([ buildfile.entrypoint('vs/workbench/workbench.desktop.main'), buildfile.base, - buildfile.serviceWorker, buildfile.workbenchDesktop, buildfile.code ]); @@ -94,6 +93,7 @@ const optimizeVSCodeTask = task.define('optimize-vscode', task.series( resources: vscodeResources, loaderConfig: common.loaderConfig(nodeModules), out: 'out-vscode', + inlineAmdImages: true, bundleInfo: undefined }) )); @@ -480,7 +480,7 @@ gulp.task(task.define( optimizeVSCodeTask, function () { const pathToMetadata = './out-vscode/nls.metadata.json'; - const pathToExtensions = './extensions/*'; + const pathToExtensions = '.build/extensions/*'; const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}'; return es.merge( @@ -501,7 +501,7 @@ gulp.task(task.define( optimizeVSCodeTask, function () { const pathToMetadata = './out-vscode/nls.metadata.json'; - const pathToExtensions = './extensions/*'; + const pathToExtensions = '.build/extensions/*'; const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}'; return es.merge( diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index 54a270695bd..fa4393c4bd4 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -238,7 +238,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 edd34cd3931..d0cb6be52c7 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/workbench.html', 'out-build/vs/base/browser/ui/octiconLabel/octicons/**', 'out-build/vs/**/markdown.css', @@ -56,7 +57,6 @@ const buildfile = require('../src/buildfile'); const vscodeWebEntryPoints = _.flatten([ buildfile.entrypoint('vs/workbench/workbench.web.api'), buildfile.base, - buildfile.serviceWorker, buildfile.workerExtensionHost, buildfile.keyboardMaps, buildfile.workbenchWeb @@ -118,7 +118,10 @@ function packageTask(sourceFolderName, destinationFolderName) { const favicon = gulp.src('resources/server/favicon.ico', { base: 'resources/server' }); const manifest = gulp.src('resources/server/manifest.json', { base: 'resources/server' }); - const pwaicon = gulp.src('resources/server/code.png', { base: 'resources/server' }); + const pwaicons = es.merge( + gulp.src('resources/server/code-192.png', { base: 'resources/server' }), + gulp.src('resources/server/code-512.png', { base: 'resources/server' }) + ); let all = es.merge( packageJsonStream, @@ -128,7 +131,7 @@ function packageTask(sourceFolderName, destinationFolderName) { deps, favicon, manifest, - pwaicon + pwaicons ); let result = all diff --git a/build/lib/compilation.js b/build/lib/compilation.js index 62aff873509..5074376df4e 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -11,7 +11,6 @@ const bom = require("gulp-bom"); const sourcemaps = require("gulp-sourcemaps"); const tsb = require("gulp-tsb"); const path = require("path"); -const _ = require("underscore"); const monacodts = require("../monaco/api"); const nls = require("./nls"); const reporter_1 = require("./reporter"); @@ -22,14 +21,7 @@ const watch = require('./watch'); const reporter = reporter_1.createReporter(); function getTypeScriptCompilerOptions(src) { const rootDir = path.join(__dirname, `../../${src}`); - const tsconfig = require(`../../${src}/tsconfig.json`); - let options; - if (tsconfig.extends) { - options = Object.assign({}, require(path.join(rootDir, tsconfig.extends)).compilerOptions, tsconfig.compilerOptions); - } - else { - options = tsconfig.compilerOptions; - } + let options = {}; options.verbose = false; options.sourceMap = true; if (process.env['VSCODE_NO_SOURCEMAP']) { // To be used by developers in a hurry @@ -38,14 +30,13 @@ function getTypeScriptCompilerOptions(src) { options.rootDir = rootDir; options.baseUrl = rootDir; options.sourceRoot = util.toFileUri(rootDir); - options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 'CRLF' : 'LF'; + options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 0 : 1; return options; } function createCompile(src, build, emitError) { - const opts = _.clone(getTypeScriptCompilerOptions(src)); - opts.inlineSources = !!build; - opts.noFilesystemLookup = true; - const ts = tsb.create(opts, true, undefined, err => reporter(err.toString())); + 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 utf8Filter = util.filter(data => /(\/|\\)test(\/|\\).*utf8/.test(data.path)); const tsFilter = util.filter(data => /\.ts$/.test(data.path)); @@ -64,23 +55,17 @@ function createCompile(src, build, emitError) { .pipe(sourcemaps.write('.', { addComment: false, includeContent: !!build, - sourceRoot: opts.sourceRoot + sourceRoot: overrideOptions.sourceRoot })) .pipe(tsFilter.restore) .pipe(reporter.end(!!emitError)); return es.duplex(input, output); }; } -const typesDts = [ - 'node_modules/typescript/lib/*.d.ts', - 'node_modules/@types/**/*.d.ts', - '!node_modules/@types/webpack/**/*', - '!node_modules/@types/uglify-js/**/*', -]; function compileTask(src, out, build) { return function () { const compile = createCompile(src, build, true); - const srcPipe = es.merge(gulp.src(`${src}/**`, { base: `${src}` }), gulp.src(typesDts)); + const srcPipe = gulp.src(`${src}/**`, { base: `${src}` }); let generator = new MonacoGenerator(false); if (src === 'src') { generator.execute(); @@ -95,8 +80,8 @@ exports.compileTask = compileTask; function watchTask(out, build) { return function () { const compile = createCompile('src', build); - const src = es.merge(gulp.src('src/**', { base: 'src' }), gulp.src(typesDts)); - const watchSrc = watch('src/**', { base: 'src' }); + const src = gulp.src('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 f9544af9cc5..b52c49c5961 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -12,27 +12,21 @@ import * as bom from 'gulp-bom'; import * as sourcemaps from 'gulp-sourcemaps'; import * as tsb from 'gulp-tsb'; import * as path from 'path'; -import * as _ from 'underscore'; import * as monacodts from '../monaco/api'; import * as nls from './nls'; import { createReporter } from './reporter'; import * as util from './util'; import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; +import ts = require('typescript'); const watch = require('./watch'); const reporter = createReporter(); -function getTypeScriptCompilerOptions(src: string) { +function getTypeScriptCompilerOptions(src: string): ts.CompilerOptions { const rootDir = path.join(__dirname, `../../${src}`); - const tsconfig = require(`../../${src}/tsconfig.json`); - let options: { [key: string]: any }; - if (tsconfig.extends) { - options = Object.assign({}, require(path.join(rootDir, tsconfig.extends)).compilerOptions, tsconfig.compilerOptions); - } else { - options = tsconfig.compilerOptions; - } + let options: ts.CompilerOptions = {}; options.verbose = false; options.sourceMap = true; if (process.env['VSCODE_NO_SOURCEMAP']) { // To be used by developers in a hurry @@ -41,16 +35,15 @@ function getTypeScriptCompilerOptions(src: string) { options.rootDir = rootDir; options.baseUrl = rootDir; options.sourceRoot = util.toFileUri(rootDir); - options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 'CRLF' : 'LF'; + options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 0 : 1; return options; } function createCompile(src: string, build: boolean, emitError?: boolean): (token?: util.ICancellationToken) => NodeJS.ReadWriteStream { - const opts = _.clone(getTypeScriptCompilerOptions(src)); - opts.inlineSources = !!build; - opts.noFilesystemLookup = true; + const projectPath = path.join(__dirname, '../../', src, 'tsconfig.json'); + const overrideOptions = { ...getTypeScriptCompilerOptions(src), inlineSources: Boolean(build) }; - const ts = tsb.create(opts, true, undefined, err => reporter(err.toString())); + const ts = tsb.create(projectPath, overrideOptions, false, err => reporter(err)); return function (token?: util.ICancellationToken) { @@ -72,7 +65,7 @@ function createCompile(src: string, build: boolean, emitError?: boolean): (token .pipe(sourcemaps.write('.', { addComment: false, includeContent: !!build, - sourceRoot: opts.sourceRoot + sourceRoot: overrideOptions.sourceRoot })) .pipe(tsFilter.restore) .pipe(reporter.end(!!emitError)); @@ -81,22 +74,12 @@ function createCompile(src: string, build: boolean, emitError?: boolean): (token }; } -const typesDts = [ - 'node_modules/typescript/lib/*.d.ts', - 'node_modules/@types/**/*.d.ts', - '!node_modules/@types/webpack/**/*', - '!node_modules/@types/uglify-js/**/*', -]; - export function compileTask(src: string, out: string, build: boolean): () => NodeJS.ReadWriteStream { return function () { const compile = createCompile(src, build, true); - const srcPipe = es.merge( - gulp.src(`${src}/**`, { base: `${src}` }), - gulp.src(typesDts), - ); + const srcPipe = gulp.src(`${src}/**`, { base: `${src}` }); let generator = new MonacoGenerator(false); if (src === 'src') { @@ -115,11 +98,8 @@ export function watchTask(out: string, build: boolean): () => NodeJS.ReadWriteSt return function () { const compile = createCompile('src', build); - const src = es.merge( - gulp.src('src/**', { base: 'src' }), - gulp.src(typesDts), - ); - const watchSrc = watch('src/**', { base: 'src' }); + const src = gulp.src('src/**', { base: 'src' }); + const watchSrc = watch('src/**', { base: 'src', readDelay: 200 }); let generator = new MonacoGenerator(true); generator.execute(); diff --git a/build/lib/i18n.js b/build/lib/i18n.js index 067e1e66889..f7302fc12ee 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -580,7 +580,7 @@ function createXlfFilesForExtensions() { } return _xlf; } - gulp.src([`./extensions/${extensionName}/package.nls.json`, `./extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(event_stream_1.through(function (file) { + gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(event_stream_1.through(function (file) { if (file.isBuffer()) { const buffer = file.contents; const basename = path.basename(file.path); @@ -603,7 +603,7 @@ function createXlfFilesForExtensions() { } else if (basename === 'nls.metadata.json') { const json = JSON.parse(buffer.toString('utf8')); - const relPath = path.relative(`./extensions/${extensionName}`, path.dirname(file.path)); + const relPath = path.relative(`.build/extensions/${extensionName}`, path.dirname(file.path)); for (let file in json) { const fileContent = json[file]; getXlf().addFile(`extensions/${extensionName}/${relPath}/${file}`, fileContent.keys, fileContent.messages); @@ -906,8 +906,8 @@ function pullCoreAndExtensionsXlfFiles(apiHostname, username, password, language _coreAndExtensionResources.push(...json.workbench); // extensions let extensionsToLocalize = Object.create(null); - glob.sync('./extensions/**/*.nls.json').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); - glob.sync('./extensions/*/node_modules/vscode-nls').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); + glob.sync('.build/extensions/**/*.nls.json').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); + glob.sync('.build/extensions/*/node_modules/vscode-nls').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); Object.keys(extensionsToLocalize).forEach(extension => { _coreAndExtensionResources.push({ name: extension, project: extensionsProject }); }); @@ -1080,7 +1080,7 @@ function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pse resultingTranslationPaths.push({ id: 'vscode', resourceName: 'main.i18n.json' }); this.queue(translatedMainFile); for (let extension in extensionsPacks) { - const translatedExtFile = createI18nFile(`./extensions/${extension}`, extensionsPacks[extension]); + const translatedExtFile = createI18nFile(`.build/extensions/${extension}`, extensionsPacks[extension]); this.queue(translatedExtFile); const externalExtensionId = externalExtensions[extension]; if (externalExtensionId) { diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index 9f53df17bad..81bf1d3991b 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -701,7 +701,7 @@ export function createXlfFilesForExtensions(): ThroughStream { } return _xlf; } - gulp.src([`./extensions/${extensionName}/package.nls.json`, `./extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(through(function (file: File) { + gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(through(function (file: File) { if (file.isBuffer()) { const buffer: Buffer = file.contents as Buffer; const basename = path.basename(file.path); @@ -721,7 +721,7 @@ export function createXlfFilesForExtensions(): ThroughStream { getXlf().addFile(`extensions/${extensionName}/package`, keys, messages); } else if (basename === 'nls.metadata.json') { const json: BundledExtensionFormat = JSON.parse(buffer.toString('utf8')); - const relPath = path.relative(`./extensions/${extensionName}`, path.dirname(file.path)); + const relPath = path.relative(`.build/extensions/${extensionName}`, path.dirname(file.path)); for (let file in json) { const fileContent = json[file]; getXlf().addFile(`extensions/${extensionName}/${relPath}/${file}`, fileContent.keys, fileContent.messages); @@ -1045,8 +1045,8 @@ export function pullCoreAndExtensionsXlfFiles(apiHostname: string, username: str // extensions let extensionsToLocalize = Object.create(null); - glob.sync('./extensions/**/*.nls.json').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); - glob.sync('./extensions/*/node_modules/vscode-nls').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); + glob.sync('.build/extensions/**/*.nls.json').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); + glob.sync('.build/extensions/*/node_modules/vscode-nls').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); Object.keys(extensionsToLocalize).forEach(extension => { _coreAndExtensionResources.push({ name: extension, project: extensionsProject }); @@ -1245,7 +1245,7 @@ export function prepareI18nPackFiles(externalExtensions: Map, resultingT this.queue(translatedMainFile); for (let extension in extensionsPacks) { - const translatedExtFile = createI18nFile(`./extensions/${extension}`, extensionsPacks[extension]); + const translatedExtFile = createI18nFile(`.build/extensions/${extension}`, extensionsPacks[extension]); this.queue(translatedExtFile); const externalExtensionId = externalExtensions[extension]; 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 600bfacf261..916dd21cd1c 100644 --- a/build/lib/typings/gulp-tsb.d.ts +++ b/build/lib/typings/gulp-tsb.d.ts @@ -7,10 +7,9 @@ declare module "gulp-tsb" { } export interface IncrementalCompiler { - (token?:ICancellationToken): NodeJS.ReadWriteStream; - // program?: ts.Program; + (token?: ICancellationToken): NodeJS.ReadWriteStream; + src(): NodeJS.ReadStream; } + export function create(projectPath: string, existingOptions: any, verbose?: boolean, onError?: (message: any) => void): IncrementalCompiler; - export function create(configOrName: { [option: string]: string | number | boolean; } | string, verbose?: boolean, json?: boolean, onError?: (message: any) => void): IncrementalCompiler; - -} \ No newline at end of file +} 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/monaco/package.json b/build/monaco/package.json index 1962694ce6d..1ff3e4e72f3 100644 --- a/build/monaco/package.json +++ b/build/monaco/package.json @@ -1,7 +1,7 @@ { "name": "monaco-editor-core", "private": true, - "version": "0.16.0", + "version": "0.18.0", "description": "A browser based code editor", "author": "Microsoft Corporation", "license": "MIT", diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js index e0d43786621..6b1159bc65c 100644 --- a/build/npm/postinstall.js +++ b/build/npm/postinstall.js @@ -80,19 +80,6 @@ if (fs.existsSync(processTreeDts)) { fs.unlinkSync(processTreeDts); } -// Rewrite the @types/node typings avoid a conflict with es2018 typings. -// This is caused by our build not understanding `typesVersions` in the package.json -// -// TODO: Fix this -{ - console.log('Rewriting node_modules/@types/node to workaround lack of typesVersions support'); - const indexPath = path.join('node_modules', '@types', 'node', 'index.d.ts'); - - const contents = fs.readFileSync(indexPath).toString() - .replace(/interface IteratorResult \{ \}/, '// VSCODE EDIT — remove IteratorResult\n// interface IteratorResult { }'); - fs.writeFileSync(indexPath, contents); -} - function getInstalledVersion(packageName, cwd) { const opts = {}; if (cwd) { 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..3ff05c280fa 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" diff --git a/extensions/css-language-features/package.json b/extensions/css-language-features/package.json index 3b68a1713ed..a02d6c2be93 100644 --- a/extensions/css-language-features/package.json +++ b/extensions/css-language-features/package.json @@ -745,6 +745,10 @@ { "fileMatch": "*.css-data.json", "url": "https://raw.githubusercontent.com/Microsoft/vscode-css-languageservice/master/docs/customData.schema.json" + }, + { + "fileMatch": "package.json", + "url": "./schemas/package.schema.json" } ] }, diff --git a/extensions/css-language-features/schemas/package.schema.json b/extensions/css-language-features/schemas/package.schema.json new file mode 100644 index 00000000000..3aeca1e040a --- /dev/null +++ b/extensions/css-language-features/schemas/package.schema.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "CSS contributions to package.json", + "type": "object", + "properties": { + "contributes": { + "type": "object", + "properties": { + "css.customData": { + "type": "array", + "markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/Microsoft/vscode-css-languageservice/blob/master/docs/customData.md).\n\nVS Code loads custom data on startup to enhance its CSS support for the custom CSS properties, at directives, pseudo classes and pseudo elements you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.", + "items": { + "type": "string", + "description": "Relative path to a CSS custom data file" + } + } + } + } + } +} diff --git a/extensions/css-language-features/server/src/cssServerMain.ts b/extensions/css-language-features/server/src/cssServerMain.ts index a5c50d515c7..a1dee46c523 100644 --- a/extensions/css-language-features/server/src/cssServerMain.ts +++ b/extensions/css-language-features/server/src/cssServerMain.ts @@ -128,7 +128,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { const capabilities: ServerCapabilities = { // Tell the client that the server works in FULL text document sync mode textDocumentSync: documents.syncKind, - completionProvider: snippetSupport ? { resolveProvider: false, triggerCharacters: ['/'] } : undefined, + completionProvider: snippetSupport ? { resolveProvider: false, triggerCharacters: ['/', '-'] } : undefined, hoverProvider: true, documentSymbolProvider: true, referencesProvider: true, diff --git a/extensions/emmet/src/abbreviationActions.ts b/extensions/emmet/src/abbreviationActions.ts index 9508d3a6a0b..058a8579e2a 100644 --- a/extensions/emmet/src/abbreviationActions.ts +++ b/extensions/emmet/src/abbreviationActions.ts @@ -231,6 +231,21 @@ export function expandEmmetAbbreviation(args: any): Thenable void, reject: (err: any) => void }; @@ -29,7 +29,7 @@ class GitIgnoreDecorationProvider implements DecorationProvider { this.disposables.push(window.registerDecorationProvider(this)); } - provideDecoration(uri: Uri): Promise { + provideDecoration(uri: Uri): Promise { const repository = this.model.getRepository(uri); if (!repository) { @@ -48,7 +48,7 @@ class GitIgnoreDecorationProvider implements DecorationProvider { this.checkIgnoreSoon(); }).then(ignored => { if (ignored) { - return { + return { priority: 3, color: new ThemeColor('gitDecoration.ignoredResourceForeground') }; @@ -89,7 +89,7 @@ class GitIgnoreDecorationProvider implements DecorationProvider { class GitDecorationProvider implements DecorationProvider { - private static SubmoduleDecorationData: DecorationData = { + private static SubmoduleDecorationData: Decoration = { title: 'Submodule', letter: 'S', color: new ThemeColor('gitDecoration.submoduleResourceForeground') @@ -99,7 +99,7 @@ class GitDecorationProvider implements DecorationProvider { readonly onDidChangeDecorations: Event = this._onDidChangeDecorations.event; private disposables: Disposable[] = []; - private decorations = new Map(); + private decorations = new Map(); constructor(private repository: Repository) { this.disposables.push( @@ -109,7 +109,7 @@ class GitDecorationProvider implements DecorationProvider { } private onDidRunGitStatus(): void { - let newDecorations = new Map(); + let newDecorations = new Map(); this.collectSubmoduleDecorationData(newDecorations); this.collectDecorationData(this.repository.indexGroup, newDecorations); @@ -121,25 +121,22 @@ class GitDecorationProvider implements DecorationProvider { this._onDidChangeDecorations.fire([...uris.values()].map(value => Uri.parse(value, true))); } - private collectDecorationData(group: GitResourceGroup, bucket: Map): void { + private collectDecorationData(group: GitResourceGroup, bucket: Map): void { group.resourceStates.forEach(r => { - if (r.resourceDecoration - && r.type !== Status.DELETED - && r.type !== Status.INDEX_DELETED - ) { + if (r.resourceDecoration) { // not deleted and has a decoration bucket.set(r.original.toString(), r.resourceDecoration); } }); } - private collectSubmoduleDecorationData(bucket: Map): void { + private collectSubmoduleDecorationData(bucket: Map): void { for (const submodule of this.repository.submodules) { bucket.set(Uri.file(path.join(this.repository.root, submodule.path)).toString(), GitDecorationProvider.SubmoduleDecorationData); } } - provideDecoration(uri: Uri): DecorationData | undefined { + provideDecoration(uri: Uri): Decoration | undefined { return this.decorations.get(uri.toString()); } diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 8208ca6623e..5d47228c455 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -1766,7 +1766,7 @@ export class Repository { } const raw = await readfile(templatePath, 'utf8'); - return raw.replace(/\n?#.*/g, ''); + return raw.replace(/^\s*#.*$\n?/gm, ''); } catch (err) { return ''; diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index bf37d036d5c..1b9f7fbd89a 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { commands, Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento, SourceControlInputBoxValidationType, OutputChannel, LogLevel, env, ProgressOptions, CancellationToken } from 'vscode'; +import { commands, Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, Decoration, Memento, SourceControlInputBoxValidationType, OutputChannel, LogLevel, env, ProgressOptions, CancellationToken } from 'vscode'; import { Repository as BaseRepository, Commit, Stash, GitError, Submodule, CommitOptions, ForcePushMode } from './git'; import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent, combinedDisposable } from './util'; import { memoize, throttle, debounce } from './decorators'; @@ -157,10 +157,7 @@ export class Resource implements SourceControlResourceState { const tooltip = this.tooltip; const strikeThrough = this.strikeThrough; const faded = this.faded; - const letter = this.letter; - const color = this.color; - - return { strikeThrough, faded, tooltip, light, dark, letter, color, source: 'git.resource' /*todo@joh*/ }; + return { strikeThrough, faded, tooltip, light, dark }; } get letter(): string { @@ -247,12 +244,12 @@ export class Resource implements SourceControlResourceState { } } - get resourceDecoration(): DecorationData { + get resourceDecoration(): Decoration { const title = this.tooltip; const letter = this.letter; const color = this.color; const priority = this.priority; - return { bubble: true, source: 'git.resource', title, letter, color, priority }; + return { bubble: true, title, letter, color, priority }; } constructor( 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/gulp/src/main.ts b/extensions/gulp/src/main.ts index 6f9a9e49334..20d824c25ed 100644 --- a/extensions/gulp/src/main.ts +++ b/extensions/gulp/src/main.ts @@ -62,8 +62,10 @@ function getOutputChannel(): vscode.OutputChannel { function showError() { vscode.window.showWarningMessage(localize('gulpTaskDetectError', 'Problem finding gulp tasks. See the output for more information.'), - localize('gulpShowOutput', 'Go to output')).then(() => { - _channel.show(true); + localize('gulpShowOutput', 'Go to output')).then((choice) => { + if (choice !== undefined) { + _channel.show(true); + } }); } @@ -156,8 +158,13 @@ class FolderDetector { try { let { stdout, stderr } = await exec(commandLine, { cwd: rootPath }); if (stderr && stderr.length > 0) { - getOutputChannel().appendLine(stderr); - showError(); + // Filter out "No license field" + const errors = stderr.split('\n'); + errors.pop(); // The last line is empty. + if (!errors.every(value => value.indexOf('No license field') >= 0)) { + getOutputChannel().appendLine(stderr); + showError(); + } } let result: vscode.Task[] = []; if (stdout) { diff --git a/extensions/html-language-features/package.json b/extensions/html-language-features/package.json index c19eec0cf34..557fe83ca86 100644 --- a/extensions/html-language-features/package.json +++ b/extensions/html-language-features/package.json @@ -188,6 +188,10 @@ { "fileMatch": "*.html-data.json", "url": "https://raw.githubusercontent.com/Microsoft/vscode-html-languageservice/master/docs/customData.schema.json" + }, + { + "fileMatch": "package.json", + "url": "./schemas/package.schema.json" } ] }, diff --git a/extensions/html-language-features/schemas/package.schema.json b/extensions/html-language-features/schemas/package.schema.json new file mode 100644 index 00000000000..aaf9588221e --- /dev/null +++ b/extensions/html-language-features/schemas/package.schema.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "HTML contributions to package.json", + "type": "object", + "properties": { + "contributes": { + "type": "object", + "properties": { + "html.customData": { + "type": "array", + "markdownDescription": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/Microsoft/vscode-html-languageservice/blob/master/docs/customData.md).\n\nVS Code loads custom data on startup to enhance its HTML support for the custom HTML tags, attributes and attribute values you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.", + "items": { + "type": "string", + "description": "Relative path to a HTML custom data file" + } + } + } + } + } +} 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/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/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/vscode-test-resolver/src/extension.ts b/extensions/vscode-test-resolver/src/extension.ts index 6ac9f34c186..64734212d79 100644 --- a/extensions/vscode-test-resolver/src/extension.ts +++ b/extensions/vscode-test-resolver/src/extension.ts @@ -78,21 +78,26 @@ export function activate(context: vscode.ExtensionContext) { } const { updateUrl, commit, quality, serverDataFolderName, dataFolderName } = getProductConfiguration(); - const serverCommand = process.platform === 'win32' ? 'server.bat' : 'server.sh'; const commandArgs = ['--port=0', '--disable-telemetry']; const env = getNewEnv(); const remoteDataDir = process.env['TESTRESOLVER_DATA_FOLDER'] || path.join(os.homedir(), serverDataFolderName || `${dataFolderName}-testresolver`); env['VSCODE_AGENT_FOLDER'] = remoteDataDir; outputChannel.appendLine(`Using data folder at ${remoteDataDir}`); - if (!commit || env['TEST_RESOLVER_USE_SERVER_FROM_SOURCES']) { // dev mode + if (!commit) { // dev mode + const serverCommand = process.platform === 'win32' ? 'server.bat' : 'server.sh'; const vscodePath = path.resolve(path.join(context.extensionPath, '..', '..')); const serverCommandPath = path.join(vscodePath, 'resources', 'server', 'bin-dev', serverCommand); extHostProcess = cp.spawn(serverCommandPath, commandArgs, { env, cwd: vscodePath }); } else { - const serverBin = path.join(remoteDataDir, 'bin'); - progress.report({ message: 'Installing VSCode Server' }); - const serverLocation = await downloadAndUnzipVSCodeServer(updateUrl, commit, quality, serverBin); + const serverCommand = process.platform === 'win32' ? 'server.cmd' : 'server.sh'; + let serverLocation = env['VSCODE_REMOTE_SERVER_PATH']; // support environment variable to specify location of server on disk + if (!serverLocation) { + const serverBin = path.join(remoteDataDir, 'bin'); + progress.report({ message: 'Installing VSCode Server' }); + serverLocation = await downloadAndUnzipVSCodeServer(updateUrl, commit, quality, serverBin); + } + outputChannel.appendLine(`Using server build at ${serverLocation}`); extHostProcess = cp.spawn(path.join(serverLocation, serverCommand), commandArgs, { env, cwd: serverLocation }); diff --git a/package.json b/package.json index 36e90f66160..4a679ae9b91 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.39.0", - "distro": "323c0a11187dcde94de3a5d913cd44437e85369a", + "distro": "8516b3c6e37976c7f4a183ec1196a939f0ff11bf", "author": { "name": "Microsoft Corporation" }, @@ -52,7 +52,7 @@ "vscode-ripgrep": "^1.5.6", "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": "2.0.7", + "gulp-tsb": "4.0.1", "gulp-tslint": "^8.1.3", "gulp-untar": "^0.0.7", "gulp-vinyl-zip": "^2.1.2", @@ -120,7 +120,6 @@ "optimist": "0.3.5", "p-all": "^1.0.0", "pump": "^1.0.1", - "puppeteer": "^1.19.0", "queue": "3.0.6", "rcedit": "^1.1.0", "rimraf": "^2.2.8", diff --git a/remote/package.json b/remote/package.json index bb43760e610..8463c3e9148 100644 --- a/remote/package.json +++ b/remote/package.json @@ -21,7 +21,7 @@ "vscode-proxy-agent": "0.4.0", "vscode-ripgrep": "^1.5.6", "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..9bc2cb3a7da 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -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/win32/bin/code.sh b/resources/win32/bin/code.sh index 745f2adb7aa..f925851fb95 100644 --- a/resources/win32/bin/code.sh +++ b/resources/win32/bin/code.sh @@ -26,7 +26,7 @@ if grep -qi Microsoft /proc/version; then # use the Remote WSL extension if installed WSL_EXT_ID="ms-vscode-remote.remote-wsl" - if [ $WSL_BUILD -ge 41955 ]; then + if [ $WSL_BUILD -ge 41955 -a $WSL_BUILD -lt 41959 ]; then # WSL2 in workaround for https://github.com/microsoft/WSL/issues/4337 CWD="$(pwd)" cd "$VSCODE_PATH" diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index 280bc476ebe..d557a24edaa 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -5,11 +5,14 @@ pushd %~dp0\.. set VSCODEUSERDATADIR=%TMP%\vscodeuserfolder-%RANDOM%-%TIME:~6,5% +:: Figure out which Electron to use for running tests if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" ( - :: code.bat makes sure Test Extensions are compiled + :: Run out of sources: no need to compile as code.sh takes care of it set INTEGRATION_TEST_ELECTRON_PATH=.\scripts\code.bat + + echo "Running integration tests out of sources." ) else ( - :: Compile Test Extensions + :: Run from a built: need to compile all test extensions call yarn gulp compile-extension:vscode-api-tests call yarn gulp compile-extension:vscode-colorize-tests call yarn gulp compile-extension:markdown-language-features @@ -18,7 +21,7 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" ( call yarn gulp compile-extension:html-language-features-server call yarn gulp compile-extension:json-language-features-server - echo "Using %INTEGRATION_TEST_ELECTRON_PATH% as Electron path" + echo "Running integration tests with '%INTEGRATION_TEST_ELECTRON_PATH%' as build." ) :: Integration & performance tests in AMD diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 0bcbcee72f7..0d236609708 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -15,10 +15,12 @@ cd $ROOT # Figure out which Electron to use for running tests if [ -z "$INTEGRATION_TEST_ELECTRON_PATH" ] then - # code.sh makes sure Test Extensions are compiled + # Run out of sources: no need to compile as code.sh takes care of it INTEGRATION_TEST_ELECTRON_PATH="./scripts/code.sh" + + echo "Running integration tests out of sources." else - # Compile Test Extensions + # Run from a built: need to compile all test extensions yarn gulp compile-extension:vscode-api-tests yarn gulp compile-extension:vscode-colorize-tests yarn gulp compile-extension:markdown-language-features @@ -27,7 +29,7 @@ else yarn gulp compile-extension:html-language-features-server yarn gulp compile-extension:json-language-features-server - echo "Using $INTEGRATION_TEST_ELECTRON_PATH as Electron path" + echo "Running integration tests with '$INTEGRATION_TEST_ELECTRON_PATH' as build." fi # Integration tests in AMD diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index 85548f51965..72403b1e413 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -34,7 +34,7 @@ exports.load = function (modulePaths, resultCallback, options) { * // configuration: IWindowConfiguration * @type {{ * zoomLevel?: number, - * extensionDevelopmentPath?: string | string[], + * extensionDevelopmentPath?: string[], * extensionTestsPath?: string, * userEnv?: { [key: string]: string | undefined }, * appRoot?: string, diff --git a/src/buildfile.js b/src/buildfile.js index 684954a3219..2df9bf24e73 100644 --- a/src/buildfile.js +++ b/src/buildfile.js @@ -15,14 +15,6 @@ exports.base = [{ dest: 'vs/base/worker/workerMain.js' }]; -exports.serviceWorker = [{ - name: 'vs/workbench/contrib/resources/browser/resourceServiceWorker', - // include: ['vs/editor/common/services/editorSimpleWorker'], - prepend: ['vs/loader.js'], - append: ['vs/workbench/contrib/resources/browser/resourceServiceWorkerMain'], - dest: 'vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.js' -}]; - exports.workerExtensionHost = [entrypoint('vs/workbench/services/extensions/worker/extensionHostWorker')]; exports.workbenchDesktop = require('./vs/workbench/buildfile.desktop').collectModules(); diff --git a/src/tsconfig.json b/src/tsconfig.json index dcff5cff53f..8917d57336d 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -24,6 +24,9 @@ "./vs" ], "exclude": [ - "./typings/require-monaco.d.ts" + "./typings/require-monaco.d.ts", + "./typings/xterm.d.ts", + "./typings/xterm-addon-search.d.ts", + "./typings/xterm-addon-web-links.d.ts" ] } 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/dialog/dialog.ts b/src/vs/base/browser/ui/dialog/dialog.ts index a15f94dab8c..b3c43c0794c 100644 --- a/src/vs/base/browser/ui/dialog/dialog.ts +++ b/src/vs/base/browser/ui/dialog/dialog.ts @@ -92,8 +92,6 @@ export class Dialog extends Disposable { checkboxMessageElement.innerText = this.options.checkboxLabel; } - - const toolbarRowElement = this.element.appendChild($('.dialog-toolbar-row')); this.toolbarContainer = toolbarRowElement.appendChild($('.dialog-toolbar')); } diff --git a/src/vs/base/browser/ui/inputbox/inputBox.css b/src/vs/base/browser/ui/inputbox/inputBox.css index d13e1f2e535..ae4cd429a07 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.css +++ b/src/vs/base/browser/ui/inputbox/inputBox.css @@ -64,6 +64,10 @@ outline: none; } +.monaco-inputbox > .wrapper > textarea.input.empty { + white-space: nowrap; +} + .monaco-inputbox > .wrapper > textarea.input::-webkit-scrollbar { display: none; } diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index 48026fe503b..a326d0211b4 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -159,7 +159,7 @@ export class InputBox extends Widget { let tagName = this.options.flexibleHeight ? 'textarea' : 'input'; let wrapper = dom.append(this.element, $('.wrapper')); - this.input = dom.append(wrapper, $(tagName + '.input')); + this.input = dom.append(wrapper, $(tagName + '.input.empty')); this.input.setAttribute('autocorrect', 'off'); this.input.setAttribute('autocapitalize', 'off'); this.input.setAttribute('spellcheck', 'false'); @@ -240,6 +240,7 @@ export class InputBox extends Widget { } public setPlaceHolder(placeHolder: string): void { + this.placeholder = placeHolder; this.input.setAttribute('placeholder', placeHolder); this.input.title = placeHolder; } @@ -506,6 +507,7 @@ export class InputBox extends Widget { this.validate(); this.updateMirror(); + dom.toggleClass(this.input, 'empty', !this.value); if (this.state === 'open' && this.contextViewProvider) { this.contextViewProvider.layout(); @@ -517,7 +519,7 @@ export class InputBox extends Widget { return; } - const value = this.value || this.placeholder; + const value = this.value; const lastCharCode = value.charCodeAt(value.length - 1); const suffix = lastCharCode === 10 ? ' ' : ''; const mirrorTextContent = value + suffix; 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 64ad6e37f6f..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?81972c7f658ef56eeefe672e514d35a3") format("truetype"), -url("./octicons2.svg?81972c7f658ef56eeefe672e514d35a3#octicons2") format("svg"); + src: url("./octicons2.ttf?04609cb7b40cfe676d00e166656be7e8") format("truetype"), +url("./octicons2.svg?04609cb7b40cfe676d00e166656be7e8#octicons2") format("svg"); } .octicon, .mega-octicon { @@ -247,5 +247,6 @@ body[data-octicons-update="enabled"] .octicon-warning:before { content: "\f02d" body[data-octicons-update="enabled"] .octicon-controls:before { content: "\26ad" } body[data-octicons-update="enabled"] .octicon-event:before { content: "\26ae" } body[data-octicons-update="enabled"] .octicon-record-keys:before { content: "\26af" } -body[data-octicons-update="enabled"] .octicon-archive:before { content: "\f101" } -body[data-octicons-update="enabled"] .octicon-arrow-both:before { content: "\f102" } +body[data-octicons-update="enabled"] .octicon-Vector:before { content: "\f101" } +body[data-octicons-update="enabled"] .octicon-archive:before { content: "\f102" } +body[data-octicons-update="enabled"] .octicon-arrow-both:before { content: "\f103" } diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.svg b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.svg index f80a5eab7fb..e25c9f56e82 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.svg +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.svg @@ -7,14 +7,17 @@ units-per-em="1000" ascent="820" descent="180" /> + + horiz-adv-x="1000" d=" M837.5 157.5C818.75 207.5018750000001 812.5 257.5018750000001 812.5 307.501875V432.501875C812.5 513.751875 787.5 588.751875 731.25 645.0018749999999C681.25 707.501875 606.25 745.001875 531.25 751.251875C487.5 757.5019374999999 443.75 757.5019374999999 400 738.751875C356.25 720.001875 318.75 707.501875 287.5 676.2518749999999C256.25 645.0018749999999 231.25 613.7518749999999 212.5 570.001875C193.75 532.5018749999999 187.5 488.751875 187.5 445.001875V307.501875C187.5 257.5018750000001 175 207.5018750000001 162.5 157.5L125 51.25L156.25 7.5H375C375 -23.75 387.5 -55 412.5 -80C431.25 -105 462.5 -117.5 500 -117.5C537.5 -117.5 562.5 -105 587.5 -80C612.5 -55 625 -23.75 625 7.5H843.75L875 51.25L837.5 157.5zM543.75 -36.25C531.25 -48.75 512.5 -55 500 -55C487.5 -55 468.75 -48.75 456.25 -36.25C443.75 -23.75 437.5 -11.25 437.5 7.5H500H562.5C562.5 -11.25 556.25 -23.75 543.75 -36.25zM587.5 70H562.5H437.5H412.5H200L225 138.75C237.5 195.0018750000001 250 251.251875 250 307.501875V445.001875C250 482.501875 256.25 513.751875 268.75 545.001875C281.25 576.2518749999999 306.25 607.5018749999999 331.25 626.251875C356.25 651.251875 387.5 670.0018749999999 418.75 676.2518749999999C456.25 695.001875 487.5 695.001875 525 695.001875C587.5 688.751875 643.75 657.501875 687.5 607.5018749999999C731.25 557.5018749999999 750 495.001875 750 432.501875V307.501875C750 251.251875 756.25 195.0018750000001 775 138.75L800 70H587.5z" /> @@ -210,7 +213,7 @@ horiz-adv-x="1000" d=" M660.625 748.75L865.625 542.5L875 520V-86.25L843.75 -117.5H156.25L125 -86.25V726.25L156.25 757.5H638.75L660.625 748.75zM625 507.5H812.5L625 695V507.5zM187.5 695V-55H812.5V445H593.75L562.5 476.25V695H187.5zM687.5 382.5H312.5V320H687.5V382.5zM312.5 257.5H687.5V195H312.5V257.5zM687.5 132.5H312.5V70H687.5V132.5z" /> + horiz-adv-x="1000" d=" M570.625 -117.5L537.5 -69.375C555.5625 -45.7437500000001 563.8225 -16.05625 560.563125 13.50625C557.30375 43.075 542.77625 70.24375 520 89.375C481.715 121.36875 455.48 165.4625 445.625 214.375C348.125 75 398.75 -1.875 445.625 -70L411.25 -117.5C345.975 -105.2 287.3575 -69.6937499999999 246.228125 -17.53125C205.09875 34.625 184.238125 99.90625 187.5 166.25C187.5 166.25 174.375 301.25 330 433.125C330 433.125 506.25 596.25 445 716.875L489.375 757.5C557.074375 710.03 608.86625 643.2275 637.9749999999999 565.835C667.0749999999999 488.443125 672.1437500000001 404.0675 652.5 323.75C667.3187499999999 338.21125 679.20625 355.401875 687.5 374.375L741.875 378.75C746.25 371.25 856.875 195.625 797.5 47.5C776.35 3.3249999999999 744.5374999999999 -34.8875 704.93125 -63.6937499999999C665.325 -92.5 619.16625 -110.99375 570.625 -117.5zM445.625 316.875L500 292.5C497.10125 263.988125 500.776875 235.1906250000001 510.745 208.320625C520.7125 181.4500000000001 536.7075 157.225 557.5 137.5C584.289375 117.9812499999999 604.58 90.85 615.728125 59.6374999999999C626.875 28.4187499999999 628.3625000000001 -5.425 620 -37.5C645.83125 -28.45 669.56875 -14.2625 689.7624999999999 4.2125C709.95625 22.69375 726.1999999999999 45.06875 737.5 70C758.71875 146.0875 749.53125 227.4400000000001 711.875 296.875C700.0375 277.6756250000001 682.84375 262.3575 662.4124999999999 252.806875C641.9749999999999 243.2568749999999 619.1975 239.89125 596.875 243.125L575 285.625C602.376875 344.8275 611.70125 410.7850000000001 601.808125 475.25625C591.915 539.728125 563.2437500000001 599.855 519.375 648.125C510.625 515.625 375 393.125 370.625 386.25C241.25 276.25 250 174.375 250 170C247.559375 131.4 255.48625 92.85 272.959375 58.34375C290.4325 23.8312500000001 316.815625 -5.36875 349.375 -26.25C312.5 61.25 312.5 166.25 447.5 316.875H445.625z" /> @@ -228,7 +231,7 @@ horiz-adv-x="1000" d=" M843.75 570H743.75C750 595 750 620 750 645C743.75 663.75 737.5 682.5 725 701.25C712.5 720 700 732.5 681.25 738.75C662.5 745 643.75 757.5 625 757.5C606.25 757.5 587.5 757.5 568.75 745C525 732.5 493.75 701.25 468.75 663.75C443.75 701.25 412.5 732.5 368.75 745C350 751.25 331.25 757.5 312.5 757.5C293.75 757.5 275 751.25 256.25 738.75C237.5 732.5 225 720 212.5 701.25C200 688.75 193.75 663.75 187.5 645C187.5 620 187.5 595 193.75 570H93.75L62.5 538.75V-23.75L93.75 -55H843.75L875 -23.75V538.75L843.75 570zM437.5 7.5H125V507.5H437.5V7.5zM437.5 570H250C250 576.25 250 576.25 250 582.5C243.75 601.25 243.75 613.75 243.75 632.5C250 645 250 657.5 262.5 663.75C268.75 676.25 281.25 682.5 293.75 688.75C300 695 312.5 695 325 695C337.5 695 350 695 362.5 688.75C381.25 682.5 400 670 412.5 651.25C425 632.5 437.5 613.75 437.5 588.75V570zM500 588.75C500 613.75 512.5 632.5 525 651.25C537.5 670 556.25 682.5 575 688.75C587.5 695 600 695 612.5 695C625 695 637.5 695 650 688.75C662.5 682.5 668.75 676.25 681.25 663.75C687.5 657.5 687.5 645 693.75 632.5C693.75 613.75 693.75 601.25 687.5 582.5C687.5 576.25 687.5 576.25 681.25 570H500V588.75zM812.5 7.5H500V507.5H812.5V7.5z" /> + horiz-adv-x="1000" d=" M187.5 -55H437.5V-111.875L443.126875 -117.5H156.25L125 -86.25V726.25L156.25 757.5H638.75L660.625 748.749375L865.625 542.5037500000001L875 519.996875V361.251875C858.8187499999999 385.2593750000001 837.4625 405.330625 812.5 419.9987500000001V445H593.75L562.5 476.25V695H187.5V-55zM812.5 507.5L625 695V507.5H812.5zM843.75 257.5V195H906.25L937.5 163.75V-86.25L906.25 -117.5H531.25L500 -86.25V163.75L531.25 195H593.75V257.5C593.75 290.651875 606.92125 322.444375 630.3625000000001 345.88625C653.80625 369.32875 685.6 382.5 718.75 382.5C751.9 382.5 783.69375 369.32875 807.1374999999999 345.88625C830.5812500000001 322.444375 843.75 290.651875 843.75 257.5zM674.55625 301.696875C662.8375 289.97625 656.25 274.07625 656.25 257.5V195H781.25V257.5C781.25 274.07625 774.6625 289.97625 762.94375 301.696875C751.225 313.4181250000001 735.325 320 718.75 320C702.175 320 686.275 313.4181250000001 674.55625 301.696875zM562.5 132.5V-55H875V132.5H562.5z" /> @@ -237,16 +240,16 @@ horiz-adv-x="1000" d=" M875.28125 477.43C875.425 506.336875 867.51875 534.713125 852.4562500000001 559.3812499999999C837.3812499999999 584.049375 815.74375 604.035625 789.9562500000001 617.10125C764.1687499999999 630.166875 735.2562499999999 635.795625 706.45625 633.358125C677.64375 630.9200000000001 650.09375 620.51125 626.86875 603.2975C603.645625 586.084375 585.671875 562.7462499999999 574.96375 535.89625C564.255625 509.045625 561.2287500000001 479.744375 566.2318750000001 451.273125C571.235 422.8025 584.060625 396.28375 603.2800000000001 374.693125C622.5 353.09875 647.3562499999999 337.28375 675.0500000000001 329.016875C664.825 308.2325 649 290.706875 629.3625000000001 278.420625C609.724375 266.13125 587.05 259.5625 563.8818749999999 259.450625H439.3225C393.21 259.2887500000001 348.80875 241.9706250000001 314.7625 210.8718749999999V511.74625C352.5675 519.463125 386.160625 540.9425 409.029375 572.020625C431.8981250000001 603.098125 442.41125 641.56 438.5331250000001 679.9493749999999C434.655625 718.33875 416.66125 753.920625 388.039375 779.797C359.4175 805.673125 322.2075 820 283.6225 820C245.0375 820 207.8275 805.673125 179.205 779.797C150.583125 753.920625 132.589375 718.33875 128.71125 679.9493749999999C124.8325 641.56 135.3475 603.098125 158.215625 572.020625C181.08375 540.9425 214.6775 519.463125 252.4825 511.74625V131.8375C214.748125 124.625 180.95875 103.84375 157.488125 73.43125C134.0175 43.0124999999999 122.4875 5.0625 125.073125 -33.2687500000001C127.65875 -71.5999999999999 144.18125 -107.6624999999999 171.524375 -134.6437500000001C198.8675 -161.6312499999999 235.140625 -177.68125 273.5025 -179.7687499999999C311.8643750000001 -181.8499999999999 349.6625 -169.8249999999999 379.7675 -145.9562499999999C409.873125 -122.09375 430.2043750000001 -88.03125 436.9262500000001 -50.20625C443.64875 -12.3812499999999 436.299375 26.59375 416.260625 59.375C396.223125 92.15625 364.883125 116.46875 328.1525000000001 127.7312500000001C338.3975000000001 148.49375 354.226875 165.9875 373.8643750000001 178.25625C393.501875 190.525 416.16875 197.070625 439.3225 197.170625H563.8818749999999C602.744375 197.349375 640.58125 209.643125 672.1312499999999 232.338125C703.6750000000001 255.0325000000001 727.35625 286.99875 739.8875 323.7856250000001C777.2125 328.693125 811.5 346.96625 836.4 375.21625C861.2937499999999 403.46625 875.1062499999999 439.7775 875.28125 477.43zM190.2025 664.27C190.2025 682.746875 195.68125 700.808125 205.94625 716.17125C216.211875 731.53375 230.801875 743.5074999999999 247.871875 750.57875C264.9425000000001 757.649 283.72625 759.499125 301.8475 755.894375C319.969375 752.29 336.615 743.3925 349.68 730.3275C362.745625 717.2625 371.6425 700.6168749999999 375.2475 682.495C378.851875 664.3731250000001 377.001875 645.589375 369.93125 628.5193750000001C362.86 611.449375 350.88625 596.85875 335.52375 586.59375C320.160625 576.32875 302.099375 570.85 283.6225 570.85C258.8456250000001 570.85 235.084375 580.6925 217.564375 598.211875C200.045 615.73125 190.2025 639.493125 190.2025 664.27zM377.0425 -20.80625C377.0425 -39.2875 371.563125 -57.34375 361.2981250000001 -72.7062500000001C351.033125 -88.06875 336.443125 -100.04375 319.3725 -107.11875C302.3025 -114.1875 283.51875 -116.0375 265.3975000000001 -112.4375C247.275625 -108.8312499999999 230.63 -99.93125 217.564375 -86.86875C204.499375 -73.8000000000001 195.6025 -57.15625 191.9975 -39.0375C188.393125 -20.9124999999999 190.243125 -2.13125 197.31375 14.9375C204.384375 32.0125 216.35875 46.6 231.72125 56.86875C247.08375 67.13125 265.145625 72.6125000000001 283.6225 72.6125000000001C308.39875 72.6125000000001 332.160625 62.76875 349.68 45.25C367.2000000000001 27.725 377.0425 3.96875 377.0425 -20.80625zM719.58125 384.01C701.10625 384.01 683.0437499999999 389.490625 667.68125 399.754375C652.3187499999999 410.0193750000001 640.34375 424.61 633.275 441.68C626.20625 458.75 624.351875 477.53375 627.95625 495.655C631.5625 513.776875 640.45625 530.423125 653.525 543.488125C666.5875 556.5531249999999 683.2375000000001 565.45 701.35625 569.0550000000001C719.475 572.659375 738.2625 570.809375 755.33125 563.73875C772.40625 556.668125 786.9937500000001 544.694375 797.25625 529.33125C807.51875 513.96875 813 495.906875 813 477.43C813 452.65375 803.15625 428.8918750000001 785.6375 411.3725C768.11875 393.854375 744.35625 384.01 719.58125 384.01z" /> + horiz-adv-x="1000" d=" M686.175 507.5C652.6875 541.7506249999999 608.665625 563.76125 561.1725 570V820H498.6725V570C447.8575 562.346875 401.35875 537.05125 367.330625 498.543125C333.3025 460.035 313.916875 410.776875 312.5743750000001 359.405625C311.2325 308.035 328.02 257.8306250000001 359.99125 217.598125C391.9625 177.36875 437.076875 149.6687499999999 487.423125 139.375H498.6725V-110.625H561.1725V139.375C579.265 141.65625 596.941875 146.49375 613.6724999999999 153.75C653.7937499999999 170.0625 688.0125 198.18 711.8 234.375C735.75 270.284375 748.575 312.4575 748.675 355.6218750000001C748.61875 412.495625 726.16875 467.06375 686.175 507.5zM642.4250000000001 242.500625C613.02375 213.2731250000001 573.2525 196.87125 531.7975 196.8768750000001C500.914375 196.8562500000001 470.7175 205.983125 445.02125 223.114375C419.3243750000001 240.245 399.281875 264.60625 387.423125 293.1218750000001C378.4468750000001 314.4525 374.340625 337.51625 375.404375 360.634375C376.468125 383.7518750000001 382.6756250000001 406.341875 393.5718750000001 426.758125C404.46875 447.174375 419.7806250000001 464.91 438.395 478.660625C457.00875 492.411875 478.45625 501.833125 501.173125 506.24875C511.360625 507.17 521.61 507.17 531.7975 506.24875C553.2325000000001 506.709375 574.525625 502.6675 594.2975 494.3775C622.813125 482.518125 647.175 462.471875 664.30625 436.775625C681.4375 411.0793750000001 690.5687499999999 380.881875 690.55 349.9987500000001C689.81875 329.375 685.025 309.0975 676.44375 290.3293750000001C667.8625000000001 271.5606250000001 655.66875 254.67 640.55 240.62375L642.4250000000001 242.500625z" /> + horiz-adv-x="1000" d=" M829.55625 336.840625C800.15625 366.068125 760.38125 382.4700000000001 718.9250000000001 382.464375C688.0437499999999 382.485 657.85 373.350625 632.15 356.219375C606.454375 339.08875 586.411875 314.7275 574.5525 286.2118750000001C570.90625 277.3493749999999 568.183125 268.1375 566.4275 258.7156250000001C502.53125 265.7275000000001 442.93875 294.318125 397.4856250000001 339.770625C352.033125 385.223125 323.43875 444.8193750000001 316.4275 508.715625C325.84875 510.47125 335.0643750000001 513.194375 343.9275 516.84125C372.443125 528.7 396.8037500000001 548.739375 413.935 574.435625C431.065625 600.131875 440.196875 630.32875 440.17625 661.211875C440.636875 682.646875 436.59125 703.94 428.3012500000001 723.711875C420.50875 742.653125 409.0425 759.866125 394.56 774.3484375C380.0775 788.83075 362.8687500000001 800.3013125 343.9275 808.09325C324.1550000000001 816.38343125 302.8625 820.4254025 281.4275 819.9645975C250.544375 819.9851908125 220.346875 810.850375 194.650625 793.7195C168.954375 776.5885625 148.911875 752.2275 137.0525 723.711875C125.3025 695.1 122.23875 663.661875 128.240625 633.319375C134.2425 602.97625 149.043125 575.0725 170.80125 553.088125C192.708125 531.700625 220.2325 516.968125 250.1775 510.5925V191.8375000000001C230.268125 187.9500000000001 211.346875 180.0875 194.551875 168.7125C169.065625 151.3812499999999 149.10625 127.08125 137.0525 98.7125C125.123125 70.125 121.96 38.6437500000001 127.9625 8.25625C133.964375 -22.13125 148.86125 -50.05 170.763125 -71.95C192.665 -93.85 220.58375 -108.75 250.97125 -114.75C281.3581250000001 -120.75 312.844375 -117.59375 341.42875 -105.6625C369.944375 -93.8062500000001 394.305625 -73.75625 411.4362500000001 -48.0625C428.5668750000001 -22.36875 437.698125 7.83125 437.6775 38.7125C438.138125 60.15 434.0925 81.44375 425.8025 101.2125C418.010625 120.15625 406.54375 137.3625 392.06125 151.84375C377.579375 166.3250000000001 360.37 177.7937500000001 341.42875 185.5875C332.156875 189.4437499999999 322.525625 192.375 312.6775 194.3375V344.340625C344.968125 298.703125 387.865625 261.598125 437.6775 236.2168750000001C478.380625 215.3768749999999 522.745 202.6425000000001 568.3043749999999 198.718125C572.82375 176.05625 582.311875 154.675 596.086875 136.125C609.86125 117.5750000000001 627.58125 102.3125 647.9625 91.43125C668.34375 80.5562500000001 690.8874999999999 74.33125 713.96875 73.2125C737.05 72.09375 760.0875 76.1062499999999 781.4250000000001 84.9625C809.9437499999999 96.8249999999999 834.30625 116.86875 851.4375 142.5687499999999C868.56875 168.2625000000001 877.69375 198.459375 877.675 229.3425000000001C876.20625 270.06625 858.95 308.618125 829.55625 336.840625zM317.053125 125.5875C334.3062500000001 118.28125 349.06875 106.11875 359.5525 90.5875C371.56625 72.5562500000001 376.96125 50.9250000000001 374.8225 29.3625C372.684375 7.8 363.14375 -12.3625 347.8225 -27.6812500000001C332.500625 -43.00625 312.346875 -52.5437499999999 290.7850000000001 -54.6875C269.223125 -56.8249999999999 247.58375 -51.425 229.55125 -39.4125C214.02 -28.9250000000001 201.8625 -14.1625 194.551875 3.09375C187.615 20.125 185.8775 38.825 189.554375 56.84375C193.083125 75.09375 201.9925 91.8625 215.135625 105.00625C228.27875 118.15 245.054375 127.05625 263.30375 130.5875C281.32125 134.2625000000001 300.023125 132.5250000000001 317.053125 125.5875zM281.4275 569.964375C262.975 569.954375 244.92875 575.389375 229.55125 585.589375C214.02 596.073125 201.8625 610.839375 194.551875 628.093125C187.615 645.1231250000001 185.8775 663.8243749999999 189.554375 681.8418750000001C193.083125 700.09125 201.9925 716.863125 215.135625 730.00625C228.27875 743.149375 245.054375 752.05875 263.30375 755.5875C281.32125 759.2644375 300.023125 757.5274375 317.053125 750.590625C334.3062500000001 743.28 349.06875 731.118125 359.5525 715.586875C368.9362500000001 701.4612500000001 374.3125 685.056875 375.10875 668.1168749999999C375.905 651.176875 372.09375 634.339375 364.0768750000001 619.395625C356.059375 604.45125 344.13875 591.959375 329.584375 583.255C315.03 574.550625 298.38625 569.958125 281.4275 569.964375zM785.175 159.9625C769.8812499999999 144.65625 749.76875 135.1125000000001 728.2375 132.9437499999999C706.70625 130.78125 685.0875 136.13125 667.0500000000001 148.0875C651.5187500000001 158.5749999999999 639.3625 173.3375 632.05 190.59375C625.1125 207.623125 623.3775 226.3243749999999 627.05625 244.341875C630.58125 262.59125 639.49375 279.363125 652.6374999999999 292.50625C665.78125 305.6493750000001 682.55625 314.5587500000001 700.80625 318.0875000000001C718.8187499999999 321.764375 737.525 320.0275000000001 754.5500000000001 313.090625C771.80625 305.78 786.56875 293.618125 797.0500000000001 278.086875C809.0125 260.051875 814.3625 238.436875 812.19375 216.906875C810.03125 195.3762499999999 800.4875000000001 175.25625 785.175 159.9625z" /> + horiz-adv-x="1000" d=" M382.431875 149.96875L461.808125 70.5875H346.183125C321.31875 70.5875 297.4725 80.46875 279.89125 98.0500000000001C262.309375 115.63125 252.433125 139.4749999999999 252.433125 164.3375V508.09C262.280625 510.053125 271.9106250000001 512.985 281.1825 516.84125C309.6975 528.7 334.060625 548.739375 351.1912500000001 574.435625C368.3225 600.131875 377.45375 630.32875 377.433125 661.211875C377.89375 682.646875 373.848125 703.94 365.5575 723.711875C357.765625 742.653125 346.296875 759.866125 331.8150000000001 774.3484375C317.3325000000001 788.83075 300.123125 800.3013125 281.1825 808.09325C261.41 816.38343125 240.1175 820.4254025 218.6825 819.9645975C187.799375 819.9851908125 157.60375 810.850375 131.9075 793.7195C106.21125 776.5885625 86.166875 752.2275 74.3075 723.711875C62.5575 695.1 59.4916875 663.661875 65.49375 633.319375C71.495625 602.97625 86.3 575.0725 108.058125 553.088125C129.965 531.700625 157.4875 516.968125 187.4325 510.5925V163.7125C187.349375 143.175 191.335625 122.81875 199.15875 103.8250000000001C206.981875 84.83125 218.486875 67.56875 233.0125 53.04375C247.538125 38.51875 264.796875 27.0125 283.791875 19.1937499999999C302.78625 11.36875 323.14 7.38125 343.6825 7.4625H459.3075L379.933125 -71.9125L424.308125 -116.28125L557.433125 16.84375V60.5875L424.308125 193.7125L382.431875 149.96875zM221.183125 570.59C202.73 570.5799999999999 184.685625 576.015 169.30875 586.215C153.776875 596.69875 141.6175 611.465 134.306875 628.71875C127.37 645.74875 125.63125 664.45 129.3075 682.4675C132.836875 700.716875 141.745625 717.48875 154.889375 730.631875C168.0325 743.775 184.808125 752.684375 203.0575 756.213125C221.074375 759.8900625 239.778125 758.1530625 256.808125 751.21625C274.061875 743.905625 288.8243750000001 731.74375 299.308125 716.2125C308.691875 702.086875 314.0675 685.6825 314.864375 668.7425000000001C315.660625 651.8025 311.8475000000001 634.965 303.83 620.02125C295.813125 605.076875 283.8918750000001 592.585 269.3375000000001 583.880625C254.78375 575.17625 238.14125 570.58375 221.183125 570.59z M894.3125 149.9625000000001C872.575 171.58125 844.975 186.3499999999999 814.93125 192.4625V539.3375000000001C815.0187500000001 559.879375 811.03125 580.23375 803.20625 599.228125C795.3875 618.2225 783.875 635.48375 769.35 650.009375C754.8249999999999 664.535 737.56875 676.038125 718.5749999999999 683.8612499999999C699.5812500000001 691.684375 679.225 695.67 658.68125 695.5875H543.06L622.4325 774.9636875L578.0600000000001 819.33624375L444.933125 686.21125V642.46375L578.0600000000001 509.33875L622.4325 553.7112500000001L543.06 633.0875H658.68125C683.55 633.0875 707.3937500000001 623.210625 724.975 605.629375C742.55625 588.0475 752.43125 564.20125 752.43125 539.3375000000001V192.4625C732.525 188.5749999999999 713.60625 180.7125 696.80625 169.3375C671.3249999999999 152 651.3625 127.6999999999999 639.30625 99.3375C627.38125 70.75 624.2162500000001 39.2687500000001 630.21875 8.88125C636.21875 -21.50625 651.11875 -49.425 673.01875 -71.325C694.91875 -93.23125 722.8375 -108.125 753.225 -114.125C783.6125000000001 -120.13125 815.1 -116.96875 843.6875 -105.04375C872.1999999999999 -93.1812500000001 896.5625 -73.1375 913.69375 -47.4375C930.825 -21.74375 939.95625 8.45625 939.93125 39.3375C939.9375 80.7937500000001 923.5375 120.5625 894.3125 149.9625000000001zM849.93125 -26.91875C834.6375 -42.225 814.5250000000001 -51.76875 792.9937500000001 -53.9312500000001C771.4625000000001 -56.09375 749.84375 -50.7437500000001 731.80625 -38.7875C716.275 -28.3062500000001 704.11875 -13.5375 696.80625 3.71875C689.86875 20.74375 688.13125 39.45 691.8125 57.4625C695.3375000000001 75.7125 704.25 92.4875 717.3937500000001 105.63125C730.5374999999999 118.775 747.3125 127.68125 765.5625 131.2125C783.575 134.8874999999999 802.28125 133.1500000000001 819.30625 126.2125C836.5625 118.9000000000001 851.325 106.74375 861.80625 91.2125C873.76875 73.1750000000001 879.11875 51.5625 876.95 30.03125C874.7875 8.5 865.24375 -11.625 849.93125 -26.91875z" /> @@ -261,13 +264,13 @@ horiz-adv-x="1000" d=" M93.75 -55H937.5V7.5H125V820H62.5V-23.75L93.75 -55zM187.5 101.25V601.25L218.75 632.5H343.75L375 601.25V101.25L343.75 70H218.75L187.5 101.25zM312.5 132.5V570H250V132.5H312.5zM687.5 726.25V101.25L718.75 70H843.75L875 101.25V726.25L843.75 757.5H718.75L687.5 726.25zM812.5 695V132.5H750V695H812.5zM437.5 101.25V476.25L468.75 507.5H593.75L625 476.25V101.25L593.75 70H468.75L437.5 101.25zM562.5 132.5V445H500V132.5H562.5z" /> + horiz-adv-x="1000" d=" M930 521.24625C924.95625 540.984375 917.175 559.9200000000001 906.875 577.498125C896.9875000000001 595.78375 884.3312500000001 612.439375 869.375 626.875625C847.6875 648.4918749999999 822 665.681875 793.75 677.4962499999999C736.8875 700.834375 673.1125 700.834375 616.249375 677.4962499999999C589.5475 666.19375 565.016875 650.3325 543.75125 630.6212499999999L540.6268749999999 626.875625L500.000625 586.24875L459.374375 626.875625L456.25 630.6212499999999C434.984375 650.3325 410.45375 666.19375 383.75125 677.4962499999999C326.88625 700.834375 263.115 700.834375 206.25 677.4962499999999C177.99875 665.681875 152.31625 648.4918749999999 130.6275 626.875625C115.656875 612.294375 102.82125 595.669375 92.50125 577.498125C82.66125 559.770625 75.100625 540.869375 70 521.24625C64.70125 500.845 62.1788125 479.821875 62.500625 458.74625C62.533125 438.9262500000001 65.0525 419.1925 70 400C75.24 380.6225 82.795 361.945 92.50125 344.374375C102.98375 326.31125 115.803125 309.7075 130.6275 294.996875L500.000625 -74.38125L869.375 294.996875C884.19375 309.556875 896.8249999999999 326.190625 906.875 344.374375C917.05625 361.78875 924.8375 380.500625 930 400C934.95 419.1925 937.46875 438.9262500000001 937.5 458.74625C937.825 479.821875 935.3 500.845 930 521.24625zM867.5 419.3712500000001C863.8249999999999 405.395 858.3625000000001 391.95 851.25 379.37C843.825 366.411875 834.8 354.445625 824.375 343.74875L498.749375 18.75L173.126875 343.74875C162.515625 354.435 153.2775 366.39875 145.626875 379.37C138.426875 392.2025 132.761875 405.8400000000001 128.750625 419.996875C125.548125 434.151875 123.8725 448.613125 123.75125 463.125625C123.83625 478.053125 125.51125 492.92625 128.750625 507.498125C132.644375 521.6956250000001 138.315 535.346875 145.626875 548.125C153.123125 561.2 162.37625 573.183125 173.126875 583.7462499999999C189.183125 599.5875 208.0425 612.301875 228.74875 621.245C270.475 637.936875 317.024375 637.936875 358.75 621.245C379.323125 612.676875 398.01125 600.15 413.750625 584.371875L498.749375 498.7475L583.7525 584.371875C599.49125 600.15 618.175625 612.676875 638.75 621.245C680.475 637.936875 727.025 637.936875 768.75 621.245C789.45625 612.301875 808.31875 599.5875 824.375 583.7462499999999C835.26875 573.46 844.35 561.42125 851.25 548.125C858.3625000000001 535.545 863.8249999999999 522.1 867.5 508.12375C871.2562499999999 493.84375 873.14375 479.141875 873.125 464.376875C873.98125 449.275625 872.71875 434.1225 869.375 419.3712500000001H867.5z" /> + horiz-adv-x="1000" d=" M522.499375 734.375L920 371.875625L875.625 327.500625L812.5 384.743125V-23.125L781.25 -54.375H593.750625L562.500625 -23.125V195.6237500000001H437.500625V-23.125L406.250625 -54.375H218.750625L187.500625 -23.125L187.5 384.27125L125.000625 327.500625L80.625625 371.875625L477.499375 734.375H478.124375H521.874375H522.499375zM250.000625 441.0425V8.125H375.000625V226.8737500000001L406.250625 258.1237500000001H593.750625L625 226.8737500000001V8.125H750V441.419375L499.999375 668.125L250.000625 441.0425z" /> @@ -300,16 +303,16 @@ horiz-adv-x="1000" d=" M250 320C250 307.63875 246.334375 295.555 239.466875 285.276875C232.599375 274.99875 222.838125 266.988125 211.4175 262.2575C199.9975 257.526875 187.430625 256.289375 175.306875 258.700625C163.183125 261.1125000000001 152.046875 267.0650000000001 143.305625 275.805625C134.565 284.546875 128.6125 295.683125 126.20125 307.806875C123.789375 319.930625 125.026875 332.4975 129.7575 343.9175C134.488125 355.338125 142.49875 365.099375 152.776875 371.966875C163.055 378.834375 175.13875 382.5 187.5 382.5C204.07625 382.5 219.973125 375.915 231.694375 364.1943750000001C243.415 352.473125 250 336.57625 250 320z M562.5 320C562.5 307.63875 558.834375 295.555 551.966875 285.276875C545.099375 274.99875 535.338125 266.988125 523.9175 262.2575C512.4975000000001 257.526875 499.930625 256.289375 487.806875 258.700625C475.683125 261.1125000000001 464.546875 267.0650000000001 455.805625 275.805625C447.065 284.546875 441.1125 295.683125 438.70125 307.806875C436.289375 319.930625 437.526875 332.4975 442.2575000000001 343.9175C446.9881250000001 355.338125 454.99875 365.099375 465.276875 371.966875C475.555 378.834375 487.63875 382.5 500 382.5C516.57625 382.5 532.473125 375.915 544.194375 364.1943750000001C555.9150000000001 352.473125 562.5 336.57625 562.5 320z M875 320C875 307.63875 871.3375 295.555 864.46875 285.276875C857.6 274.99875 847.8375 266.988125 836.41875 262.2575C825 257.526875 812.4312500000001 256.289375 800.30625 258.700625C788.1812500000001 261.1125000000001 777.04375 267.0650000000001 768.30625 275.805625C759.5625 284.546875 753.6125000000001 295.683125 751.1999999999999 307.806875C748.7875 319.930625 750.0250000000001 332.4975 754.75625 343.9175C759.4875 355.338125 767.5 365.099375 777.775 371.966875C788.05625 378.834375 800.1374999999999 382.5 812.5 382.5C829.075 382.5 844.975 375.915 856.69375 364.1943750000001C868.4125 352.473125 875 336.57625 875 320z" /> + horiz-adv-x="1000" d=" M465.276875 -44.46875C475.555 -51.3375 487.63875 -55 500 -55C516.575625 -55 532.473125 -48.4125 544.19375 -36.69375C555.9150000000001 -24.975 562.5 -9.075 562.5 7.5C562.5 19.8625000000001 558.834375 31.94375 551.966875 42.225C545.09875 52.5 535.338125 60.5125000000001 523.9175 65.24375C512.4968749999999 69.9749999999999 499.930625 71.2125 487.806875 68.8000000000001C475.683125 66.3874999999999 464.54625 60.4375 455.805625 51.69375C447.065 42.95625 441.1125 31.8187499999999 438.700625 19.69375C436.289375 7.5687499999999 437.526875 -5 442.2575000000001 -16.41875C446.9875 -27.8375 454.99875 -37.6 465.276875 -44.46875zM500 257.5C487.638125 257.5 475.554375 261.165625 465.276875 268.0331250000001C454.99875 274.900625 446.9875 284.661875 442.2575000000001 296.0825C437.526875 307.5025 436.289375 320.069375 438.700625 332.193125C441.1125 344.3168750000001 447.065 355.453125 455.805625 364.1943750000001C464.54625 372.935 475.683125 378.8875 487.806875 381.299375C499.930625 383.710625 512.4968749999999 382.4731250000001 523.9175 377.7425C535.338125 373.011875 545.09875 365.00125 551.966875 354.7231250000001C558.834375 344.445 562.5 332.36125 562.5 320C562.5 303.4237500000001 555.9150000000001 287.526875 544.19375 275.805625C532.473125 264.0849999999999 516.575625 257.5 500 257.5zM500 570C487.63875 570 475.555 573.665625 465.276875 580.533125C454.99875 587.400625 446.9881250000001 597.161875 442.2575000000001 608.5825C437.526875 620.0025 436.289375 632.569375 438.70125 644.693125C441.1125 656.816875 447.065 667.95375 455.805625 676.694375C464.546875 685.435 475.683125 691.3875 487.806875 693.7993749999999C499.930625 696.210625 512.4975000000001 694.973125 523.9175 690.2425000000001C535.338125 685.511875 545.099375 677.50125 551.966875 667.223125C558.834375 656.9449999999999 562.5 644.8612499999999 562.5 632.5C562.5 615.92375 555.9150000000001 600.026875 544.194375 588.305625C532.473125 576.585 516.57625 570 500 570z" /> + horiz-adv-x="1000" d=" M709.4375 751.80875C763.99375 740.700625 814.0625 713.745625 853.375 674.316875C886.6125000000001 640.80125 911.03125 599.564375 924.44375 554.306875C937.85625 509.04125 939.85625 461.166875 930.25 414.948125C916.3375 351.578125 881.33125 294.815625 830.9499999999999 253.9375C780.56875 213.066875 717.80625 190.50625 652.9375 189.94375C625.56875 189.8937500000001 598.339375 193.88125 572.124375 201.76L522.125 143.1937499999999L498.43625 132.25625H437.5V38.50625L406.25 7.25625H312.5V-86.49375L281.25 -117.74375H93.75L62.5 -86.49375V57.69375L71.625 79.75625L382.5 390.5725C373.67625 418.984375 369.4575 448.631875 369.99875 478.38625C370.765625 534.050625 387.931875 588.265 419.3575 634.224375C450.77875 680.18375 495.06375 715.859375 546.66125 736.77125C598.25875 757.6910625 654.88125 762.9171875 709.4375 751.80875zM791.83125 301.8350000000001C831.0875 333.6262500000001 858.38125 377.808125 869.25 427.1325L869.5 426.819375C877.21875 462.88375 875.80625 500.305625 865.39375 535.6912500000001C854.975 571.07625 835.89375 603.295 809.8625000000001 629.425625C783.8375 655.55625 751.69375 674.775 716.35625 685.33375C681.0125 695.893125 643.59375 697.456875 607.498125 689.88125C558.8 679.0699999999999 515.11375 652.283125 483.4025 613.77C451.686875 575.264375 433.7693750000001 527.253125 432.49875 477.379375C431.82375 448.9525000000001 436.905 420.678125 447.4375 394.2575L440.563125 360.3825L125 44.75625V-55.24375H250V38.50625L281.25 69.75625H375V163.50625L406.25 194.75625H484.0625L538.810625 258.255625L573.875625 267.00625C599.1475 257.134375 626.05 252.083125 653.1875 252.1368750000001C703.7 252.518125 752.58125 270.0431250000001 791.83125 301.8350000000001zM739.46875 472.535C746.33125 482.811875 750 494.896875 750 507.25625C750 523.835 743.41875 539.7268750000001 731.69375 551.453125C719.975 563.171875 704.075 569.75625 687.5 569.75625C675.1374999999999 569.75625 663.05625 566.094375 652.78125 559.22C642.5 552.35375 634.4875 542.595625 629.75625 531.174375C625.0250000000001 519.753125 623.7906250000001 507.1875 626.1999999999999 495.064375C628.6125000000001 482.94125 634.5625 471.8025 643.30625 463.059375C652.04375 454.32375 663.1812500000001 448.365 675.30625 445.95375C687.4312500000001 443.543125 700 444.786875 711.41875 449.516875C722.8375 454.246875 732.6 462.258125 739.46875 472.535z" /> + horiz-adv-x="1000" d=" M914.375 382.5L812.5 632.5H875V695H562.5V757.5H500V695H187.5V632.5H250L148.75 382.5H125V320H134.375C144.149375 288.880625 163.9225 261.8575 190.625 243.125C216.978125 224.015 248.6975 213.725 281.25 213.725C313.8025 213.725 345.521875 224.015 371.875 243.125C398.5850000000001 261.989375 418.52375 288.9400000000001 428.75 320H437.5V382.5H409.375L305 632.5H500V132.5H375L350.625 121.25L225.625 -35.625L250 -86.25H812.5L836.875 -35.625L711.875 121.25L687.5 132.5H562.5V632.5H758.125L653.75 382.5H625V320H634.375C644.5999999999999 289.035 664.325 262.0825000000001 690.75 242.9775C717.175 223.8725 748.95625 213.58875 781.5625 213.58875C814.16875 213.58875 845.9499999999999 223.8725 872.375 242.9775C898.8000000000001 262.0825000000001 918.525 289.035 928.75 320H937.5V382.5H914.375zM326.25 288.125C312.466875 280.4968750000001 297.0025 276.41625 281.25 276.25C265.68375 276.3318750000001 250.4012500000001 280.42125 236.875 288.125C223.081875 295.685625 211.46125 306.66125 203.125 320H359.375C351.109375 306.823125 339.734375 295.8781250000001 326.25 288.125zM341.875 382.5H216.875L279.375 532.5L341.875 382.5zM672.5 70L750 -23.75H312.5L390 70H672.5zM783.75 531.25L846.25 381.25H721.25L783.75 531.25zM826.25 286.875C812.5875 278.955625 797.04375 274.854375 781.25 275C765.64375 274.7781250000001 750.28125 278.88875 736.875 286.875C723.0625 294.9593749999999 711.46875 306.3400000000001 703.125 320H859.375C851.625 306.09375 840.15625 294.6225 826.25 286.875z" /> @@ -327,7 +330,7 @@ horiz-adv-x="1000" d=" M125.015 632.5H62.515V570H125.015V632.5zM125.015 445H62.515V382.5H125.015V445zM62.515 257.5H125.015V195H62.515V257.5zM125.015 70H62.515V7.5H125.015V70zM250.015 632.5H937.5125V570H250.015V632.5zM937.5125 445H250.015V382.5H937.5125V445zM250.015 257.5H937.5125V195H250.015V257.5zM937.5125 70H250.015V7.5H937.5125V70z" /> + horiz-adv-x="1000" d=" M677.04375 652.025625C630.3562499999999 698.714375 567.29375 725.344375 501.27125 726.25H498.77125C432.7487500000001 725.344375 369.685 698.714375 322.995625 652.025625C276.30625 605.3362500000001 249.676875 542.2725 248.77125 476.25C247.931875 429.3575 261.1212500000001 383.283125 286.64625 343.9375L483.361875 -55H516.680625L713.3937500000001 343.9375C738.9187499999999 383.283125 752.1125 429.3575 751.2687500000001 476.25C750.36875 542.2725 723.7375000000001 605.3362500000001 677.04375 652.025625zM495.27125 663.75L500.39625 663.125L505.02125 663.75C554.119375 661.611875 600.5325 640.745625 634.71875 605.441875C668.90625 570.138125 688.275 523.0787499999999 688.83125 473.9375C689.30625 439.0612500000001 679.125 404.8712500000001 659.64375 375.9375L658.39375 373.8125L657.3312500000001 371.625L500.02125 52.5625L342.70875 371.3125L341.64625 373.75L340.39625 375.875C320.9175 404.80875 310.734375 438.99875 311.20875 473.875C311.741875 523.073125 331.1287500000001 570.191875 365.374375 605.51875C399.62 640.8456249999999 446.1131250000001 661.688125 495.27125 663.75zM533.4875 528.2168750000001C523.209375 535.084375 511.125625 538.75 498.764375 538.75C482.188125 538.75 466.29125 532.165 454.57 520.444375C442.84875 508.723125 436.264375 492.82625 436.264375 476.25C436.264375 463.88875 439.929375 451.805 446.7975 441.526875C453.665 431.2487500000001 463.42625 423.2381250000001 474.84625 418.5075000000001C486.266875 413.776875 498.83375 412.539375 510.9575 414.950625C523.0812500000001 417.3625 534.2175 423.315 542.958125 432.055625C551.69875 440.796875 557.651875 451.933125 560.063125 464.056875C562.4749999999999 476.180625 561.2368749999999 488.7475 556.5068749999999 500.1675C551.77625 511.588125 543.7650000000001 521.349375 533.4875 528.2168750000001zM429.318125 580.18375C449.8737500000001 593.91875 474.04125 601.25 498.764375 601.25C531.91625 601.25 563.710625 588.080625 587.1524999999999 564.638125C610.594375 541.19625 623.76375 509.401875 623.76375 476.25C623.76375 451.5275 616.433125 427.36 602.698125 406.8037500000001C588.9625000000001 386.2475 569.4399999999999 370.22625 546.599375 360.765C523.7587500000001 351.304375 498.625625 348.82875 474.3775 353.651875C450.13 358.475 427.8575 370.38 410.375625 387.861875C392.8943750000001 405.3431250000001 380.989375 427.6162500000001 376.165625 451.86375C371.3425000000001 476.11125 373.818125 501.244375 383.279375 524.0856249999999C392.74 546.92625 408.761875 566.44875 429.318125 580.18375z" /> @@ -336,7 +339,7 @@ horiz-adv-x="1000" d=" M515.625 721.878125H483.75L62.5 472.503125V-23.74375L93.75 -54.99375H906.25L937.5 -23.74375V472.503125L515.625 721.878125zM500 658.753125L851.875 451.253125L766.25 351.878125H233.75L151.875 451.253125L500 658.753125zM875 7.50625H125V387.503125L194.375 301.253125L218.75 289.378125H781.25L805.625 301.253125L875 387.503125V7.50625z" /> + horiz-adv-x="1000" d=" M62.5 601.25L93.75 632.5H906.25L937.5 601.25V584.435V38.75L906.25 7.5H93.75L62.5 38.75V584.435V601.25zM125 536.568125V70H875V536.499375L519.375 263.74875H481.250625L125 536.568125zM814.375 570H185.625L500 328.1862500000001L814.375 570z" /> @@ -357,7 +360,7 @@ horiz-adv-x="1000" d=" M535.625 757.5L923.125 507.5L937.5 483.75V-91.25L890 -117.5L500 132.5L110 -117.5L62.5 -91.25V483.75L76.875 507.5L464.375 757.5H535.625zM531.875 186.875L875 -34.375V466.875L531.875 685.625V507.5H469.375V686.875L125 465.625V-34.375L469.375 188.125V186.875H531.875zM588.125 485.62375L632.5 529.37375L786.875 374.37375V329.99875L633.125 176.25L589.375 219.998125L688.75 319.9987500000001H559.375H442.5H313.75L412.5 219.998125L368.75 176.25L215 329.99875V374.37375L370 529.37375L413.75 485.62375L311.25 382.49875H442.5H559.375H691.25L588.125 485.62375z" /> + horiz-adv-x="1000" d=" M937.5 466.25L511.25 632.5H488.75L62.5 466.25V70H125V382.5L269.375 326.25C237.483125 280.83375 220.253125 226.745 220 171.25C219.3825 164.3874999999999 219.3825 157.4875000000001 220 150.625V143.75L237.5 118.75L486.25 7.5H511.8749999999999L758.125 120.625L775.625 145.625V153.125C775.625 159.375 775.625 166.25 775.625 173.125C775.26875 228.315 758.28125 282.1162500000001 726.875 327.5L937.5 409.375V466.25zM717.5 173.75V169.375L500 70L281.25 170C280.9575000000001 171.2312500000001 280.9575000000001 172.51875 281.25 173.75C281.5900000000001 221.9206250000001 298.0975000000001 268.581875 328.125 306.25L489.375 243.75H511.8749999999999L671.875 306.25C701.625 268.5125 717.7125 221.805 717.5 173.75zM500 304.375L157.5 437.5L500 570L842.5 436.25L500 304.375z" /> @@ -372,22 +375,22 @@ 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" /> + horiz-adv-x="1000" d=" M908.7875 81.80625L837.5375 276.8143750000001V280.560625L530.6625 587.4375V664.936875C530.555 677.334375 528.2275 689.60875 523.78875 701.184375C518.92625 712.565 511.8287500000001 722.85375 502.918125 731.4425C494.0075 740.03125 483.464375 746.7475 471.9125 751.1875C460.398125 755.779375 448.04875 757.907 435.66125 757.435625C423.433125 757.6960625 411.289375 755.35375 400.035625 750.561875C388.8125 745.943125 378.615 739.146875 370.0331250000001 730.565C361.45125 721.983125 354.655 711.7825 350.036875 700.55875C345.245 689.305625 342.9025 677.165 343.1625 664.936875V461.18625L151.9125 273.68625C134.655625 255.95125 125 232.1781249999999 125 207.433125C125 182.6875 134.655625 158.9250000000001 151.9125 141.1875L378.788125 -85.6875C387.53875 -94.5124999999999 397.945625 -101.5187500000001 409.4125 -106.3125C432.275625 -115.4875000000001 457.8 -115.4875000000001 480.663125 -106.3125C492.13 -101.5187500000001 502.536875 -94.5124999999999 511.2875 -85.6875L819.4125 221.8143749999999L778.1625 84.3125C776.29375 74.81875 776.29375 65.05625 778.1625 55.5625C780.1687499999999 46.05625 784.21875 37.09375 790.0374999999999 29.30625C796.09375 21.75 803.5124999999999 15.3937500000001 811.9125 10.5625C820.68125 6.1875 830.25 3.6375 840.0375 3.0625C850.35 2.4312500000001 860.65625 4.3625 870.0375 8.6875C879.36875 12.90625 887.6875 19.09375 894.4125 26.8125C901.2125 34.69375 905.9375 44.14375 908.1625 54.3125C910.125 63.3562500000001 910.3375 72.6875 908.7875 81.80625zM408.786875 664.936875C407.87 669.053125 407.87 673.3175 408.786875 677.43375C410.5456250000001 681.4449999999999 413.09625 685.061875 416.2862500000001 688.061875C419.674375 690.73875 423.473125 692.8475 427.53625 694.31C431.861875 695.239375 436.336875 695.239375 440.6625 694.31C448.248125 693.72375 455.36 690.389375 460.663125 684.93375C465.574375 679.19125 468.238125 671.8668749999999 468.1625 664.31125V585.560625L405.6625 523.0606250000001L408.786875 664.936875zM471.286875 -44.4375C468.64625 -47.6 465.18875 -49.975 461.2887500000001 -51.3125C457.548125 -52.9625 453.503125 -53.81875 449.4131250000001 -53.81875C445.32375 -53.81875 441.27875 -52.9625 437.538125 -51.3125C433.638125 -49.975 430.176875 -47.6 427.53625 -44.4375L200.660625 181.8125C197.81375 184.7312499999999 195.489375 188.1062499999999 193.786875 191.80625C192.15375 195.6637499999999 191.315 199.8125 191.315 203.999375C191.315 208.186875 192.15375 212.328125 193.786875 216.1837499999999C195.489375 219.885625 197.81375 223.27 200.660625 226.185625L472.538125 498.059375V319.935625C467.775625 315.57125 463.97875 310.2543750000001 461.395 304.33375C458.811875 298.4131250000001 457.499375 292.0175 457.53875 285.5575C456.77625 277.3318750000001 458.201875 269.053125 461.67 261.555625C465.138125 254.058125 470.525 247.60875 477.2875 242.86375C484.049375 238.11875 491.945 235.24375 500.175625 234.5325000000001C508.405625 233.8212500000001 516.6787499999999 235.2981249999999 524.154375 238.8125C531.630625 242.326875 538.0443750000001 247.753125 542.7475000000001 254.544375C547.450625 261.3356250000001 550.276875 269.2512500000001 550.9375 277.4856250000001C551.5981250000001 285.7206250000001 550.0693749999999 293.988125 546.50875 301.441875C542.948125 308.89625 537.4825 315.274375 530.6625 319.935625V496.808125L771.2875 254.933125L471.286875 -44.4375z" /> + horiz-adv-x="1000" d=" M500 695C512.36125 695 524.445 691.334375 534.723125 684.466875C545.000625 677.599375 553.011875 667.838125 557.7425000000001 656.4175C562.4725000000001 644.9975 563.710625 632.430625 561.2987499999999 620.306875C558.8874999999999 608.183125 552.9343749999999 597.046875 544.19375 588.305625C535.453125 579.565 524.316875 573.6125 512.193125 571.200625C500.06875 568.789375 487.5025 570.026875 476.081875 574.7574999999999C464.661875 579.488125 454.900625 587.49875 448.033125 597.776875C441.165 608.0550000000001 437.5 620.1387500000001 437.5 632.5C437.5 649.07625 444.084375 664.973125 455.805625 676.694375C467.526875 688.415 483.42375 695 500 695zM500 757.5C475.276875 757.5 451.109375 750.16875 430.5537500000001 736.43375C409.9975 722.69875 393.975625 703.17625 384.515 680.3356249999999C375.0537500000001 657.494375 372.578125 632.36125 377.401875 608.11375C382.225 583.86625 394.13 561.5931250000001 411.61125 544.111875C429.0931250000001 526.63 451.365625 514.7249999999999 475.613125 509.901875C499.86125 505.07875 524.994375 507.554375 547.8349999999999 517.015C570.675625 526.4762499999999 590.198125 542.4975 603.9331249999999 563.05375C617.66875 583.61 625 607.7775 625 632.5C625 665.651875 611.83 697.44625 588.3881250000001 720.888125C564.94625 744.330625 533.151875 757.5 500 757.5V757.5zM576.875 476.875H423.125C393.785 476.875 365.6475000000001 465.22 344.90125 444.47375C324.1550000000001 423.7275 312.5 395.589375 312.5 366.25V201.25C311.816875 183.88125 317.9862500000001 166.94375 329.6775 154.08125C341.36875 141.21875 357.64625 133.46875 375 132.5V-13.125C375 -33.0187500000001 382.90125 -52.09375 396.966875 -66.15625C411.031875 -80.225 430.10875 -88.125 450 -88.125H550C560.0625 -88.1312499999999 570.0243750000001 -86.1124999999999 579.290625 -82.1875C588.556875 -78.2624999999999 596.9387499999999 -72.5125 603.936875 -65.28125C610.934375 -58.0499999999999 616.405625 -49.4875 620.024375 -40.09375C623.6431249999999 -30.70625 625.3375 -20.6812500000001 625 -10.625V132.5C642.3562499999999 133.46875 658.63125 141.21875 670.3249999999999 154.08125C682.0125 166.94375 688.18125 183.88125 687.5 201.25V366.25C687.5 395.589375 675.84375 423.7275 655.1 444.47375C634.35 465.22 606.214375 476.875 576.875 476.875zM375 195V366.25C374.915625 372.5931250000001 376.103125 378.88875 378.491875 384.765625C380.880625 390.6425 384.4225 395.98125 388.908125 400.466875C393.39375 404.9525 398.7325 408.494375 404.609375 410.883125C410.4856250000001 413.271875 416.781875 414.45875 423.125 414.375H576.875C583.218125 414.45875 589.51375 413.271875 595.390625 410.883125C601.266875 408.494375 606.605625 404.9525 611.09125 400.466875C615.576875 395.98125 619.1187500000001 390.6425 621.5074999999999 384.765625C623.89625 378.88875 625.0812500000001 372.5931250000001 625 366.25V195H562.5V-11.875C562.5 -15.1875 561.1825 -18.36875 558.83875 -20.7125C556.494375 -23.05625 553.315 -24.375 550 -24.375H450C446.6843750000001 -24.375 443.505 -23.05625 441.160625 -20.7125C438.816875 -18.36875 437.5 -15.1875 437.5 -11.875V195H375z" /> + horiz-adv-x="1000" d=" M615.001875 757.5L558.124375 735.000625V601.25L344.375625 446.876875C312.088125 462.23125 276.160625 468.293125 240.62375 464.37875C205.404375 460.41 172.033125 446.54 144.375 424.3775V378.74625L321.87625 206.253125L60.001375 -55H154.99875L369.99875 159.99375L525.623125 8.125H573.1237500000001C595.60375 34.58125 609.7418749999999 67.1 613.746875 101.5875C617.75125 136.06875 611.44625 170.96875 595.626875 201.874375L755 409.378125H892.5L915.625 464.37875L615.001875 757.5zM740 474.373125L713.125 461.250625L533.74875 226.875625L529.99875 195C547.994375 160.61875 553.0962499999999 120.9375 544.37625 83.125L419.3762500000001 208.1225000000001L371.875625 254.371875L224.99875 397.499375C263.8625 405.660625 304.34125 400.6025 340 383.125625L373.1268750000001 386.8718750000001L614.3762499999999 561.249375L627.5 586.87625V658.7525L815 476.25L740 474.373125z" /> @@ -417,7 +420,7 @@ horiz-adv-x="1000" d=" M447.5 601.248125C295.625 503.748125 221.875 403.123125 221.875 234.998125C231.875 238.1231250000001 240.625 238.1231250000001 249.375 238.1231250000001C328.75 238.1231250000001 405.625 184.375 405.625 87.5C405.625 -13.125 341.25 -75.625 249.375 -75.625C130.625 -75.625 62.5 19.375 62.5 190C62.5 427.498125 171.875 598.123125 376.25 716.248125L447.5 601.248125zM885 601.248125C733.125 503.748125 659.375 403.123125 659.375 234.998125C669.375 238.1231250000001 678.125 238.1231250000001 686.875 238.1231250000001C766.25 238.1231250000001 843.125 184.375 843.125 87.5C843.125 -13.125 778.75 -75.625 686.875 -75.625C568.75 -75.625 500.625 19.375 500.625 190C500.625 427.498125 610 598.123125 814.375 716.248125L885.625 601.248125H885z" /> + horiz-adv-x="1000" d=" M187.400625 471.2525C188.040625 562.236875 224.4025 649.326875 288.650625 713.753125L244.274375 757.5C206.480625 720.0231249999999 176.485 675.435 156.01375 626.3050000000001C135.541875 577.174375 125 524.4775 125 471.2525C125 418.0281250000001 135.541875 365.330625 156.01375 316.200625C176.485 267.07 206.480625 222.4825 244.274375 185.00625L288.650625 228.7525C224.4025 293.178125 188.040625 380.26875 187.400625 471.2525zM253.649375 471.2525C253.488125 434.3950000000001 260.705625 397.88 274.874375 363.8537500000001C289.0431250000001 329.8275 309.876875 298.9756250000001 336.15 273.125L380.52625 317.505C359.984375 337.270625 343.8037500000001 361.114375 333.025625 387.505C321.87125 414.0168750000001 316.1325 442.49 316.149375 471.2525C316.061875 499.820625 321.805 528.103125 333.025625 554.375C343.643125 581.03375 359.83875 605.114375 380.52625 625L336.15 669.380625C309.989375 643.445625 289.229375 612.5825 275.06875 578.575625C260.908125 544.5687499999999 253.6275 508.09 253.649375 471.2525zM731.775 270.63L687.4 315.0025C708.0125 334.9500000000001 724.1999999999999 359.01375 734.9 385.628125C746.05625 412.14 751.79375 440.613125 751.775 469.375625C751.8625 497.94375 746.125 526.23375 734.9 552.505625C724.28125 579.1643750000001 708.0875 603.245 687.4 623.13125L731.775 666.878125C757.8937500000001 640.915 778.61875 610.044375 792.75625 576.0425C806.9 542.040625 814.18125 505.575625 814.18125 468.75C814.18125 431.925 806.9 395.4675000000001 792.75625 361.465625C778.61875 327.46375 757.8937500000001 296.59375 731.775 270.63zM816.775 757.5L772.4 713.1275C804.4875000000001 681.54625 829.975 643.896875 847.36875 602.37125C864.7625 560.8456249999999 873.71875 516.274375 873.71875 471.2525C873.71875 426.23125 864.7625 381.659375 847.36875 340.13375C829.975 298.6081250000001 804.4875000000001 260.95875 772.4 229.3781250000001L816.775 185.00625C854.56875 222.4825 884.56875 267.07 905.04375 316.200625C925.5125 365.330625 936.05 418.0281250000001 936.05 471.2525C936.05 524.4775 925.5125 577.174375 905.04375 626.3050000000001C884.56875 675.435 854.56875 720.0231249999999 816.775 757.5zM624.54625 480.60625C626.6875 459.044375 621.2893750000001 437.413125 609.275625 419.380625C604.0875 414.09875 598.439375 409.281875 592.399375 404.999375L807.4 -78.125L749.9 -103.11875L701.7750000000001 5.00625H355.52625L307.4000000000001 -103.11875L249.900625 -78.125L464.90125 404.999375C451.840625 418.1925 442.9337500000001 434.924375 439.2775 453.125625C435.60125 471.1425 437.3381250000001 489.844375 444.275 506.874375C451.585625 524.128125 463.743125 538.894375 479.275 549.378125C497.306875 561.391875 518.9462500000001 566.79 540.508125 564.651875C562.0706250000001 562.51375 582.224375 552.973125 597.545625 537.65125C612.866875 522.3299999999999 622.4075 502.16875 624.54625 480.60625zM524.9025 501.8775C518.9775 500.48125 513.56375 497.44875 509.2775 493.12625C505.91875 489.15875 503.55875 484.445 502.399375 479.378125C500.530625 473.48125 500.530625 467.148125 502.399375 461.250625C504.861875 455.578125 508.7343749999999 450.630625 513.64875 446.876875C518.9143750000001 443.639375 524.97 441.9125 531.150625 441.8793750000001C539.38875 442.039375 547.24375 445.384375 553.0699999999999 451.2106250000001C558.89625 457.036875 562.240625 464.891875 562.400625 473.129375C562.368125 479.310625 560.6375 485.36625 557.4 490.63125C553.64625 495.54625 548.69875 499.415 543.02625 501.8775C537.1287500000001 503.74625 530.7993749999999 503.74625 524.9025 501.8775zM539.27625 373.749375H522.4L468.025 252.503125H593.025L539.27625 373.749375zM676.775 65L621.15125 190H441.150625L385.5250000000001 65H676.775z" /> @@ -429,16 +432,16 @@ horiz-adv-x="1000" d=" M812.5 195H249.998125V695H499.998125V757.5H233.7475C219.413125 757.34125 205.226875 754.588125 191.87375 749.375C178.3075 743.470625 166.16 734.731875 156.248125 723.7475C146.12 713.150625 138.2525 700.606875 133.12375 686.875C127.9825 674.5899999999999 125.225 661.44 124.998125 648.125V54.375C124.848125 40.0125 127.6125 25.7624999999999 133.12375 12.5C144.080625 -14.2874999999999 165.20625 -35.6375 191.87375 -46.875C205.226875 -52.0875 219.413125 -54.84375 233.7475 -55H249.998125V7.5H233.7475C227.51125 7.48125 221.340625 8.7625 215.62375 11.25625C204.455625 16.1625 195.53375 25.08125 190.6225 36.25C189.674375 42.25 189.674375 48.36875 190.6225 54.375V85.625C189.674375 91.63125 189.674375 97.75 190.6225 103.75C195.53375 114.9187500000001 204.455625 123.8375 215.62375 128.74375C221.340625 131.2375 227.51125 132.51875 233.7475 132.5H812.5V7.5H562.498125V-55H843.75L875 -23.75V257.5H812.5V195zM375 632.5H312.5V570H375V632.5zM312.5 507.5H375V445H312.5V507.5zM312.5 382.5H375V320H312.5V382.5zM330 -117.5H312.5V70H500V-117.5H482.5L406.25 -23.125L330 -117.5zM625 757.5H906.25L937.5 726.25V351.25L906.25 320H750V257.5H687.5V320H625C608.42375 320 592.5275 326.5818750000001 580.806875 338.303125C569.085625 350.02375 562.5 365.92375 562.5 382.5V695C562.5 711.57625 569.085625 727.4762499999999 580.806875 739.196875C592.5275 750.918125 608.42375 757.5 625 757.5zM656.25 382.5H687.5V445H656.25C647.9625 445 640.0124999999999 441.705 634.15 435.845C628.2937499999999 429.984375 625 422.038125 625 413.75C625 405.461875 628.2937499999999 397.515625 634.15 391.6550000000001C640.0124999999999 385.795 647.9625 382.5 656.25 382.5zM750 382.5H875V445H750V382.5zM687.5 507.5H875V695H687.5V507.5z" /> + horiz-adv-x="1000" d=" M233.75125 757.5H843.75L875 726.25V-23.75L843.75 -55H625V7.5H812.5V132.5H625V195H812.5V695H250.001875V195H437.501875V132.5H250.001875H233.75125C227.625 132.5 221.559375 131.2875 215.90625 128.9187500000001C212.781875 127.6187500000001 209.818125 125.96875 207.06375 124.025C204.839375 122.4500000000001 202.749375 120.68125 200.826875 118.7375C196.52375 114.375 193.12875 109.2000000000001 190.84 103.5187500000001C188.555 97.83125 187.418125 91.75 187.501875 85.625V54.375C187.418125 48.25 188.555 42.16875 190.84 36.4812499999999C193.12875 30.8 196.52375 25.625 200.826875 21.2625C205.129375 16.90625 210.25625 13.44375 215.90625 11.08125C218.446875 10.0187500000001 221.07125 9.1875 223.749375 8.59375C225.49625 8.2 227.26625 7.91875 229.0475 7.7375C230.608125 7.575 232.179375 7.5 233.75125 7.5H437.501875V-55H233.75125C219.419375 -55 205.225 -52.16875 191.991875 -46.6625C178.755 -41.1625 166.73875 -33.0875 156.633125 -22.9250000000001C146.524375 -12.7624999999999 138.52875 -0.6999999999999 133.100625 12.5687499999999C127.671875 25.8312500000001 124.918125 40.0375 125.001875 54.375V648.125C124.918125 662.4606249999999 127.671875 676.666875 133.100625 689.934375C138.52875 703.201875 146.524375 715.26375 156.633125 725.42625C166.73875 735.588125 178.755 743.66 191.991875 749.16125C205.225 754.669375 219.419375 757.5 233.75125 757.5zM333.7537500000001 455.6275L378.12625 411.873125L500.001875 533.745V443.123125L336.251875 279.37375L380.6287500000001 235.6262500000001L500.6275 355.6293750000001V-117.5H563.1275V361.984375L690 235.6262500000001L733.75 279.37375L562.501875 451.233125V536.369375L687.5 411.873125L731.25 455.6275L555.0018749999999 632.5H510.625625L333.7537500000001 455.6275z" /> + horiz-adv-x="1000" d=" M875 570.0025C875.04375 593.474375 868.4812499999999 616.485 856.0625 636.40125C843.6437500000001 656.316875 825.8625000000001 672.333125 804.7625 682.6168749999999C783.6625 692.9 760.09375 697.035 736.75625 694.548125C713.41875 692.06125 691.25 683.05375 672.7875 668.5550000000001C654.3312500000001 654.056875 640.325 634.654375 632.38125 612.56875C624.435 590.4825 622.8675000000001 566.605625 627.85625 543.670625C632.85 520.735625 644.2 499.669375 660.6062499999999 482.8825C677.0125 466.09625 697.8125 454.268125 720.625 448.7525V382.5025C720.7249999999999 376.786875 719.1875 371.1625 716.1999999999999 366.290625C713.2125 361.41875 708.8875 357.5025 703.75 355.0025L530.625 265.0025L358.125 352.5025C352.63 355.2362500000001 348.083125 359.558125 345.07375 364.9075C342.065 370.256875 340.7325 376.386875 341.25 382.5025V448.7525C370.708125 456.358125 396.380625 474.446875 413.45625 499.6275C430.53125 524.808125 437.836875 555.3518750000001 434.0037500000001 585.53375C430.17 615.715 415.460625 643.4625 392.6318750000001 663.575C369.80375 683.686875 340.4237500000001 694.783125 310 694.783125C279.575625 694.783125 250.195625 683.686875 227.3675 663.575C204.539375 643.4625 189.829375 615.715 185.99625 585.53375C182.1625 555.3518750000001 189.468125 524.808125 206.54375 499.6275C223.61875 474.446875 249.291875 456.358125 278.75 448.7525V382.5025C278.785625 365.184375 283.58625 348.209375 292.625625 333.4375C301.665625 318.665625 314.5950000000001 306.66625 330 298.7525000000001L500 211.2525000000001V128.75C470.541875 121.1437500000001 444.86875 103.05625 427.79375 77.875C410.718125 52.69375 403.4125 22.1500000000001 407.24625 -8.03125C411.0793750000001 -38.2125000000001 425.789375 -65.9562499999999 448.6175 -86.06875C471.445625 -106.18125 500.8256250000001 -117.28125 531.25 -117.28125C561.6737499999999 -117.28125 591.05375 -106.18125 613.881875 -86.06875C636.7125 -65.9562499999999 651.41875 -38.2125000000001 655.25625 -8.03125C659.0875000000001 22.1500000000001 651.78125 52.69375 634.7062500000001 77.875C617.630625 103.05625 591.958125 121.1437500000001 562.5 128.75V211.2525000000001L731.25 296.2525C747.13125 304.2368750000001 760.4 316.601875 769.48125 331.885625C778.5625 347.169375 783.08125 364.7337500000001 782.5 382.5025V450.0025C808.93125 457.118125 832.29375 472.7125 849 494.390625C865.7125 516.06875 874.84375 542.631875 875 570.0025zM250 570.0025C250 582.36375 253.665625 594.4475 260.533125 604.725625C267.400625 615.00375 277.161875 623.014375 288.581875 627.745C300.0025 632.475 312.569375 633.713125 324.693125 631.30125C336.8168750000001 628.89 347.953125 622.9375 356.69375 614.19625C365.435 605.455625 371.3875 594.319375 373.7987500000001 582.195625C376.210625 570.071875 374.9725 557.505 370.2425 546.084375C365.511875 534.6643750000001 357.50125 524.903125 347.2231250000001 518.035625C336.945 511.168125 324.86125 507.5025 312.5 507.5025C295.92375 507.5025 280.026875 514.086875 268.305625 525.808125C256.584375 537.5293750000001 250 553.42625 250 570.0025zM591.875 7.5C591.875 -4.8562499999999 588.209375 -16.94375 581.341875 -27.21875C574.47375 -37.5 564.713125 -45.5125 553.2925 -50.2375C541.871875 -54.96875 529.305625 -56.20625 517.181875 -53.79375C505.0575000000001 -51.3874999999999 493.92125 -45.43125 485.180625 -36.69375C476.44 -27.9499999999999 470.4875 -16.8125 468.075625 -4.69375C465.664375 7.4312500000001 466.901875 20 471.6325 31.41875C476.3625 42.8375 484.37375 52.6 494.651875 59.46875C504.93 66.3375 517.013125 70 529.375 70C537.5825 70 545.709375 68.3874999999999 553.2925 65.24375C560.875625 62.1062499999999 567.765 57.5 573.5687499999999 51.69375C579.3725 45.89375 583.9762499999999 39 587.1175 31.41875C590.258125 23.8375 591.875 15.7125 591.875 7.5zM750 507.5025C737.6374999999999 507.5025 725.55625 511.168125 715.275 518.035625C705 524.903125 696.9875 534.6643750000001 692.25625 546.084375C687.5250000000001 557.505 686.2875 570.071875 688.6999999999999 582.195625C691.1125000000001 594.319375 697.0625 605.455625 705.80625 614.19625C714.54375 622.9375 725.6812500000001 628.89 737.80625 631.30125C749.9312500000001 633.713125 762.5 632.475 773.91875 627.745C785.3375 623.014375 795.1 615.00375 801.96875 604.725625C808.83125 594.4475 812.5 582.36375 812.5 570.0025C812.5 553.42625 805.9125 537.5293750000001 794.19375 525.808125C782.475 514.086875 766.575 507.5025 750 507.5025z" /> + horiz-adv-x="1000" d=" M843.75 757.5H233.75C219.415625 757.50025 205.223125 754.666875 191.988125 749.1625C178.753125 743.658125 166.736875 735.591875 156.63 725.4275C146.52375 715.2625 138.52625 703.2 133.098125 689.93375C127.669375 676.6675 124.9175 662.45875 125 648.125V54.375C124.9175 40.0437499999999 127.669375 25.8312500000001 133.098125 12.5687499999999C138.52625 -0.6999999999999 146.52375 -12.7624999999999 156.63 -22.9250000000001C166.736875 -33.09375 178.753125 -41.15625 191.988125 -46.6625C205.223125 -52.16875 219.415625 -55 233.75 -55H437.5V7.5H233.75C227.623125 7.5 221.5575 8.71875 215.905 11.08125C210.2525 13.44375 205.12625 16.90625 200.823125 21.26875C196.52 25.625 193.126875 30.8 190.839375 36.4812499999999C188.5525 42.16875 187.416875 48.25 187.5 54.375V85.625C187.416875 91.75 188.5525 97.83125 190.839375 103.5187500000001C193.126875 109.2000000000001 196.52 114.375 200.823125 118.7312500000001C205.12625 123.09375 210.2525 126.55625 215.905 128.9187500000001C221.555 131.28125 227.618125 132.5 233.741875 132.5C233.744375 132.5 233.7475 132.5 233.75 132.5H250H437.5V195H250V695H812.5V195H625V132.5H812.5V7.5H625V-55H843.75L875 -23.75V726.25L843.75 757.5zM187.5 649.38375C187.494375 648.964375 187.494375 648.5450000000001 187.5 648.125V184.375L187.5 649.38375zM375 632.5H312.5V570H375V632.5zM336.25 279.378125L380.625 235.6281250000001L500.625625 355.62875V-117.5H563.125625V361.99125L690 235.6281250000001L733.75 279.378125L557.5 456.253125H513.125L336.25 279.378125zM312.5 507.5H375V445H312.5V507.5z" /> @@ -450,7 +453,7 @@ horiz-adv-x="1000" d=" M906.25 757.5H93.75L62.5 726.25V101.25L93.75 70H250V-86.25L303.375 -108.375L481.6875 70H906.25L937.5 101.25V726.25L906.25 757.5zM875 132.5H468.75L446.625 123.375L312.5 -10.8125V101.25L281.25 132.5H125V695H875V132.5zM625 195H375V258.8425H625V195zM468.75 632.5H531.25V507.5H656.25V445H531.25V320H468.75V445H343.75V507.5H468.75V632.5z" /> + horiz-adv-x="1000" d=" M905.6875 757.5C680.7875 757.21875 489.8325 633.581875 353.521875 507.5H93.75L62.5 476.25V288.75L71.6875 266.625L133.6225 204.69L133.686875 204.125L383.686875 -45.875L384.25 -45.9375L446.6875 -108.375L468.75 -117.5H656.25L687.5 -86.25V173.375C813.6875 309.475625 937.25 500.436875 937 726.25L905.6875 757.5zM125 445H290.191875C224.529375 375.9993750000001 176.98125 312.5025 151.151875 275.56625L125 301.6875V445zM481.25 -55L455.030625 -28.5374999999999C492.038125 -2.84375 555.621875 44.46875 624.6875 109.93125V-55H481.25zM409.811875 16.5L195.999375 230.1875C257.999375 320 523.686875 672.8125 873.625 694C853.25 343.25 499.436875 78.1875 409.811875 16.5zM250 -117.5V-55H125V70H62.5V-117.5H250zM671.71875 361.6975C682.0125 377.1075 687.5 395.220625 687.5 413.7493750000001C687.5 426.0875 685.0625 438.30375 680.3312500000001 449.698125C675.6 461.093125 668.66875 471.441875 659.93125 480.15125C651.19375 488.86125 640.81875 495.76 629.4125 500.453125C618 505.14625 605.775 507.540625 593.4375 507.499375C574.9087499999999 507.4375 556.8143749999999 501.886875 541.438125 491.548125C526.0625 481.209375 514.0949999999999 466.54625 507.046875 449.4100000000001C499.999375 432.274375 498.186875 413.43375 501.839375 395.26875C505.4925 377.10375 514.4456250000001 360.4287500000001 527.569375 347.34875C540.6925 334.26875 557.3981249999999 325.370625 575.5749999999999 321.77875C593.751875 318.1862500000001 612.58625 320.0612500000001 629.7 327.16625C646.8125 334.270625 661.43125 346.286875 671.71875 361.6975z" /> @@ -486,7 +489,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.2zM406.25 382.5C406.25 347.9825 378.2675 320 343.75 320C309.2325 320 281.25 347.9825 281.25 382.5C281.25 417.0175 309.2325 445 343.75 445C378.2675 445 406.25 417.0175 406.25 382.5zM718.75 382.5C718.75 347.9825 690.7687500000001 320 656.25 320C621.7318750000001 320 593.75 347.9825 593.75 382.5C593.75 417.0175 621.7318750000001 445 656.25 445C690.7687500000001 445 718.75 417.0175 718.75 382.5zM500 132.5C466.038125 132.4187499999999 432.689375 141.55625 403.51875 158.9499999999999C374.348125 176.34375 350.44875 201.3306250000001 334.3737500000001 231.2475L279.9987500000001 201.24875C301.883125 160.75 334.5250000000001 127.08125 374.3250000000001 103.9500000000001C414.124375 80.81875 459.536875 69.13125 505.558125 70.1687500000001C551.57875 71.1999999999999 596.423125 84.9187499999999 635.14375 109.8125C673.8625000000001 134.70625 704.95625 169.8125 725 211.250625L668.75 238.1212500000001C653.375 206.4475000000001 629.39375 179.74375 599.551875 161.0625C569.70875 142.3875000000001 535.2075 132.4875000000001 500 132.5z" /> + horiz-adv-x="1000" d=" M347.380625 654.87375C344.81 655.121875 342.2362500000001 655.3275 339.659375 655.489375C338.5925000000001 659.740625 337.220625 663.919375 335.549375 667.993125C330.93 679.253125 324.12 689.483125 315.51375 698.089375C306.908125 706.6949999999999 296.6775 713.505625 285.4175 718.125C274.1575 722.74375 262.091875 725.08 249.92125 724.996875V643.288125C202.60875 624.485 160.730625 594.176875 128.08125 555.10625C95.3475 515.935 72.929375 469.199375 62.866875 419.153125V394.788125C91.5475 342.4875 181.98875 324.104375 197.481875 320.955625C199.2 320.60625 199.99625 320.444375 199.684375 320.444375C48.4976875 300.4525 62.866875 179.88125 62.866875 179.88125C63.975625 164.08125 71.04375 149.2874999999999 82.641875 138.50625C94.24 127.71875 109.501875 121.7375 125.340625 121.775C142.28125 122.90625 158.938125 126.6999999999999 174.695 133.025H303.390625C292.2356250000001 113.6999999999999 284.619375 92.5437499999999 280.9 70.5500000000001H260.90875C223.106875 64.85 188.61375 45.75 163.725625 16.7375C138.8375 -12.28125 125.21375 -49.28125 125.340625 -87.5125C124.815 -91.10625 125.04125 -94.7687500000001 126.005 -98.2687499999999C126.968125 -101.7687500000001 128.64875 -105.03125 130.93875 -107.8499999999999C133.229375 -110.66875 136.079375 -112.9812499999999 139.31 -114.6437499999999C142.54 -116.30625 146.08 -117.275 149.705 -117.5H567.0300000000001C600.978125 -119.2312499999999 634.9 -113.575 666.4499999999999 -100.9249999999999C698 -88.2750000000001 726.425 -68.9249999999999 749.76875 -44.2125000000001C773.1125 -19.50625 790.81875 9.975 801.65625 42.19375C812.49375 74.4125 816.2125 108.6 812.55 142.3937500000001C810.875 189.725 794.49375 235.3631250000001 765.7 272.964375L758.8249999999999 281.7106250000001C731.9625 316.07125 716.34375 338.561875 724.4625 362.301875C732.5875 386.041875 747.25 387.2912500000001 747.25 387.2912500000001C747.25 387.2912500000001 758.8249999999999 389.1656250000001 775.6937499999999 381.66875C789.4625 373.6675 804.44375 367.9700000000001 820.05 364.800625C834.7 362.03125 849.7875 362.6162500000001 864.1750000000001 366.51125C878.56875 370.406875 891.8875 377.51125 903.1375 387.2912500000001C913.95 396.693125 922.6125 408.30875 928.5375 421.35125C934.46875 434.39375 937.525 448.558125 937.5 462.884375C937.86875 507.773125 916.84375 553.790625 892.19375 593.35625C867.5500000000001 632.92125 834.35625 666.46875 795.0625 691.5387499999999C744.56875 718.51375 686.34375 727.335625 630.13125 716.528125C590.3362500000001 709.524375 553.8 690.053125 525.7975 660.926875C503.459375 636.565625 486.815 607.544375 477.068125 575.9625C465.615 592.9762499999999 452.285625 608.62875 437.3425000000001 622.629375V632.5375C437.511875 656.680625 428.166875 679.919375 411.33 697.22375C394.493125 714.52875 371.519375 724.506875 347.380625 724.99875V654.87375zM678.86875 108.6999999999999C685.83125 62.3499999999999 692.5812500000001 -5.14375 624.703125 -43.9187499999999C606.1775 -50.4 586.7168750000001 -53.95 567.0300000000001 -54.4H200.93375C200.883125 -38.6625 206.775 -23.4812499999999 217.430625 -11.9C228.086875 -0.31875 242.721875 6.81875 258.41 8.075H338.37625V39.3125C338.044375 54 340.609375 68.6062500000001 345.925 82.3C351.24 95.9937500000001 359.2018750000001 108.5124999999999 369.354375 119.125C379.5075 129.74375 391.6525000000001 138.25625 405.09625 144.175C416.70375 149.2937500000001 429.083125 152.3874999999999 441.7018750000001 153.34375L402.589375 208.8406250000001C387.825625 204.641875 373.628125 199.265625 366.489375 194.25H165.94875C160.558125 194.25 154.975 192.0375 149.42625 189.8375000000001C140.8275 186.4375 132.31 183.0625 124.715625 188C112.22125 196.1212499999999 131.588125 257.970625 187.814375 257.970625H250.288125C280.9 257.970625 285.898125 291.70625 285.898125 291.70625L303.390625 362.301875C271.244375 357.686875 238.4675 360.52625 207.594375 370.6006250000001C176.720625 380.675 148.5775 397.715 125.340625 420.4025000000001C135.285 465.783125 159.875625 506.635 195.32375 536.6643750000001C230.771875 566.693125 275.11 584.23375 321.508125 586.5825C323.320625 586.518125 325.058125 586.465 326.738125 586.4143750000001C343.02 585.92 353.91875 585.589375 375.2356250000001 575.9625C433.33625 549.723125 509.554375 421.651875 509.554375 421.651875L513.303125 416.029375H523.923125V420.4025000000001C520.18 448.078125 522.66875 511.850625 531.2075000000001 538.440625C539.7468749999999 565.03125 554.120625 589.3768749999999 573.2775 609.698125C595.2937499999999 631.705 623.735 646.144375 654.49375 650.930625C694.1374999999999 659.375625 735.50625 652.92625 770.6937499999999 632.813125C799.48125 615.063125 823.8375 590.9825 841.91875 562.4025C859.99375 533.823125 871.6625 510.136875 875.36875 476.523125C875.3 475.295625 875.3874999999999 473.545625 875.49375 471.433125C875.94375 462.50125 876.71875 447.085 867.49375 437.270625C859.56875 428.83625 839.50625 422.85125 825.6750000000001 426.025C815.775 428.2956250000001 806.29375 432.089375 797.55625 437.270625C787.04375 443.854375 775.19375 448.0012500000001 762.86875 449.40625C750.5437499999999 450.811875 738.0625 449.44 726.3375 445.391875C712.06875 440.79 699.1937499999999 432.64625 688.925 421.72125C678.65625 410.795625 671.3249999999999 397.445625 667.6125000000001 382.918125C661.34375 358.138125 661.74375 332.1418750000001 668.7687500000001 307.5650000000001C675.7875 282.988125 689.18125 260.705625 707.59375 242.9768750000001L714.46875 234.2306249999999C736.09375 207.145625 748.5625 173.89375 750.0812500000001 139.26875C750.9125 114.5 746.8249999999999 89.8125 738.05 66.63125C735.9312500000001 61.0375 733.5500000000001 55.55625 730.9187499999999 50.2125000000001C730.5 55.1999999999999 729.8625 60.1875 729 65.15C724.825 89.11875 715.54375 111.8125 701.9 131.7375L678.86875 108.6999999999999zM265 507.5C256.711875 507.5 248.763125 504.2075 242.903125 498.346875C237.0425 492.486875 233.75 484.538125 233.75 476.25C233.75 467.961875 237.0425 460.013125 242.903125 454.153125C248.763125 448.2925 256.711875 445 265 445C273.288125 445 281.236875 448.2925 287.096875 454.153125C292.9575 460.013125 296.25 467.961875 296.25 476.25C296.25 484.538125 292.9575 492.486875 287.096875 498.346875C281.236875 504.2075 273.288125 507.5 265 507.5z" /> @@ -495,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" /> @@ -516,10 +519,10 @@ horiz-adv-x="1000" d=" M875 507.5H125V632.5H875V507.5zM875 257.5H125V382.5H875V257.5zM125 7.5H875V132.5H125V7.5z" /> + horiz-adv-x="1000" d=" M341.25 -61.875C323.20125 -61.7874999999999 305.58375 -56.3499999999999 290.625 -46.25C274.4575000000001 -34.6 262.821875 -17.71875 257.694375 1.5375C252.5675 20.79375 254.265625 41.23125 262.5 59.375L323.125 195H148.75C134.4325 194.7312499999999 120.279375 198.088125 107.605 204.7531250000001C94.93 211.4181249999999 84.145 221.1775 76.25 233.125C68.31125 245.2375000000001 63.623125 259.19 62.638125 273.63875C61.6530625 288.0875 64.40375 302.546875 70.625 315.625C112.5 406.25 187.5 570 212.5 638.75C218.610625 655.22125 229.605625 669.4337499999999 244.014375 679.48625C258.4225 689.5387499999999 275.556875 694.9512500000001 293.125 695H851.25C874.2375 694.67125 896.1750000000001 685.308125 912.3125 668.9337499999999C928.45625 652.56 937.5 630.49125 937.5 607.5V388.125C937.5 376.79875 935.26875 365.583125 930.9375 355.11875C926.6 344.654375 920.25 335.14625 912.2375 327.136875C904.23125 319.128125 894.71875 312.775 884.2562499999999 308.440625C873.79375 304.1056250000001 862.5749999999999 301.875 851.25 301.875H765L400 -39.375C383.851875 -53.85 362.935 -61.85625 341.25 -61.875zM293.125 632.5C288.24125 632.45 283.484375 630.933125 279.4725000000001 628.146875C275.460625 625.36125 272.378125 621.43375 270.625 616.875C245.625 548.75 178.75 401.25 125 289.375C123.1925 285.900625 122.24875 282.041875 122.24875 278.125C122.24875 274.208125 123.1925 270.349375 125 266.875C127.60125 263.1531250000001 131.240625 260.2793750000001 135.46375 258.6125C139.6875 256.9450000000001 144.308125 256.558125 148.75 257.5H355L387.5 215V186.25L319.375 33.75C317.110625 28.76875 316.6843750000001 23.1500000000001 318.171875 17.8875C319.659375 12.625 322.964375 8.0562500000001 327.5 5C331.7375 1.55 337.035 -0.3375000000001 342.5 -0.3375000000001C347.9650000000001 -0.3375000000001 353.263125 1.55 357.5 5L736.25 354.375L765.625 362.5H851.25C854.53125 362.49 857.78125 363.160625 860.79375 364.469375C863.80625 365.778125 866.5125 367.6975 868.7437500000001 370.105625C870.975 372.51375 872.68125 375.358125 873.7625 378.459375C874.8375000000001 381.5612500000001 875.2625 384.851875 875 388.125V607.5C875.00625 613.919375 872.5437499999999 620.095625 868.125 624.75C863.70625 629.4043750000001 857.6625 632.17875 851.25 632.5H293.125z" /> + horiz-adv-x="1000" d=" M658.75 695.000625C676.8 694.9137499999999 694.4187499999999 689.4762499999999 709.375 679.375625C725.54375 667.72875 737.18125 650.8425 742.30625 631.5875C747.43125 612.3325 745.7375000000001 591.895625 737.5 573.75125L676.875 438.12625L851.25 438.125625C865.56875 438.3925 879.71875 435.038125 892.39375 428.3725C905.06875 421.7075 915.85625 411.948125 923.75 400.000625C931.6875 387.888125 936.375 373.9362500000001 937.3625 359.4875C938.35 345.0381250000001 935.59375 330.57875 929.375 317.500625C887.5 226.875625 812.5 63.125 787.5 -5.625C781.3875 -22.09375 770.39375 -36.3062500000001 755.9875000000001 -46.3625000000001C741.5749999999999 -56.4125 724.44375 -61.8249999999999 706.875 -61.875L148.75 -61.875C125.760625 -61.5437499999999 103.824375 -52.18125 87.684375 -35.80625C71.544375 -19.43125 62.4974375 2.6375 62.49975 25.625L62.4998125 245.0012500000001C62.4998125 256.3275 64.730625 267.5431250000001 69.065 278.0075000000001C73.399375 288.471875 79.7525 297.9799999999999 87.761875 305.98875C95.770625 313.998125 105.27875 320.3512500000001 115.743125 324.685625C126.2075 329.02 137.423125 331.25125 148.75 331.25125L235 331.25125L600 672.50125C616.148125 686.97375 637.0625 694.984375 658.75 695.000625zM706.875 0.625C711.75625 0.6750000000001 716.5125 2.19375 720.525 4.9812499999999C724.5374999999999 7.7625 727.61875 11.69375 729.375 16.25C754.375 84.375 821.25 231.875625 875 343.750625C876.80625 347.225625 877.75 351.084375 877.75 355.000625C877.75 358.9175 876.80625 362.77625 875 366.250625C872.4 369.9725 868.7625 372.84625 864.5374999999999 374.51375C860.3125 376.180625 855.69375 376.5675 851.25 375.625625L645 375.62625L612.5 418.125625L612.5 446.8762500000001L680.625 599.375625C682.8874999999999 604.355 683.31875 609.975625 681.83125 615.239375C680.34375 620.5025 677.0374999999999 625.06875 672.5 628.125625C668.2624999999999 631.5775 662.9625 633.4625 657.5 633.4625C652.0375 633.4625 646.7375 631.5775 642.5 628.12625L263.75 278.7512500000001L234.375 270.6262500000001L148.75 270.6262500000001C145.466875 270.6362499999999 142.216875 269.9656250000001 139.20625 268.6568749999999C136.195 267.3475 133.48875 265.4287500000001 131.256875 263.020625C129.025 260.6125 127.316875 257.768125 126.239375 254.66625C125.1625 251.565 124.740625 248.2737500000001 125 245.0012500000001L125 25.625C124.991875 19.2062500000001 127.453125 13.03125 131.875 8.375C136.29625 3.725 142.338125 0.95 148.75 0.625L706.875 0.625z" /> @@ -552,7 +555,7 @@ horiz-adv-x="1000" d=" M479.375 -100H523.75L631.25 7.5H781.25L812.5 38.75V190L921.25 297.4975000000001V341.8725L814.375 449.3725V601.8725L783.125 632.4975H631.25L523.75 739.3725H479.375L375 632.4975H220.625L187.5 601.2475V449.3725L81.875 341.8725V297.4975000000001L187.5 190V38.75L220.625 7.5H375L479.375 -100zM385 70H250V203.1225000000001L242.5 224.9975000000001L148.125 319.9975L240.625 414.3725L250 436.2475V569.9975H385L407.5 578.7475L500 673.1225L596.25 578.7475L618.125 569.9975H750V436.2475L760.625 414.3725L855.625 319.9975L758.75 224.9975000000001L750 203.1225000000001V70H618.125L594.375 60.625L500 -33.75L407.5 61.25L385 70zM420.6275 165.0062499999999H465.0025L700.625 400.625L656.25 445L443.1275 231.255625L356.875 317.51L312.5 273.135L420.6275 165.0062499999999z" /> + horiz-adv-x="1000" d=" M437.5 38.75L468.75 7.5H906.25L937.5 38.75V601.25L906.25 632.5H468.75L437.5 601.25V38.75zM562.5 507.5H812.5V132.5H562.5V507.5zM312.5 257.5V507.5H375V570H281.25L250 538.75V257.5V226.25V101.25L281.25 70H375V132.5H312.5V226.25V257.5zM125 320V445H187.5V507.5H93.75L62.5 476.25V320V288.75V163.75L93.75 132.5H187.5V195H125V288.75V320z" /> diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf index 108574251ca..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/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index ea4d43f5810..16279b74af9 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -143,7 +143,7 @@ export class Sash extends Disposable { this._register(domEvent(this.el, EventType.Start)(this.onTouchStart, this)); if (isIPad) { - // see also http://ux.stackexchange.com/questions/39023/what-is-the-optimum-button-size-of-touch-screen-applications + // see also https://ux.stackexchange.com/questions/39023/what-is-the-optimum-button-size-of-touch-screen-applications addClass(this.el, 'touch'); } diff --git a/src/vs/base/browser/ui/splitview/splitview.css b/src/vs/base/browser/ui/splitview/splitview.css index 6fb8f1c61d0..e5baba1f32a 100644 --- a/src/vs/base/browser/ui/splitview/splitview.css +++ b/src/vs/base/browser/ui/splitview/splitview.css @@ -21,24 +21,15 @@ } .monaco-split-view2 > .split-view-container { - display: flex; width: 100%; height: 100%; white-space: nowrap; -} - -.monaco-split-view2.vertical > .split-view-container { - flex-direction: column; -} - -.monaco-split-view2.horizontal > .split-view-container { - flex-direction: row; + position: relative; } .monaco-split-view2 > .split-view-container > .split-view-view { white-space: initial; - flex: none; - position: relative; + position: absolute; } .monaco-split-view2 > .split-view-container > .split-view-view:not(.visible) { @@ -51,7 +42,6 @@ .monaco-split-view2.horizontal > .split-view-container > .split-view-view { height: 100%; - display: inline-block; } .monaco-split-view2.separator-border > .split-view-container > .split-view-view:not(:first-child)::before { @@ -72,4 +62,4 @@ .monaco-split-view2.separator-border.vertical > .split-view-container > .split-view-view:not(:first-child)::before { height: 1px; width: 100%; -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 5e5e54dcf61..93b50dbcb4b 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -125,10 +125,13 @@ abstract class ViewItem { } } - layout(orthogonalSize: number | undefined): void { + layout(position: number, orthogonalSize: number | undefined): void { + this.layoutContainer(position); this.view.layout(this.size, orthogonalSize); } + abstract layoutContainer(position: number): void; + dispose(): IView { this.disposable.dispose(); return this.view; @@ -137,16 +140,16 @@ abstract class ViewItem { class VerticalViewItem extends ViewItem { - layout(orthogonalSize: number | undefined): void { - super.layout(orthogonalSize); + layoutContainer(position: number): void { + this.container.style.top = `${position}px`; this.container.style.height = `${this.size}px`; } } class HorizontalViewItem extends ViewItem { - layout(orthogonalSize: number | undefined): void { - super.layout(orthogonalSize); + layoutContainer(position: number): void { + this.container.style.left = `${position}px`; this.container.style.width = `${this.size}px`; } } @@ -846,7 +849,12 @@ export class SplitView extends Disposable { this.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); // Layout views - this.viewItems.forEach(item => item.layout(this.orthogonalSize)); + let position = 0; + + for (const viewItem of this.viewItems) { + viewItem.layout(position, this.orthogonalSize); + position += viewItem.size; + } // Layout sashes this.sashItems.forEach(item => item.sash.layout()); @@ -903,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 a8dca1e311a..c20a8771c87 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -24,7 +24,7 @@ interface IAsyncDataTreeNode { readonly parent: IAsyncDataTreeNode | null; readonly children: IAsyncDataTreeNode[]; readonly id?: string | null; - loading: boolean; + refreshPromise: Promise | undefined; hasChildren: boolean; stale: boolean; slow: boolean; @@ -41,7 +41,7 @@ function createAsyncDataTreeNode(props: IAsyncDataTreeNodeRequiredPro return { ...props, children: [], - loading: false, + refreshPromise: undefined, stale: true, slow: false, collapsedByDefault: undefined @@ -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,13 +463,17 @@ 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'); } - if (this.root.loading) { - await this.subTreeRefreshPromises.get(this.root)!; + if (this.root.refreshPromise) { + await this.root.refreshPromise; await Event.toPromise(this._onDidRender.event); } @@ -519,21 +523,26 @@ export class AsyncDataTree implements IDisposable throw new TreeError(this.user, 'Tree input not set'); } - if (this.root.loading) { - await this.subTreeRefreshPromises.get(this.root)!; + if (this.root.refreshPromise) { + await this.root.refreshPromise; await Event.toPromise(this._onDidRender.event); } const node = this.getDataNode(element); - if (node !== this.root && !node.loading && !this.tree.isCollapsed(node)) { + if (node.refreshPromise) { + await this.root.refreshPromise; + await Event.toPromise(this._onDidRender.event); + } + + if (node !== this.root && !node.refreshPromise && !this.tree.isCollapsed(node)) { return false; } const result = this.tree.expand(node === this.root ? null : node, recursive); - if (node.loading) { - await this.subTreeRefreshPromises.get(node)!; + if (node.refreshPromise) { + await this.root.refreshPromise; await Event.toPromise(this._onDidRender.event); } @@ -677,18 +686,18 @@ export class AsyncDataTree implements IDisposable return result; } - result = this.doRefreshSubTree(node, recursive, viewStateContext); - this.subTreeRefreshPromises.set(node, result); - - try { - await result; - } finally { - this.subTreeRefreshPromises.delete(node); - } + return this.doRefreshSubTree(node, recursive, viewStateContext); } private async doRefreshSubTree(node: IAsyncDataTreeNode, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext): Promise { - node.loading = true; + let done: () => void; + node.refreshPromise = new Promise(c => done = c); + this.subTreeRefreshPromises.set(node, node.refreshPromise); + + node.refreshPromise.finally(() => { + node.refreshPromise = undefined; + this.subTreeRefreshPromises.delete(node); + }); try { const childrenToRefresh = await this.doRefreshNode(node, recursive, viewStateContext); @@ -696,7 +705,7 @@ export class AsyncDataTree implements IDisposable await Promise.all(childrenToRefresh.map(child => this.doRefreshSubTree(child, recursive, viewStateContext))); } finally { - node.loading = false; + done!(); } } @@ -869,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/collections.ts b/src/vs/base/common/collections.ts index a0f6695e8ae..ea5c8832004 100644 --- a/src/vs/base/common/collections.ts +++ b/src/vs/base/common/collections.ts @@ -7,17 +7,14 @@ * An interface for a JavaScript object that * acts a dictionary. The keys are strings. */ -export interface IStringDictionary { - [name: string]: V; -} +export type IStringDictionary = Record; + /** * An interface for a JavaScript object that * acts a dictionary. The keys are numbers. */ -export interface INumberDictionary { - [idx: number]: V; -} +export type INumberDictionary = Record; const hasOwnProperty = Object.prototype.hasOwnProperty; @@ -136,4 +133,4 @@ export class SetMap { values.forEach(fn); } -} \ No newline at end of file +} diff --git a/src/vs/base/common/console.ts b/src/vs/base/common/console.ts index 9b49ff985d4..478e06077a6 100644 --- a/src/vs/base/common/console.ts +++ b/src/vs/base/common/console.ts @@ -114,9 +114,9 @@ export function log(entry: IRemoteConsoleLog, label: string): void { // First arg is a string if (typeof args[0] === 'string') { if (topFrame && isOneStringArg) { - consoleArgs = [`%c[${label}] %c${args[0]} %c${topFrame}`, color('blue'), color('black'), color('grey')]; + consoleArgs = [`%c[${label}] %c${args[0]} %c${topFrame}`, color('blue'), color(''), color('grey')]; } else { - consoleArgs = [`%c[${label}] %c${args[0]}`, color('blue'), color('black'), ...args.slice(1)]; + consoleArgs = [`%c[${label}] %c${args[0]}`, color('blue'), color(''), ...args.slice(1)]; } } @@ -139,4 +139,4 @@ export function log(entry: IRemoteConsoleLog, label: string): void { function color(color: string): string { return `color: ${color}`; -} \ No newline at end of file +} diff --git a/src/vs/base/common/json.ts b/src/vs/base/common/json.ts index da0535be422..12a9c0a9761 100644 --- a/src/vs/base/common/json.ts +++ b/src/vs/base/common/json.ts @@ -207,17 +207,17 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON function scanHexDigits(count: number): number { let digits = 0; - let value = 0; + let hexValue = 0; while (digits < count) { const ch = text.charCodeAt(pos); if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) { - value = value * 16 + ch - CharacterCodes._0; + hexValue = hexValue * 16 + ch - CharacterCodes._0; } else if (ch >= CharacterCodes.A && ch <= CharacterCodes.F) { - value = value * 16 + ch - CharacterCodes.A + 10; + hexValue = hexValue * 16 + ch - CharacterCodes.A + 10; } else if (ch >= CharacterCodes.a && ch <= CharacterCodes.f) { - value = value * 16 + ch - CharacterCodes.a + 10; + hexValue = hexValue * 16 + ch - CharacterCodes.a + 10; } else { break; @@ -226,9 +226,9 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON digits++; } if (digits < count) { - value = -1; + hexValue = -1; } - return value; + return hexValue; } function setPosition(newPosition: number) { @@ -291,7 +291,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON scanError = ScanError.UnexpectedEndOfString; break; } - let ch = text.charCodeAt(pos); + const ch = text.charCodeAt(pos); if (ch === CharacterCodes.doubleQuote) { result += text.substring(start, pos); pos++; @@ -304,8 +304,8 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON scanError = ScanError.UnexpectedEndOfString; break; } - ch = text.charCodeAt(pos++); - switch (ch) { + const ch2 = text.charCodeAt(pos++); + switch (ch2) { case CharacterCodes.doubleQuote: result += '\"'; break; @@ -331,9 +331,9 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON result += '\t'; break; case CharacterCodes.u: - const ch = scanHexDigits(4); - if (ch >= 0) { - result += String.fromCharCode(ch); + const ch3 = scanHexDigits(4); + if (ch3 >= 0) { + result += String.fromCharCode(ch3); } else { scanError = ScanError.InvalidUnicode; } @@ -1340,4 +1340,4 @@ function getLiteralNodeType(value: any): NodeType { case 'string': return 'string'; default: return 'null'; } -} \ No newline at end of file +} diff --git a/src/vs/base/common/jsonEdit.ts b/src/vs/base/common/jsonEdit.ts index a1538870749..0aac5a59b22 100644 --- a/src/vs/base/common/jsonEdit.ts +++ b/src/vs/base/common/jsonEdit.ts @@ -144,11 +144,11 @@ function withFormatting(text: string, edit: Edit, formattingOptions: FormattingO // apply the formatting edits and track the begin and end offsets of the changes for (let i = edits.length - 1; i >= 0; i--) { - const edit = edits[i]; - newText = applyEdit(newText, edit); - begin = Math.min(begin, edit.offset); - end = Math.max(end, edit.offset + edit.length); - end += edit.content.length - edit.length; + const curr = edits[i]; + newText = applyEdit(newText, curr); + begin = Math.min(begin, curr.offset); + end = Math.max(end, curr.offset + curr.length); + end += curr.content.length - curr.length; } // create a single edit with all changes const editLength = text.length - (newText.length - end) - begin; @@ -182,4 +182,4 @@ export function applyEdits(text: string, edits: Edit[]): string { export function isWS(text: string, offset: number) { return '\r\n \t'.indexOf(text.charAt(offset)) !== -1; -} \ No newline at end of file +} diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 277ab50bb88..007d0a0d529 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -18,7 +18,7 @@ export function values(forEachable: { forEach(callback: (value: V, ...more: a export function keys(map: Map): K[] { const result: K[] = []; - map.forEach((value, key) => result.push(key)); + map.forEach((_value, key) => result.push(key)); return result; } @@ -482,8 +482,6 @@ export class ResourceMap { } } -// We should fold BoundedMap and LinkedMap. See https://github.com/Microsoft/vscode/issues/28496 - interface Item { previous: Item | undefined; next: Item | undefined; diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 71185d07046..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 1aa1c6fa550..1177889e12a 100644 --- a/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts +++ b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts @@ -8,6 +8,7 @@ import { ITreeNode, ITreeRenderer, IAsyncDataSource } from 'vs/base/browser/ui/t import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list'; import { hasClass } from 'vs/base/browser/dom'; +import { timeout } from 'vs/base/common/async'; interface Element { id: string; @@ -26,104 +27,89 @@ function find(elements: Element[] | undefined, id: string): Element { throw new Error('element not found'); } +class Renderer implements ITreeRenderer { + readonly templateId = 'default'; + renderTemplate(container: HTMLElement): HTMLElement { + return container; + } + renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { + templateData.textContent = element.element.id; + } + disposeTemplate(templateData: HTMLElement): void { + // noop + } +} + +class IdentityProvider implements IIdentityProvider { + getId(element: Element) { + return element.id; + } +} + +class VirtualDelegate implements IListVirtualDelegate { + getHeight() { return 20; } + getTemplateId(element: Element): string { return 'default'; } +} + +class DataSource implements IAsyncDataSource { + hasChildren(element: Element): boolean { + return !!element.children && element.children.length > 0; + } + getChildren(element: Element): Promise { + return Promise.resolve(element.children || []); + } +} + +class Model { + + constructor(readonly root: Element) { } + + get(id: string): Element { + return find(this.root.children, id); + } +} + suite('AsyncDataTree', function () { test('Collapse state should be preserved across refresh calls', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; - - const dataSource = new class implements IAsyncDataSource { - hasChildren(element: Element): boolean { - return !!element.children && element.children.length > 0; - } - getChildren(element: Element): Promise { - return Promise.resolve(element.children || []); - } - }; - - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a' }] - }; + }); - const _: (id: string) => Element = find.bind(null, root.children); - - const tree = new AsyncDataTree('test', container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], new DataSource(), { identityProvider: new IdentityProvider() }); tree.layout(200); assert.equal(container.querySelectorAll('.monaco-list-row').length, 0); - await tree.setInput(root); + 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')); - _('a').children = [ + model.get('a').children = [ { id: 'aa' }, { id: 'ab' }, { id: 'ac' } ]; - await tree.updateChildren(root); + await tree.updateChildren(model.root); assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); - await tree.expand(_('a')); + await tree.expand(model.get('a')); assert.equal(container.querySelectorAll('.monaco-list-row').length, 4); - _('a').children = []; - await tree.updateChildren(root); + model.get('a').children = []; + await tree.updateChildren(model.root); assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); }); test('issue #68648', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; const getChildrenCalls: string[] = []; const dataSource = new class implements IAsyncDataSource { @@ -136,25 +122,17 @@ suite('AsyncDataTree', function () { } }; - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a' }] - }; + }); - const _: (id: string) => Element = find.bind(null, root.children); - - const tree = new AsyncDataTree('test', container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); tree.layout(200); - await tree.setInput(root); + await tree.setInput(model.root); assert.deepStrictEqual(getChildrenCalls, ['root']); let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; @@ -162,8 +140,8 @@ suite('AsyncDataTree', function () { assert(!hasClass(twistie, 'collapsed')); assert(tree.getNode().children[0].collapsed); - _('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; - await tree.updateChildren(root); + model.get('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; + await tree.updateChildren(model.root); assert.deepStrictEqual(getChildrenCalls, ['root', 'root']); twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; @@ -171,8 +149,8 @@ suite('AsyncDataTree', function () { assert(hasClass(twistie, 'collapsed')); assert(tree.getNode().children[0].collapsed); - _('a').children = []; - await tree.updateChildren(root); + model.get('a').children = []; + await tree.updateChildren(model.root); assert.deepStrictEqual(getChildrenCalls, ['root', 'root', 'root']); twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; @@ -180,8 +158,8 @@ suite('AsyncDataTree', function () { assert(!hasClass(twistie, 'collapsed')); assert(tree.getNode().children[0].collapsed); - _('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; - await tree.updateChildren(root); + model.get('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; + await tree.updateChildren(model.root); assert.deepStrictEqual(getChildrenCalls, ['root', 'root', 'root', 'root']); twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; @@ -192,26 +170,6 @@ suite('AsyncDataTree', function () { test('issue #67722 - once resolved, refreshed collapsed nodes should only get children when expanded', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; const getChildrenCalls: string[] = []; const dataSource = new class implements IAsyncDataSource { @@ -224,131 +182,66 @@ suite('AsyncDataTree', function () { } }; - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a', children: [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }] }] - }; + }); - const _: (id: string) => Element = find.bind(null, root.children); - - const tree = new AsyncDataTree('test', container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); tree.layout(200); - await tree.setInput(root); - assert(tree.getNode(_('a')).collapsed); + await tree.setInput(model.root); + assert(tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root']); - await tree.expand(_('a')); - assert(!tree.getNode(_('a')).collapsed); + await tree.expand(model.get('a')); + assert(!tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root', 'a']); - tree.collapse(_('a')); - assert(tree.getNode(_('a')).collapsed); + tree.collapse(model.get('a')); + assert(tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root', 'a']); await tree.updateChildren(); - assert(tree.getNode(_('a')).collapsed); + assert(tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root', 'a', 'root'], 'a should not be refreshed, since it\' collapsed'); }); test('resolved collapsed nodes which lose children should lose twistie as well', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; - - const dataSource = new class implements IAsyncDataSource { - hasChildren(element: Element): boolean { - return !!element.children && element.children.length > 0; - } - getChildren(element: Element): Promise { - return Promise.resolve(element.children || []); - } - }; - - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a', children: [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }] }] - }; + }); - const _: (id: string) => Element = find.bind(null, root.children); - - const tree = new AsyncDataTree('test', container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], new DataSource(), { identityProvider: new IdentityProvider() }); tree.layout(200); - await tree.setInput(root); - await tree.expand(_('a')); + await tree.setInput(model.root); + await tree.expand(model.get('a')); let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; assert(hasClass(twistie, 'collapsible')); assert(!hasClass(twistie, 'collapsed')); - assert(!tree.getNode(_('a')).collapsed); + assert(!tree.getNode(model.get('a')).collapsed); - tree.collapse(_('a')); - _('a').children = []; - await tree.updateChildren(root); + tree.collapse(model.get('a')); + model.get('a').children = []; + await tree.updateChildren(model.root); twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; assert(!hasClass(twistie, 'collapsible')); assert(!hasClass(twistie, 'collapsed')); - assert(tree.getNode(_('a')).collapsed); + assert(tree.getNode(model.get('a')).collapsed); }); test('support default collapse state per element', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; const getChildrenCalls: string[] = []; const dataSource = new class implements IAsyncDataSource { @@ -361,22 +254,139 @@ suite('AsyncDataTree', function () { } }; - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a', children: [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }] }] - }; + }); - const _: (id: string) => Element = find.bind(null, root.children); - - const tree = new AsyncDataTree('test', container, delegate, [renderer], dataSource, { + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { collapseByDefault: el => el.id !== 'a' }); tree.layout(200); - await tree.setInput(root); - assert(!tree.getNode(_('a')).collapsed); + await tree.setInput(model.root); + assert(!tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root', 'a']); }); + + test('issue #80098 - concurrent refresh and expand', async () => { + const container = document.createElement('div'); + + const calls: Function[] = []; + const dataSource = new class implements IAsyncDataSource { + hasChildren(element: Element): boolean { + return !!element.children && element.children.length > 0; + } + getChildren(element: Element): Promise { + return new Promise(c => calls.push(() => c(element.children))); + } + }; + + const model = new Model({ + id: 'root', + children: [{ + id: 'a', children: [{ + id: 'aa' + }] + }] + }); + + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); + tree.layout(200); + + const pSetInput = tree.setInput(model.root); + calls.pop()!(); // resolve getChildren(root) + await pSetInput; + + const pUpdateChildrenA = tree.updateChildren(model.get('a')); + const pExpandA = tree.expand(model.get('a')); + assert.equal(calls.length, 1, 'expand(a) still hasn\'t called getChildren(a)'); + + calls.pop()!(); + assert.equal(calls.length, 0, 'no pending getChildren calls'); + + await pUpdateChildrenA; + assert.equal(calls.length, 0, 'expand(a) should not have forced a second refresh'); + + const result = await pExpandA; + assert.equal(result, true, 'expand(a) should be done'); + }); + + test('issue #80098 - first expand should call getChildren', async () => { + const container = document.createElement('div'); + + const calls: Function[] = []; + const dataSource = new class implements IAsyncDataSource { + hasChildren(element: Element): boolean { + return !!element.children && element.children.length > 0; + } + getChildren(element: Element): Promise { + return new Promise(c => calls.push(() => c(element.children))); + } + }; + + const model = new Model({ + id: 'root', + children: [{ + id: 'a', children: [{ + id: 'aa' + }] + }] + }); + + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); + tree.layout(200); + + const pSetInput = tree.setInput(model.root); + calls.pop()!(); // resolve getChildren(root) + await pSetInput; + + const pExpandA = tree.expand(model.get('a')); + assert.equal(calls.length, 1, 'expand(a) should\'ve called getChildren(a)'); + + let race = await Promise.race([pExpandA.then(() => 'expand'), timeout(1).then(() => 'timeout')]); + assert.equal(race, 'timeout', 'expand(a) should not be yet done'); + + calls.pop()!(); + assert.equal(calls.length, 0, 'no pending getChildren calls'); + + 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/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..5fead4265ff 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,40 @@ + + + + + + + - + + + 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-browser/workbench/workbench.js b/src/vs/code/electron-browser/workbench/workbench.js index 22d5dbe329c..2a2c6981c7d 100644 --- a/src/vs/code/electron-browser/workbench/workbench.js +++ b/src/vs/code/electron-browser/workbench/workbench.js @@ -49,7 +49,7 @@ bootstrapWindow.load([ * @param {{ * partsSplashPath?: string, * highContrast?: boolean, - * extensionDevelopmentPath?: string | string[], + * extensionDevelopmentPath?: string[], * folderUri?: object, * workspace?: object * }} configuration diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index cf63cbaf3e2..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'; @@ -56,7 +56,6 @@ import { serve as serveDriver } from 'vs/platform/driver/electron-main/driver'; import { IMenubarService } from 'vs/platform/menubar/node/menubar'; import { MenubarService } from 'vs/platform/menubar/electron-main/menubarService'; import { MenubarChannel } from 'vs/platform/menubar/node/menubarIpc'; -import { hasArgs } from 'vs/platform/environment/node/argv'; import { RunOnceScheduler } from 'vs/base/common/async'; import { registerContextMenuListener } from 'vs/base/parts/contextmenu/electron-main/contextmenu'; import { homedir } from 'os'; @@ -580,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, @@ -616,9 +616,9 @@ export class CodeApplication extends Disposable { // Open our first window const macOpenFiles: string[] = (global).macOpenFiles; const context = !!process.env['VSCODE_CLI'] ? OpenContext.CLI : OpenContext.DESKTOP; - const hasCliArgs = hasArgs(args._); - const hasFolderURIs = hasArgs(args['folder-uri']); - const hasFileURIs = hasArgs(args['file-uri']); + const hasCliArgs = args._.length; + const hasFolderURIs = !!args['folder-uri']; + const hasFileURIs = !!args['file-uri']; const noRecentEntry = args['skip-add-to-recently-opened'] === true; const waitMarkerFileURI = args.wait && args.waitMarkerFilePath ? URI.file(args.waitMarkerFilePath) : undefined; diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index c6d2f29b1ba..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'; @@ -32,7 +32,7 @@ const RUN_TEXTMATE_IN_WORKER = false; export interface IWindowCreationOptions { state: IWindowState; - extensionDevelopmentPath?: string | string[]; + extensionDevelopmentPath?: string[]; isExtensionTestHost?: boolean; } @@ -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/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index c7cdbd794e0..d4b330e55c5 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -12,7 +12,6 @@ import { IBackupMainService, IEmptyWindowBackupInfo } from 'vs/platform/backup/c import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { IStateService } from 'vs/platform/state/common/state'; import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window'; -import { hasArgs, asArray } from 'vs/platform/environment/node/argv'; import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter } from 'electron'; import { parseLineAndColumnAware } from 'vs/code/node/paths'; import { ILifecycleService, UnloadReason, LifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; @@ -450,7 +449,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Make sure to pass focus to the most relevant of the windows if we open multiple if (usedWindows.length > 1) { - const focusLastActive = this.windowsState.lastActiveWindow && !openConfig.forceEmpty && !hasArgs(openConfig.cli._) && !hasArgs(openConfig.cli['file-uri']) && !hasArgs(openConfig.cli['folder-uri']) && !(openConfig.urisToOpen && openConfig.urisToOpen.length); + const focusLastActive = this.windowsState.lastActiveWindow && !openConfig.forceEmpty && openConfig.cli._.length && !openConfig.cli['file-uri'] && !openConfig.cli['folder-uri'] && !(openConfig.urisToOpen && openConfig.urisToOpen.length); let focusLastOpened = true; let focusLastWindow = true; @@ -811,7 +810,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } // Extract paths: from CLI - else if (hasArgs(openConfig.cli._) || hasArgs(openConfig.cli['folder-uri']) || hasArgs(openConfig.cli['file-uri'])) { + else if (openConfig.cli._.length || openConfig.cli['folder-uri'] || openConfig.cli['file-uri']) { windowsToOpen = this.doExtractPathsFromCLI(openConfig.cli); isCommandLineOrAPICall = true; } @@ -885,31 +884,36 @@ export class WindowsManager extends Disposable implements IWindowsMainService { const parseOptions: IPathParseOptions = { ignoreFileNotFound: true, gotoLineMode: cli.goto, remoteAuthority: cli.remote || undefined }; // folder uris - const folderUris = asArray(cli['folder-uri']); - for (let f of folderUris) { - const folderUri = this.argToUri(f); - if (folderUri) { - const path = this.parseUri({ folderUri }, parseOptions); - if (path) { - pathsToOpen.push(path); + const folderUris = cli['folder-uri']; + if (folderUris) { + for (let f of folderUris) { + const folderUri = this.argToUri(f); + if (folderUri) { + const path = this.parseUri({ folderUri }, parseOptions); + if (path) { + pathsToOpen.push(path); + } } } } + // file uris - const fileUris = asArray(cli['file-uri']); - for (let f of fileUris) { - const fileUri = this.argToUri(f); - if (fileUri) { - const path = this.parseUri(hasWorkspaceFileExtension(f) ? { workspaceUri: fileUri } : { fileUri }, parseOptions); - if (path) { - pathsToOpen.push(path); + const fileUris = cli['file-uri']; + if (fileUris) { + for (let f of fileUris) { + const fileUri = this.argToUri(f); + if (fileUri) { + const path = this.parseUri(hasWorkspaceFileExtension(f) ? { workspaceUri: fileUri } : { fileUri }, parseOptions); + if (path) { + pathsToOpen.push(path); + } } } } // folder or file paths - const cliArgs = asArray(cli._); + const cliArgs = cli._; for (let cliArg of cliArgs) { const path = this.parsePath(cliArg, parseOptions); if (path) { @@ -1166,7 +1170,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { return { openFolderInNewWindow: !!openFolderInNewWindow, openFilesInNewWindow }; } - openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string | string[], openConfig: IOpenConfiguration): void { + openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): void { // Reload an existing extension development host window on the same path // We currently do not allow more than one extension development window @@ -1178,8 +1182,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService { return; } - let folderUris = asArray(openConfig.cli['folder-uri']); - let fileUris = asArray(openConfig.cli['file-uri']); + let folderUris = openConfig.cli['folder-uri'] || []; + let fileUris = openConfig.cli['file-uri'] || []; let cliArgs = openConfig.cli._; // Fill in previously opened workspace unless an explicit path is provided and we are not unit testing @@ -1203,10 +1207,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } } - if (!Array.isArray(extensionDevelopmentPath)) { - extensionDevelopmentPath = [extensionDevelopmentPath]; - } - let authority = ''; for (let p of extensionDevelopmentPath) { if (p.match(/^[a-zA-Z][a-zA-Z0-9\+\-\.]+:/)) { 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/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index ee828c29374..94bb62a7518 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -83,23 +83,14 @@ export class Main { async run(argv: ParsedArgs): Promise { if (argv['install-source']) { await this.setInstallSource(argv['install-source']); - } else if (argv['list-extensions']) { await this.listExtensions(!!argv['show-versions'], argv['category']); - } else if (argv['install-extension']) { - const arg = argv['install-extension']; - const args: string[] = typeof arg === 'string' ? [arg] : arg; - await this.installExtensions(args, !!argv['force']); - + await this.installExtensions(argv['install-extension'], !!argv['force']); } else if (argv['uninstall-extension']) { - const arg = argv['uninstall-extension']; - const ids: string[] = typeof arg === 'string' ? [arg] : arg; - await this.uninstallExtension(ids); + await this.uninstallExtension(argv['uninstall-extension']); } else if (argv['locate-extension']) { - const arg = argv['locate-extension']; - const ids: string[] = typeof arg === 'string' ? [arg] : arg; - await this.locateExtension(ids); + await this.locateExtension(argv['locate-extension']); } else if (argv['telemetry']) { console.log(buildTelemetryMessage(this.environmentService.appRoot, this.environmentService.extensionsPath ? this.environmentService.extensionsPath : undefined)); } diff --git a/src/vs/code/node/windowsFinder.ts b/src/vs/code/node/windowsFinder.ts index dc4b62e41ff..03e836c4827 100644 --- a/src/vs/code/node/windowsFinder.ts +++ b/src/vs/code/node/windowsFinder.ts @@ -14,7 +14,7 @@ export interface ISimpleWindow { openedWorkspace?: IWorkspaceIdentifier; openedFolderUri?: URI; - extensionDevelopmentPath?: string | string[]; + extensionDevelopmentPath?: string[]; lastFocusTime: number; } @@ -95,30 +95,17 @@ export function findWindowOnWorkspace(windows: W[], wor return null; } -export function findWindowOnExtensionDevelopmentPath(windows: W[], extensionDevelopmentPath: string | string[]): W | null { +export function findWindowOnExtensionDevelopmentPath(windows: W[], extensionDevelopmentPaths: string[]): W | null { const matches = (uriString: string): boolean => { - if (Array.isArray(extensionDevelopmentPath)) { - return extensionDevelopmentPath.some(p => extpath.isEqual(p, uriString, !platform.isLinux /* ignorecase */)); - } else if (extensionDevelopmentPath) { - return extpath.isEqual(extensionDevelopmentPath, uriString, !platform.isLinux /* ignorecase */); - } - return false; + return extensionDevelopmentPaths.some(p => extpath.isEqual(p, uriString, !platform.isLinux /* ignorecase */)); }; for (const window of windows) { // match on extension development path. The path can be one or more paths or uri strings, using paths.isEqual is not 100% correct but good enough - - if (window.extensionDevelopmentPath) { - if (Array.isArray(window.extensionDevelopmentPath)) { - if (window.extensionDevelopmentPath.some(p => matches(p))) { - return window; - } - } else if (window.extensionDevelopmentPath) { - if (matches(window.extensionDevelopmentPath)) { - return window; - } - } + const currPaths = window.extensionDevelopmentPath; + if (currPaths && currPaths.some(p => matches(p))) { + return window; } } 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 193ff840ac4..94ed9e159cb 100644 --- a/src/vs/editor/browser/controller/coreCommands.ts +++ b/src/vs/editor/browser/controller/coreCommands.ts @@ -294,7 +294,7 @@ export namespace CoreNavigationCommands { CursorMoveCommands.moveTo(cursors.context, cursors.getPrimaryCursor(), this._inSelectionMode, args.position, args.viewPosition) ] ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -322,7 +322,7 @@ export namespace CoreNavigationCommands { toViewLineNumber: result.toLineNumber, toViewVisualColumn: result.toVisualColumn }); - cursors.reveal(true, (result.reversed ? RevealTarget.TopMost : RevealTarget.BottomMost), ScrollType.Smooth); + cursors.reveal(args.source, true, (result.reversed ? RevealTarget.TopMost : RevealTarget.BottomMost), ScrollType.Smooth); } protected abstract _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult; @@ -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); } }); @@ -492,7 +488,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, CursorMoveCommands.move(cursors.context, cursors.getAll(), args) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -831,7 +827,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, CursorMoveCommands.moveToBeginningOfLine(cursors.context, cursors.getAll(), this._inSelectionMode) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -880,7 +876,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, this._exec(cursors.context, cursors.getAll()) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } private _exec(context: CursorContext, cursors: CursorState[]): PartialCursorState[] { @@ -910,7 +906,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, CursorMoveCommands.moveToEndOfLine(cursors.context, cursors.getAll(), this._inSelectionMode) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -959,7 +955,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, this._exec(cursors.context, cursors.getAll()) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } private _exec(context: CursorContext, cursors: CursorState[]): PartialCursorState[] { @@ -990,7 +986,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, CursorMoveCommands.moveToBeginningOfBuffer(cursors.context, cursors.getAll(), this._inSelectionMode) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -1034,7 +1030,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, CursorMoveCommands.moveToEndOfBuffer(cursors.context, cursors.getAll(), this._inSelectionMode) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -1253,7 +1249,7 @@ export namespace CoreNavigationCommands { CursorMoveCommands.word(cursors.context, cursors.getPrimaryCursor(), this._inSelectionMode, args.position) ] ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } } @@ -1313,7 +1309,7 @@ export namespace CoreNavigationCommands { CursorMoveCommands.line(cursors.context, cursors.getPrimaryCursor(), this._inSelectionMode, args.position, args.viewPosition) ] ); - cursors.reveal(false, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, false, RevealTarget.Primary, ScrollType.Smooth); } } @@ -1385,7 +1381,7 @@ export namespace CoreNavigationCommands { CursorChangeReason.Explicit, CursorMoveCommands.expandLineSelection(cursors.context, cursors.getAll()) ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } }); @@ -1413,7 +1409,7 @@ export namespace CoreNavigationCommands { CursorMoveCommands.cancelSelection(cursors.context, cursors.getPrimaryCursor()) ] ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } }); @@ -1440,7 +1436,7 @@ export namespace CoreNavigationCommands { cursors.getPrimaryCursor() ] ); - cursors.reveal(true, RevealTarget.Primary, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.Primary, ScrollType.Smooth); } }); @@ -1488,7 +1484,7 @@ export namespace CoreNavigationCommands { const viewRange = cursors.context.convertModelRangeToViewRange(range); - cursors.revealRange(false, viewRange, revealAt, ScrollType.Smooth); + cursors.revealRange(args.source, false, viewRange, revealAt, ScrollType.Smooth); } }); 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 c1a41a4981f..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'); @@ -280,6 +283,7 @@ export class TextAreaHandler extends ViewPart { const column = this._selections[0].startColumn; this._context.privateViewEventBus.emit(new viewEvents.ViewRevealRangeRequestEvent( + 'keyboard', new Range(lineNumber, column, lineNumber, column), viewEvents.VerticalRevealType.Simple, true, @@ -340,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; @@ -367,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; } @@ -544,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 580311d7691..eb524a41b69 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLines.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLines.ts @@ -12,12 +12,14 @@ import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/v import { DomReadingContext, ViewLine, ViewLineOptions } from 'vs/editor/browser/viewParts/lines/viewLine'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; +import { Selection } from 'vs/editor/common/core/selection'; import { ScrollType } from 'vs/editor/common/editorCommon'; import { HorizontalRange, IViewLines, LineVisibleRanges } from 'vs/editor/common/view/renderingContext'; 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 { @@ -71,7 +73,8 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, private _typicalHalfwidthCharacterWidth: number; private _isViewportWrapping: boolean; private _revealHorizontalRightPadding: number; - private _scrollOff: number; + private _selections: Selection[]; + private _cursorSurroundingLines: number; private _canUseLayerHinting: boolean; private _viewLineOptions: ViewLineOptions; @@ -90,18 +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; @@ -135,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; } @@ -188,6 +185,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, return false; } public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { + this._selections = e.selections; const rendStartLineNumber = this._visibleLines.getStartLineNumber(); const rendEndLineNumber = this._visibleLines.getEndLineNumber(); let r = false; @@ -223,7 +221,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, public onRevealRangeRequest(e: viewEvents.ViewRevealRangeRequestEvent): boolean { // Using the future viewport here in order to handle multiple // incoming reveal range requests that might all desire to be animated - const desiredScrollTop = this._computeScrollTopToRevealRange(this._context.viewLayout.getFutureViewport(), e.range, e.verticalType); + const desiredScrollTop = this._computeScrollTopToRevealRange(this._context.viewLayout.getFutureViewport(), e.source, e.range, e.verticalType); // validate the new desired scroll top let newScrollPosition = this._context.viewLayout.validateScrollPosition({ scrollTop: desiredScrollTop }); @@ -589,7 +587,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, } } - private _computeScrollTopToRevealRange(viewport: Viewport, range: Range, verticalType: viewEvents.VerticalRevealType): number { + private _computeScrollTopToRevealRange(viewport: Viewport, source: string, range: Range, verticalType: viewEvents.VerticalRevealType): number { const viewportStartY = viewport.top; const viewportHeight = viewport.height; const viewportEndY = viewportStartY + viewportHeight; @@ -600,9 +598,16 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, boxStartY = this._context.viewLayout.getVerticalOffsetForLineNumber(range.startLineNumber); boxEndY = this._context.viewLayout.getVerticalOffsetForLineNumber(range.endLineNumber) + this._lineHeight; - const context = Math.min((viewportHeight / this._lineHeight) / 2, this._scrollOff); - boxStartY -= context * this._lineHeight; - boxEndY += Math.max(0, (context - 1)) * this._lineHeight; + const shouldIgnoreScrollOff = source === 'mouse' && ( + this._selections.length > 1 // scroll off might trigger scrolling and mess up with multi cursor + || (this._selections.length > 0 && this._selections[0].isEmpty()) // we don't want to single click triggering selection + ); + + if (!shouldIgnoreScrollOff) { + const context = Math.min((viewportHeight / this._lineHeight) / 2, this._cursorSurroundingLines); + boxStartY -= context * this._lineHeight; + boxEndY += Math.max(0, (context - 1)) * this._lineHeight; + } if (verticalType === viewEvents.VerticalRevealType.Simple || verticalType === viewEvents.VerticalRevealType.Bottom) { // Reveal one line more when the last line would be covered by the scrollbar - arrow down case or revealing a line explicitly at bottom 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 1182f2ee8ab..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; @@ -517,6 +518,7 @@ export class Minimap extends ViewPart { lineNumber = Math.min(lineNumber, this._context.model.getLineCount()); this._context.privateViewEventBus.emit(new viewEvents.ViewRevealRangeRequestEvent( + 'mouse', new Range(lineNumber, 1, lineNumber, 1), viewEvents.VerticalRevealType.Center, false, 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 0ac879ee78a..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(); } @@ -526,7 +532,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE const validatedModelRange = this._modelData.model.validateRange(modelRange); const viewRange = this._modelData.viewModel.coordinatesConverter.convertModelRangeToViewRange(validatedModelRange); - this._modelData.cursor.emitCursorRevealRange(viewRange, verticalType, revealHorizontal, scrollType); + this._modelData.cursor.emitCursorRevealRange('api', viewRange, verticalType, revealHorizontal, scrollType); } public revealLine(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { @@ -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 fa0e688d696..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'; @@ -79,7 +79,7 @@ class VisualEditorState { constructor( private _contextMenuService: IContextMenuService, - private _clipboardService: IClipboardService + private _clipboardService: IClipboardService | null ) { this._zones = []; this.inlineDiffMargins = []; @@ -129,7 +129,7 @@ class VisualEditorState { this._zones.push(zoneId); this._zonesMap[String(zoneId)] = true; - if (newDecorations.zones[i].diff && viewZone.marginDomNode) { + if (newDecorations.zones[i].diff && viewZone.marginDomNode && this._clipboardService) { this.inlineDiffMargins.push(new InlineDiffMargin(zoneId, viewZone.marginDomNode, editor, newDecorations.zones[i].diff!, this._contextMenuService, this._clipboardService)); } } @@ -213,7 +213,8 @@ 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, @IInstantiationService instantiationService: IInstantiationService, @@ -221,7 +222,6 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE @IThemeService themeService: IThemeService, @INotificationService notificationService: INotificationService, @IContextMenuService contextMenuService: IContextMenuService, - @IClipboardService clipboardService: IClipboardService ) { super(); @@ -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 2f36d8e9765..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(), editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService, clipboardService); + 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 7933869ab4f..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) { @@ -122,15 +123,12 @@ export class InlineDiffMargin extends Disposable { })); } - this._register(dom.addStandardDisposableListener(this._diffActions, 'mousedown', e => { - const { top, height } = dom.getDomNodePagePosition(this._diffActions); - let pad = Math.floor(lineHeight / 3); - e.preventDefault(); + const showContextMenu = (x: number, y: number) => { this._contextMenuService.showContextMenu({ getAnchor: () => { return { - x: e.posx, - y: top + height + pad + x, + y }; }, getActions: () => { @@ -141,6 +139,15 @@ export class InlineDiffMargin extends Disposable { }, autoSelectFirstItem: true }); + }; + + this._register(dom.addStandardDisposableListener(this._diffActions, 'mousedown', e => { + const { top, height } = dom.getDomNodePagePosition(this._diffActions); + let pad = Math.floor(lineHeight / 3); + e.preventDefault(); + + showContextMenu(e.posx, top + height + pad); + })); this._register(editor.onMouseMove((e: editorBrowser.IEditorMouseEvent) => { @@ -157,6 +164,22 @@ export class InlineDiffMargin extends Disposable { this.visibility = false; } })); + + this._register(editor.onMouseDown((e: editorBrowser.IEditorMouseEvent) => { + if (!e.event.rightButton) { + return; + } + + if (e.target.type === editorBrowser.MouseTargetType.CONTENT_VIEW_ZONE || e.target.type === editorBrowser.MouseTargetType.GUTTER_VIEW_ZONE) { + const viewZoneId = e.target.detail.viewZoneId; + + if (viewZoneId === this._viewZoneId) { + e.event.preventDefault(); + currentLineNumberOffset = this._updateLightBulbPosition(this._marginDomNode, e.event.browserEvent.y, lineHeight); + showContextMenu(e.event.posx, e.event.posy + lineHeight); + } + } + })); } private _updateLightBulbPosition(marginDomNode: HTMLElement, y: number, lineHeight: number): number { 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 b76218fe99b..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++) { @@ -295,12 +296,12 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._columnSelectData = columnSelectData; } - public reveal(horizontal: boolean, target: RevealTarget, scrollType: editorCommon.ScrollType): void { - this._revealRange(target, viewEvents.VerticalRevealType.Simple, horizontal, scrollType); + public reveal(source: string, horizontal: boolean, target: RevealTarget, scrollType: editorCommon.ScrollType): void { + this._revealRange(source, target, viewEvents.VerticalRevealType.Simple, horizontal, scrollType); } - public revealRange(revealHorizontal: boolean, viewRange: Range, verticalType: viewEvents.VerticalRevealType, scrollType: editorCommon.ScrollType) { - this.emitCursorRevealRange(viewRange, verticalType, revealHorizontal, scrollType); + public revealRange(source: string, revealHorizontal: boolean, viewRange: Range, verticalType: viewEvents.VerticalRevealType, scrollType: editorCommon.ScrollType) { + this.emitCursorRevealRange(source, viewRange, verticalType, revealHorizontal, scrollType); } public scrollTo(desiredScrollTop: number): void { @@ -371,7 +372,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { } this.setStates('restoreState', CursorChangeReason.NotSet, CursorState.fromModelSelections(desiredSelections)); - this.reveal(true, RevealTarget.Primary, editorCommon.ScrollType.Immediate); + this.reveal('restoreState', true, RevealTarget.Primary, editorCommon.ScrollType.Immediate); } private _onModelContentChanged(hadFlushEvent: boolean): void { @@ -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 { @@ -543,7 +544,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { return true; } - private _revealRange(revealTarget: RevealTarget, verticalType: viewEvents.VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void { + private _revealRange(source: string, revealTarget: RevealTarget, verticalType: viewEvents.VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void { const viewPositions = this._cursors.getViewPositions(); let viewPosition = viewPositions[0]; @@ -568,13 +569,13 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { } const viewRange = new Range(viewPosition.lineNumber, viewPosition.column, viewPosition.lineNumber, viewPosition.column); - this.emitCursorRevealRange(viewRange, verticalType, revealHorizontal, scrollType); + this.emitCursorRevealRange(source, viewRange, verticalType, revealHorizontal, scrollType); } - public emitCursorRevealRange(viewRange: Range, verticalType: viewEvents.VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType) { + public emitCursorRevealRange(source: string, viewRange: Range, verticalType: viewEvents.VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType) { try { const eventsCollector = this._beginEmit(); - eventsCollector.emit(new viewEvents.ViewRevealRangeRequestEvent(viewRange, verticalType, revealHorizontal, scrollType)); + eventsCollector.emit(new viewEvents.ViewRevealRangeRequestEvent(source, viewRange, verticalType, revealHorizontal, scrollType)); } finally { this._endEmit(); } @@ -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); @@ -748,7 +749,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._validateAutoClosedActions(); if (this._emitStateChangedIfNecessary(source, cursorChangeReason, oldState)) { - this._revealRange(RevealTarget.Primary, viewEvents.VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth); + this._revealRange(source, RevealTarget.Primary, viewEvents.VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth); } } diff --git a/src/vs/editor/common/controller/cursorCommon.ts b/src/vs/editor/common/controller/cursorCommon.ts index 87c3878b61c..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'; @@ -55,8 +55,8 @@ export interface ICursors { setColumnSelectData(columnSelectData: IColumnSelectData): void; setStates(source: string, reason: CursorChangeReason, states: PartialCursorState[] | null): void; - reveal(horizontal: boolean, target: RevealTarget, scrollType: ScrollType): void; - revealRange(revealHorizontal: boolean, viewRange: Range, verticalType: VerticalRevealType, scrollType: ScrollType): void; + reveal(source: string, horizontal: boolean, target: RevealTarget, scrollType: ScrollType): void; + revealRange(source: string, revealHorizontal: boolean, viewRange: Range, verticalType: VerticalRevealType, scrollType: ScrollType): void; scrollTo(desiredScrollTop: number): void; @@ -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/model/textModelSearch.ts b/src/vs/editor/common/model/textModelSearch.ts index ec2bb71ec30..f350079ee69 100644 --- a/src/vs/editor/common/model/textModelSearch.ts +++ b/src/vs/editor/common/model/textModelSearch.ts @@ -45,7 +45,8 @@ export class SearchParams { matchCase: this.matchCase, wholeWord: false, multiline: multiline, - global: true + global: true, + unicode: true }); } catch (err) { return null; 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 962579d3f0f..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); } } @@ -198,7 +180,13 @@ export class ViewRevealRangeRequestEvent { public readonly scrollType: ScrollType; - constructor(range: Range, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: ScrollType) { + /** + * Source of the call that caused the event. + */ + readonly source: string; + + constructor(source: string, range: Range, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: ScrollType) { + this.source = source; this.range = range; this.verticalType = verticalType; this.revealHorizontal = revealHorizontal; 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/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/documentSymbols/outlineModel.ts b/src/vs/editor/contrib/documentSymbols/outlineModel.ts index e5004629993..8059fdbdcfd 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineModel.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineModel.ts @@ -386,6 +386,9 @@ export class OutlineModel extends TreeElement { protected constructor(readonly textModel: ITextModel) { super(); + + this.id = 'root'; + this.parent = undefined; } adopt(): OutlineModel { 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 faca23f0a55..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; @@ -467,7 +468,7 @@ export class FindModelBoundToEditorModel { let searchRegex = searchData.regex; if (!searchRegex.multiline) { - let mod = 'm'; + let mod = 'mu'; if (searchRegex.ignoreCase) { mod += 'i'; } diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index 383f158c1de..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'; @@ -67,6 +67,7 @@ let FIND_ALL_CONTROLS_WIDTH = 17/** Find Input margin-left */ + (MAX_MATCHES_COU const FIND_INPUT_AREA_HEIGHT = 33; // The height of Find Widget when Replace Input is not visible. const ctrlEnterReplaceAllWarningPromptedKey = 'ctrlEnterReplaceAll.windows.donotask'; +const ctrlKeyMod = (platform.isMacintosh ? KeyMod.WinCtrl : KeyMod.CtrlCmd); export class FindWidgetViewZone implements IViewZone { public readonly afterLineNumber: number; public heightInPx: number; @@ -175,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(); @@ -238,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. } @@ -315,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(); @@ -456,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); } @@ -466,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; @@ -487,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); @@ -534,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(); @@ -562,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; @@ -642,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 @@ -652,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; @@ -775,7 +777,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } private _onFindInputKeyDown(e: IKeyboardEvent): void { - if (e.equals(KeyMod.WinCtrl | KeyCode.Enter)) { + if (e.equals(ctrlKeyMod | KeyCode.Enter)) { const inputElement = this._findInput.inputBox.inputElement; const start = inputElement.selectionStart; const end = inputElement.selectionEnd; @@ -817,7 +819,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } private _onReplaceInputKeyDown(e: IKeyboardEvent): void { - if (e.equals(KeyMod.WinCtrl | KeyCode.Enter)) { + if (e.equals(ctrlKeyMod | KeyCode.Enter)) { if (platform.isWindows && platform.isNative && !this._ctrlEnterReplaceAllWarningPrompted) { // this is the first time when users press Ctrl + Enter to replace all this._notificationService.info( @@ -835,7 +837,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas const end = inputElement.selectionEnd; const content = inputElement.value; - if (start && end) { + if (start !== null && end !== null) { const value = content.substr(0, start) + '\n' + content.substr(end); this._replaceInput.inputBox.value = value; inputElement.setSelectionRange(start + 1, start + 1); @@ -1187,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 { /** @@ -1208,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.css b/src/vs/editor/contrib/hover/hover.css index 06639005192..0906f2aed72 100644 --- a/src/vs/editor/contrib/hover/hover.css +++ b/src/vs/editor/contrib/hover/hover.css @@ -55,9 +55,13 @@ margin-bottom: 0; } +/* MarkupContent Layout */ .monaco-editor-hover ul { padding-left: 20px; } +.monaco-editor-hover ol { + padding-left: 20px; +} .monaco-editor-hover li > p { margin-bottom: 0; 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 ec0925af31a..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 { @@ -72,7 +73,7 @@ export class InsertCursorAbove extends EditorAction { CursorChangeReason.Explicit, CursorMoveCommands.addCursorUp(context, cursors.getAll(), useLogicalLine) ); - cursors.reveal(true, RevealTarget.TopMost, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.TopMost, ScrollType.Smooth); } } @@ -121,7 +122,7 @@ export class InsertCursorBelow extends EditorAction { CursorChangeReason.Explicit, CursorMoveCommands.addCursorDown(context, cursors.getAll(), useLogicalLine) ); - cursors.reveal(true, RevealTarget.BottomMost, ScrollType.Smooth); + cursors.reveal(args.source, true, RevealTarget.BottomMost, ScrollType.Smooth); } } @@ -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 { @@ -1053,4 +1054,4 @@ registerEditorAction(MoveSelectionToPreviousFindMatchAction); registerEditorAction(SelectHighlightsAction); registerEditorAction(CompatChangeAll); registerEditorAction(InsertCursorAtEndOfLineSelected); -registerEditorAction(InsertCursorAtTopOfLineSelected); \ No newline at end of file +registerEditorAction(InsertCursorAtTopOfLineSelected); 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/referenceSearch/referencesWidget.ts b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts index cc6b12bca84..26eca18fb11 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts @@ -383,8 +383,11 @@ export class ReferenceWidget extends PeekViewWidget { }); this._tree.onDidOpen(e => { const aside = (e.browserEvent instanceof MouseEvent) && (e.browserEvent.ctrlKey || e.browserEvent.metaKey || e.browserEvent.altKey); - const goto = !e.browserEvent || ((e.browserEvent instanceof MouseEvent) && e.browserEvent.detail === 2); - + let goto = !e.browserEvent || ((e.browserEvent instanceof MouseEvent) && e.browserEvent.detail === 2); + if (e.browserEvent instanceof KeyboardEvent) { + // todo@joh make this a command + goto = true; + } if (aside) { onEvent(e.elements[0], 'side'); } else if (goto) { 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/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/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index a0115bd5528..481a63fec10 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -45,11 +45,13 @@ float: right; } -/* Details Layout */ +/* MarkupContent Layout */ .monaco-editor .suggest-widget > .details ul { padding-left: 20px; } - +.monaco-editor .suggest-widget > .details ol { + padding-left: 20px; +} /* Styles for Message element for when widget is loading or is empty */ .monaco-editor .suggest-widget > .message { 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 c076d21a0b3..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 { @@ -17,55 +18,53 @@ export abstract class WordDistance { distance() { return 0; } }; - static create(service: IEditorWorkerService, editor: ICodeEditor): Promise { + static async create(service: IEditorWorkerService, editor: ICodeEditor): Promise { - if (!editor.getConfiguration().contribInfo.suggest.localityBonus) { - return Promise.resolve(WordDistance.None); + if (!editor.getOption(EditorOption.suggest).localityBonus) { + return WordDistance.None; } if (!editor.hasModel()) { - return Promise.resolve(WordDistance.None); + return WordDistance.None; } const model = editor.getModel(); const position = editor.getPosition(); if (!service.canComputeWordRanges(model.uri)) { - return Promise.resolve(WordDistance.None); + return WordDistance.None; } - return new BracketSelectionRangeProvider().provideSelectionRanges(model, [position]).then(ranges => { - if (!ranges || ranges.length === 0 || ranges[0].length === 0) { - return WordDistance.None; - } - return service.computeWordRanges(model.uri, ranges[0][0].range).then(wordRanges => { - return new class extends WordDistance { - distance(anchor: IPosition, suggestion: CompletionItem) { - if (!wordRanges || !position.equals(editor.getPosition())) { - return 0; - } - if (suggestion.kind === CompletionItemKind.Keyword) { - return 2 << 20; - } - let word = suggestion.label; - let wordLines = wordRanges[word]; - if (isFalsyOrEmpty(wordLines)) { - return 2 << 20; - } - let idx = binarySearch(wordLines, Range.fromPositions(anchor), Range.compareRangesUsingStarts); - let bestWordRange = idx >= 0 ? wordLines[idx] : wordLines[Math.max(0, ~idx - 1)]; - let blockDistance = ranges.length; - for (const range of ranges[0]) { - if (!Range.containsRange(range.range, bestWordRange)) { - break; - } - blockDistance -= 1; - } - return blockDistance; + const ranges = await new BracketSelectionRangeProvider().provideSelectionRanges(model, [position]); + if (!ranges || ranges.length === 0 || ranges[0].length === 0) { + return WordDistance.None; + } + const wordRanges = await service.computeWordRanges(model.uri, ranges[0][0].range); + return new class extends WordDistance { + distance(anchor: IPosition, suggestion: CompletionItem) { + if (!wordRanges || !position.equals(editor.getPosition())) { + return 0; + } + if (suggestion.kind === CompletionItemKind.Keyword) { + return 2 << 20; + } + let word = suggestion.label; + let wordLines = wordRanges[word]; + if (isFalsyOrEmpty(wordLines)) { + return 2 << 20; + } + let idx = binarySearch(wordLines, Range.fromPositions(anchor), Range.compareRangesUsingStarts); + let bestWordRange = idx >= 0 ? wordLines[idx] : wordLines[Math.max(0, ~idx - 1)]; + let blockDistance = ranges.length; + for (const range of ranges[0]) { + if (!Range.containsRange(range.range, bestWordRange)) { + break; } - }; - }); - }); + blockDistance -= 1; + } + return blockDistance; + } + }; } abstract distance(anchor: IPosition, suggestion: CompletionItem): number; 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/standaloneCodeEditor.ts b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts index d64e0e6e2af..47d797f2519 100644 --- a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts @@ -23,7 +23,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -376,7 +376,7 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon @INotificationService notificationService: INotificationService, @IConfigurationService configurationService: IConfigurationService, @IContextMenuService contextMenuService: IContextMenuService, - @IClipboardService clipboardService: IClipboardService + @optional(IClipboardService) clipboardService: IClipboardService | null, ) { applyConfigurationValues(configurationService, options, true); options = options || {}; @@ -384,7 +384,7 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon options.theme = themeService.setTheme(options.theme); } - super(domElement, options, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService, clipboardService); + super(domElement, options, clipboardService, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService); this._contextViewService = contextViewService; this._configurationService = configurationService; diff --git a/src/vs/editor/standalone/browser/standaloneEditor.ts b/src/vs/editor/standalone/browser/standaloneEditor.ts index 280e00cbdf7..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'; @@ -38,7 +38,6 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { clearAllFontInfos } from 'vs/editor/browser/config/configuration'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; type Omit = Pick>; @@ -121,7 +120,7 @@ export function createDiffEditor(domElement: HTMLElement, options?: IDiffEditorC services.get(INotificationService), services.get(IConfigurationService), services.get(IContextMenuService), - services.get(IClipboardService) + null ); }); } @@ -352,6 +351,7 @@ export function createMonacoEditorAPI(): typeof monaco.editor { remeasureFonts: remeasureFonts, // enums + AccessibilitySupport: standaloneEnums.AccessibilitySupport, ScrollbarVisibility: standaloneEnums.ScrollbarVisibility, WrappingIndent: standaloneEnums.WrappingIndent, OverviewRulerLane: standaloneEnums.OverviewRulerLane, @@ -371,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/model/textModelSearch.test.ts b/src/vs/editor/test/common/model/textModelSearch.test.ts index 6476015cb5d..aa90e1c0c3f 100644 --- a/src/vs/editor/test/common/model/textModelSearch.test.ts +++ b/src/vs/editor/test/common/model/textModelSearch.test.ts @@ -611,25 +611,25 @@ suite('TextModelSearch', () => { }); test('parseSearchRequest non regex', () => { - assertParseSearchResult('foo', false, false, null, new SearchData(/foo/gi, null, null)); - assertParseSearchResult('foo', false, false, USUAL_WORD_SEPARATORS, new SearchData(/foo/gi, usualWordSeparators, null)); - assertParseSearchResult('foo', false, true, null, new SearchData(/foo/g, null, 'foo')); - assertParseSearchResult('foo', false, true, USUAL_WORD_SEPARATORS, new SearchData(/foo/g, usualWordSeparators, 'foo')); - assertParseSearchResult('foo\\n', false, false, null, new SearchData(/foo\\n/gi, null, null)); - assertParseSearchResult('foo\\\\n', false, false, null, new SearchData(/foo\\\\n/gi, null, null)); - assertParseSearchResult('foo\\r', false, false, null, new SearchData(/foo\\r/gi, null, null)); - assertParseSearchResult('foo\\\\r', false, false, null, new SearchData(/foo\\\\r/gi, null, null)); + assertParseSearchResult('foo', false, false, null, new SearchData(/foo/giu, null, null)); + assertParseSearchResult('foo', false, false, USUAL_WORD_SEPARATORS, new SearchData(/foo/giu, usualWordSeparators, null)); + assertParseSearchResult('foo', false, true, null, new SearchData(/foo/gu, null, 'foo')); + assertParseSearchResult('foo', false, true, USUAL_WORD_SEPARATORS, new SearchData(/foo/gu, usualWordSeparators, 'foo')); + assertParseSearchResult('foo\\n', false, false, null, new SearchData(/foo\\n/giu, null, null)); + assertParseSearchResult('foo\\\\n', false, false, null, new SearchData(/foo\\\\n/giu, null, null)); + assertParseSearchResult('foo\\r', false, false, null, new SearchData(/foo\\r/giu, null, null)); + assertParseSearchResult('foo\\\\r', false, false, null, new SearchData(/foo\\\\r/giu, null, null)); }); test('parseSearchRequest regex', () => { - assertParseSearchResult('foo', true, false, null, new SearchData(/foo/gi, null, null)); - assertParseSearchResult('foo', true, false, USUAL_WORD_SEPARATORS, new SearchData(/foo/gi, usualWordSeparators, null)); - assertParseSearchResult('foo', true, true, null, new SearchData(/foo/g, null, null)); - assertParseSearchResult('foo', true, true, USUAL_WORD_SEPARATORS, new SearchData(/foo/g, usualWordSeparators, null)); - assertParseSearchResult('foo\\n', true, false, null, new SearchData(/foo\n/gim, null, null)); - assertParseSearchResult('foo\\\\n', true, false, null, new SearchData(/foo\\n/gi, null, null)); - assertParseSearchResult('foo\\r', true, false, null, new SearchData(/foo\r/gim, null, null)); - assertParseSearchResult('foo\\\\r', true, false, null, new SearchData(/foo\\r/gi, null, null)); + assertParseSearchResult('foo', true, false, null, new SearchData(/foo/giu, null, null)); + assertParseSearchResult('foo', true, false, USUAL_WORD_SEPARATORS, new SearchData(/foo/giu, usualWordSeparators, null)); + assertParseSearchResult('foo', true, true, null, new SearchData(/foo/gu, null, null)); + assertParseSearchResult('foo', true, true, USUAL_WORD_SEPARATORS, new SearchData(/foo/gu, usualWordSeparators, null)); + assertParseSearchResult('foo\\n', true, false, null, new SearchData(/foo\n/gimu, null, null)); + assertParseSearchResult('foo\\\\n', true, false, null, new SearchData(/foo\\n/giu, null, null)); + assertParseSearchResult('foo\\r', true, false, null, new SearchData(/foo\r/gimu, null, null)); + assertParseSearchResult('foo\\\\r', true, false, null, new SearchData(/foo\\r/giu, null, null)); }); test('issue #53415. \W should match line break.', () => { @@ -721,6 +721,20 @@ suite('TextModelSearch', () => { ); }); + test('Simple find using unicode escape sequences', () => { + assertFindMatches( + regularText.join('\n'), + '\\u{0066}\\u006f\\u006F', true, false, null, + [ + [1, 14, 1, 17], + [1, 44, 1, 47], + [2, 22, 2, 25], + [2, 48, 2, 51], + [4, 59, 4, 62] + ] + ); + }); + test('isMultilineRegexSource', () => { assert(!isMultilineRegexSource('foo')); assert(!isMultilineRegexSource('')); 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/dialogs/common/dialogs.ts b/src/vs/platform/dialogs/common/dialogs.ts index f72f2276330..ab029f1944e 100644 --- a/src/vs/platform/dialogs/common/dialogs.ts +++ b/src/vs/platform/dialogs/common/dialogs.ts @@ -127,8 +127,6 @@ export const IDialogService = createDecorator('dialogService'); export interface IDialogOptions { cancelId?: number; detail?: string; - checkboxLabel?: string; - checkboxChecked?: boolean; } /** diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index cfb931c013e..f60b09ad56f 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -8,8 +8,8 @@ import { URI } from 'vs/base/common/uri'; export interface ParsedArgs { _: string[]; - 'folder-uri'?: string | string[]; - 'file-uri'?: string | string[]; + 'folder-uri'?: string[]; // undefined or array of 1 or more + 'file-uri'?: string[]; // undefined or array of 1 or more _urls?: string[]; help?: boolean; version?: boolean; @@ -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; @@ -36,7 +36,7 @@ export interface ParsedArgs { logExtensionHostCommunication?: boolean; 'extensions-dir'?: string; 'builtin-extensions-dir'?: string; - extensionDevelopmentPath?: string | string[]; // one or more local paths or URIs + extensionDevelopmentPath?: string[]; // // undefined or array of 1 or more local paths or URIs extensionTestsPath?: string; // either a local path or a URI 'extension-development-confirm-save'?: boolean; 'inspect-extensions'?: string; @@ -45,14 +45,14 @@ export interface ParsedArgs { 'inspect-search'?: string; 'inspect-brk-search'?: string; 'disable-extensions'?: boolean; - 'disable-extension'?: string | string[]; + 'disable-extension'?: string[]; // undefined or array of 1 or more 'list-extensions'?: boolean; 'show-versions'?: boolean; 'category'?: string; - 'install-extension'?: string | string[]; - 'uninstall-extension'?: string | string[]; - 'locate-extension'?: string | string[]; - 'enable-proposed-api'?: string | string[]; + 'install-extension'?: string[]; // undefined or array of 1 or more + 'uninstall-extension'?: string[]; // undefined or array of 1 or more + 'locate-extension'?: string[]; // undefined or array of 1 or more + 'enable-proposed-api'?: string[]; // undefined or array of 1 or more 'open-url'?: boolean; 'skip-getting-started'?: boolean; 'skip-release-notes'?: 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; @@ -76,7 +76,7 @@ export interface ParsedArgs { 'force'?: boolean; 'gitCredential'?: string; // node flags - 'js-flags'?: boolean; + 'js-flags'?: string; 'disable-gpu'?: boolean; 'nolazy'?: boolean; diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 5e22e54d396..e639efb6f59 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -20,103 +20,124 @@ const helpCategories = { t: localize('troubleshooting', "Troubleshooting") }; -export interface Option { - id: keyof ParsedArgs; - type: 'boolean' | '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.") }, + '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: '_', type: 'string' }, + 'extensions-dir': { type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") }, + '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") }, + '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.") }, -export function parseArgs(args: string[], isOptionSupported = (_: Option) => true): ParsedArgs { + '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' }, + '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-category-filter': { type: 'string' }, + 'trace-options': { type: 'string' }, + 'disable-inspect': { type: 'boolean' }, + + 'js-flags': { type: 'string' }, // chrome js flags + 'nolazy': { type: 'boolean' }, // node inspect + + _: { type: 'string[]' } // main arguments +}; + +export interface ErrorReporter { + onUnknownOption(id: string): void; + onMultipleValues(id: string, usedValue: string): void; +} + +const ignoringReporter: ErrorReporter = { + onUnknownOption: () => { }, + onMultipleValues: () => { } +}; + +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) { + const o = options[optionId]; + if (o.alias) { + alias[optionId] = o.alias; } - if (o.type === 'string') { - string.push(o.id); + if (o.type === 'string' || o.type === 'string[]') { + 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); } @@ -124,23 +145,51 @@ export function parseArgs(args: string[], isOptionSupported = (_: Option) => tru } // remote aliases to avoid confusion const parsedArgs = minimist(args, { string, boolean, alias }); - for (const o of options) { + + const cleanedArgs: any = {}; + + // 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]; } - if (o.deprecates && parsedArgs.hasOwnProperty(o.deprecates) && !parsedArgs[o.id]) { - parsedArgs[o.id] = parsedArgs[o.deprecates]; + + let val = parsedArgs[optionId]; + if (o.deprecates && parsedArgs.hasOwnProperty(o.deprecates)) { + if (!val) { + val = parsedArgs[o.deprecates]; + } delete parsedArgs[o.deprecates]; } + + if (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[optionId] = val; + } + delete parsedArgs[optionId]; } - // https://github.com/microsoft/vscode/issues/58177 - parsedArgs._ = parsedArgs._.filter(arg => arg.length > 0); + for (let key in parsedArgs) { + errorReporter.onUnknownOption(key); + } - return parsedArgs; + return cleanedArgs; } -function formatUsage(option: Option) { +function formatUsage(optionId: string, option: Option) { let args = ''; if (option.args) { if (Array.isArray(option.args)) { @@ -150,30 +199,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; } @@ -192,7 +248,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}`]; @@ -207,11 +263,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(''); @@ -224,32 +292,6 @@ export function buildVersionMessage(version: string | undefined, commit: string return `${version || localize('unknownVersion', "Unknown version")}\n${commit || localize('unknownCommit', "Unknown commit")}\n${process.arch}`; } -/** - * Converts an argument into an array - * @param arg a argument value. Can be undefined, an entry or an array - */ -export function asArray(arg: string | string[] | undefined): string[] { - if (arg) { - if (Array.isArray(arg)) { - return arg; - } - return [arg]; - } - return []; -} - -/** - * Returns whether an argument is present. - */ -export function hasArgs(arg: string | string[] | undefined): boolean { - if (arg) { - if (Array.isArray(arg)) { - return !!arg.length; - } - return true; - } - return false; -} export function addArg(argv: string[], ...args: string[]): string[] { const endOfArgsMarkerIndex = argv.indexOf('--'); diff --git a/src/vs/platform/environment/node/argvHelper.ts b/src/vs/platform/environment/node/argvHelper.ts index f2887c6191c..f656fa743b8 100644 --- a/src/vs/platform/environment/node/argvHelper.ts +++ b/src/vs/platform/environment/node/argvHelper.ts @@ -8,9 +8,19 @@ 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 } from 'vs/platform/environment/node/argv'; +import { parseArgs, ErrorReporter, OPTIONS } from 'vs/platform/environment/node/argv'; -function validate(args: ParsedArgs): ParsedArgs { +function parseAndValidate(cmdLineArgs: string[], reportWarnings: boolean): ParsedArgs { + const errorReporter: ErrorReporter = { + onUnknownOption: (id) => { + console.warn(localize('unknownOption', "Option '{0}' is unknown. Ignoring.", id)); + }, + onMultipleValues: (id, val) => { + console.warn(localize('multipleValues', "Option '{0}' is defined more than once. Using value '{1}.'", id, val)); + } + }; + + 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))`."))); } @@ -42,7 +52,9 @@ export function parseMainProcessArgv(processArgv: string[]): ParsedArgs { args = stripAppPath(args) || []; } - return validate(parseArgs(args)); + // If called from CLI, don't report warnings as they are already reported. + let reportWarnings = !process.env['VSCODE_CLI']; + return parseAndValidate(args, reportWarnings); } /** @@ -55,5 +67,5 @@ export function parseCLIProcessArgv(processArgv: string[]): ParsedArgs { args = stripAppPath(args) || []; } - return validate(parseArgs(args)); + return parseAndValidate(args, true); } diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 3eb487a5c44..e0cc96ad33b 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -198,11 +198,6 @@ export class EnvironmentService implements IEnvironmentService { } return URI.file(path.normalize(p)); }); - } else if (s) { - if (/^[^:/?#]+?:\/\//.test(s)) { - return [URI.parse(s)]; - } - return [URI.file(path.normalize(s))]; } 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/launch/electron-main/launchService.ts b/src/vs/platform/launch/electron-main/launchService.ts index 19e396d6052..876d2198d1f 100644 --- a/src/vs/platform/launch/electron-main/launchService.ts +++ b/src/vs/platform/launch/electron-main/launchService.ts @@ -17,7 +17,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { URI } from 'vs/base/common/uri'; import { BrowserWindow, ipcMain, Event as IpcEvent, app } from 'electron'; import { Event } from 'vs/base/common/event'; -import { hasArgs } from 'vs/platform/environment/node/argv'; import { coalesce } from 'vs/base/common/arrays'; import { IDiagnosticInfoOptions, IDiagnosticInfo, IRemoteDiagnosticInfo, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics'; import { IMainProcessInfo, IWindowInfo } from 'vs/platform/launch/common/launchService'; @@ -173,7 +172,7 @@ export class LaunchService implements ILaunchService { } // Start without file/folder arguments - else if (!hasArgs(args._) && !hasArgs(args['folder-uri']) && !hasArgs(args['file-uri'])) { + else if (!args._.length && !args['folder-uri'] && !args['file-uri']) { let openNewWindow = false; // Force new window 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/url/node/urlService.ts b/src/vs/platform/url/node/urlService.ts index adf857493e8..f73ff3fb045 100644 --- a/src/vs/platform/url/node/urlService.ts +++ b/src/vs/platform/url/node/urlService.ts @@ -10,7 +10,11 @@ import { AbstractURLService } from 'vs/platform/url/common/urlService'; export class URLService extends AbstractURLService { create(options?: Partial): URI { - const { authority, path, query, fragment } = options ? options : { authority: undefined, path: undefined, query: undefined, fragment: undefined }; + let { authority, path, query, fragment } = options ? options : { authority: undefined, path: undefined, query: undefined, fragment: undefined }; + + if (authority && path && path.indexOf('/') !== 0) { + path = `/${path}`; // URI validation requires a path if there is an authority + } return URI.from({ scheme: product.urlProtocol, authority, path, query, fragment }); } diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 71479f9009e..d98d0727c57 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -96,7 +96,7 @@ export interface IWindowsMainService { enterWorkspace(win: ICodeWindow, path: URI): Promise; closeWorkspace(win: ICodeWindow): void; open(openConfig: IOpenConfiguration): ICodeWindow[]; - openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string | string[], openConfig: IOpenConfiguration): void; + openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): void; pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise; pickFolderAndOpen(options: INativeOpenDialogOptions): Promise; pickFileAndOpen(options: INativeOpenDialogOptions): Promise; @@ -140,4 +140,4 @@ export interface IOpenConfiguration { export interface ISharedProcess { whenReady(): Promise; toggle(): void; -} \ No newline at end of file +} diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index b02f54433d2..68863b9f480 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -309,8 +309,9 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH async openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise { this.logService.trace('windowsService#openExtensionDevelopmentHostWindow ' + JSON.stringify(args)); - if (args.extensionDevelopmentPath) { - this.windowsMainService.openExtensionDevelopmentHostWindow(args.extensionDevelopmentPath, { + const extDevPaths = args.extensionDevelopmentPath; + if (extDevPaths) { + this.windowsMainService.openExtensionDevelopmentHostWindow(extDevPaths, { context: OpenContext.API, cli: args, userEnv: Object.keys(env).length > 0 ? env : undefined 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/vscode.d.ts b/src/vs/vscode.d.ts index 32533758bb5..ab7024c4c86 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2532,6 +2532,18 @@ declare module 'vscode' { TypeParameter = 25 } + + /** + * Symbol tags are extra annotations that tweak the rendering of a symbol. + */ + export enum SymbolTag { + + /** + * Render a symbol as obsolete, usually using a strike-out. + */ + Deprecated = 1 + } + /** * Represents information about programming constructs like variables, classes, * interfaces etc. @@ -2553,6 +2565,11 @@ declare module 'vscode' { */ kind: SymbolKind; + /** + * Tags for this symbol. + */ + tags?: ReadonlyArray; + /** * The location of this symbol. */ @@ -2604,6 +2621,11 @@ declare module 'vscode' { */ kind: SymbolKind; + /** + * Tags for this symbol. + */ + tags?: ReadonlyArray; + /** * The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. */ @@ -3285,6 +3307,17 @@ declare module 'vscode' { TypeParameter = 24 } + /** + * Completion item tags are extra annotations that tweak the rendering of a completion + * item. + */ + export enum CompletionItemTag { + /** + * Render a completion as obsolete, usually using a strike-out. + */ + Deprecated = 1 + } + /** * A completion item represents a text snippet that is proposed to complete text that is being typed. * @@ -3315,6 +3348,11 @@ declare module 'vscode' { */ kind?: CompletionItemKind; + /** + * Tags for this completion item. + */ + tags?: ReadonlyArray; + /** * A human-readable string with additional information * about this item, like type or symbol information. @@ -6797,26 +6835,35 @@ declare module 'vscode' { export function createStatusBarItem(alignment?: StatusBarAlignment, priority?: number): StatusBarItem; /** - * Creates a [Terminal](#Terminal). The cwd of the terminal will be the workspace directory - * if it exists, regardless of whether an explicit customStartPath setting exists. + * Creates a [Terminal](#Terminal) with a backing shell process. The cwd of the terminal will be the workspace + * directory if it exists. * * @param name Optional human-readable string which will be used to represent the terminal in the UI. * @param shellPath Optional path to a custom shell executable to be used in the terminal. * @param shellArgs Optional args for the custom shell executable. A string can be used on Windows only which - * allows specifying shell args in [command-line format](https://msdn.microsoft.com/en-au/08dfcab2-eb6e-49a4-80eb-87d4076c98c6). + * allows specifying shell args in + * [command-line format](https://msdn.microsoft.com/en-au/08dfcab2-eb6e-49a4-80eb-87d4076c98c6). * @return A new Terminal. */ export function createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): Terminal; /** - * Creates a [Terminal](#Terminal). The cwd of the terminal will be the workspace directory - * if it exists, regardless of whether an explicit customStartPath setting exists. + * Creates a [Terminal](#Terminal) with a backing shell process. * * @param options A TerminalOptions object describing the characteristics of the new terminal. * @return A new Terminal. */ export function createTerminal(options: TerminalOptions): Terminal; + /** + * Creates a [Terminal](#Terminal) where an extension controls its input and output. + * + * @param options An [ExtensionTerminalOptions](#ExtensionTerminalOptions) object describing + * the characteristics of the new terminal. + * @return A new Terminal. + */ + export function createTerminal(options: ExtensionTerminalOptions): Terminal; + /** * Register a [TreeDataProvider](#TreeDataProvider) for the view contributed using the extension point `views`. * This will allow you to contribute data to the [TreeView](#TreeView) and update if the data changes. @@ -7170,6 +7217,169 @@ declare module 'vscode' { hideFromUser?: boolean; } + /** + * Value-object describing what options a virtual process terminal should use. + */ + export interface ExtensionTerminalOptions { + /** + * A human-readable string which will be used to represent the terminal in the UI. + */ + name: string; + + /** + * An implementation of [Pseudoterminal](#Pseudoterminal) that allows an extension to + * control a terminal. + */ + pty: Pseudoterminal; + } + + /** + * Defines the interface of a terminal pty, enabling extensions to control a terminal. + */ + interface Pseudoterminal { + /** + * An event that when fired will write data to the terminal. Unlike + * [Terminal.sendText](#Terminal.sendText) which sends text to the underlying _process_ + * (the pty "slave"), this will write the text to the terminal itself (the pty "master"). + * + * **Example:** Write red text to the terminal + * ```typescript + * const writeEmitter = new vscode.EventEmitter(); + * const pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * open: () => writeEmitter.fire('\x1b[31mHello world\x1b[0m'), + * close: () => {} + * }; + * vscode.window.createTerminal({ name: 'My terminal', pty }); + * ``` + * + * **Example:** Move the cursor to the 10th row and 20th column and write an asterisk + * ```typescript + * writeEmitter.fire('\x1b[10;20H*'); + * ``` + */ + onDidWrite: Event; + + /** + * An event that when fired allows overriding the [dimensions](#Terminal.dimensions) of the + * terminal. Note that when set, the overridden dimensions will only take effect when they + * are lower than the actual dimensions of the terminal (ie. there will never be a scroll + * bar). Set to `undefined` for the terminal to go back to the regular dimensions (fit to + * the size of the panel). + * + * **Example:** Override the dimensions of a terminal to 20 columns and 10 rows + * ```typescript + * const dimensionsEmitter = new vscode.EventEmitter(); + * const pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * onDidOverrideDimensions: dimensionsEmitter.event, + * open: () => { + * dimensionsEmitter.fire({ + * columns: 20, + * rows: 10 + * }); + * }, + * close: () => {} + * }; + * vscode.window.createTerminal({ name: 'My terminal', pty }); + * ``` + */ + onDidOverrideDimensions?: Event; + + /** + * An event that when fired will signal that the pty is closed and dispose of the terminal. + * + * A number can be used to provide an exit code for the terminal. Exit codes must be + * positive and a non-zero exit codes signals failure which shows a notification for a + * regular terminal and allows dependent tasks to proceed when used with the + * `CustomExecution2` API. + * + * **Example:** Exit the terminal when "y" is pressed, otherwise show a notification. + * ```typescript + * const writeEmitter = new vscode.EventEmitter(); + * const closeEmitter = new vscode.EventEmitter(); + * const pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * onDidClose: closeEmitter.event, + * open: () => writeEmitter.fire('Press y to exit successfully'), + * close: () => {}, + * handleInput: data => { + * if (data !== 'y') { + * vscode.window.showInformationMessage('Something went wrong'); + * } + * closeEmitter.fire(); + * } + * }; + * vscode.window.createTerminal({ name: 'Exit example', pty }); + */ + onDidClose?: Event; + + /** + * Implement to handle when the pty is open and ready to start firing events. + * + * @param initialDimensions The dimensions of the terminal, this will be undefined if the + * terminal panel has not been opened before this is called. + */ + open(initialDimensions: TerminalDimensions | undefined): void; + + /** + * Implement to handle when the terminal is closed by an act of the user. + */ + close(): void; + + /** + * Implement to handle incoming keystrokes in the terminal or when an extension calls + * [Terminal.sendText](#Terminal.sendText). `data` contains the keystrokes/text serialized into + * their corresponding VT sequence representation. + * + * @param data The incoming data. + * + * **Example:** Echo input in the terminal. The sequence for enter (`\r`) is translated to + * CRLF to go to a new line and move the cursor to the start of the line. + * ```typescript + * const writeEmitter = new vscode.EventEmitter(); + * const pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * open: () => {}, + * close: () => {}, + * handleInput: data => writeEmitter.fire(data === '\r' ? '\r\n' : data) + * }; + * vscode.window.createTerminal({ name: 'Local echo', pty }); + * ``` + */ + handleInput?(data: string): void; + + /** + * Implement to handle when the number of rows and columns that fit into the terminal panel + * changes, for example when font size changes or when the panel is resized. The initial + * state of a terminal's dimensions should be treated as `undefined` until this is triggered + * as the size of a terminal isn't know until it shows up in the user interface. + * + * When dimensions are overridden by + * [onDidOverrideDimensions](#Pseudoterminal.onDidOverrideDimensions), `setDimensions` will + * continue to be called with the regular panel dimensions, allowing the extension continue + * to react dimension changes. + * + * @param dimensions The new dimensions. + */ + setDimensions?(dimensions: TerminalDimensions): void; + } + + /** + * Represents the dimensions of a terminal. + */ + export interface TerminalDimensions { + /** + * The number of columns in the terminal. + */ + readonly columns: number; + + /** + * The number of rows in the terminal. + */ + readonly rows: number; + } + /** * A location in the editor at which progress information can be shown. It depends on the * location how progress is visually represented. @@ -8692,9 +8902,10 @@ declare module 'vscode' { readonly type: string; /** - * The debug session's name from the [debug configuration](#DebugConfiguration). + * The debug session's name is initially taken from the [debug configuration](#DebugConfiguration). + * Any changes will be properly reflected in the UI. */ - readonly name: string; + name: string; /** * The workspace folder of this session or `undefined` for a folderless setup. diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 52de41f3a47..530cca349bc 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -556,25 +556,17 @@ declare module 'vscode' { //#region Joh: decorations - //todo@joh -> make class - export interface DecorationData { + export class Decoration { letter?: string; title?: string; color?: ThemeColor; priority?: number; bubble?: boolean; - source?: string; // hacky... we should remove it and use equality under the hood - } - - export interface SourceControlResourceDecorations { - source?: string; - letter?: string; - color?: ThemeColor; } export interface DecorationProvider { onDidChangeDecorations: Event; - provideDecoration(uri: Uri, token: CancellationToken): ProviderResult; + provideDecoration(uri: Uri, token: CancellationToken): ProviderResult; } export namespace window { @@ -768,184 +760,6 @@ declare module 'vscode' { readonly onDidWriteData: Event; } - /** - * Represents the dimensions of a terminal. - */ - export interface TerminalDimensions { - /** - * The number of columns in the terminal. - */ - readonly columns: number; - - /** - * The number of rows in the terminal. - */ - readonly rows: number; - } - - //#endregion - - //#region Extension terminals - - export namespace window { - /** - * Creates a [Terminal](#Terminal) where an extension controls the terminal. - * - * @param options An [ExtensionTerminalOptions](#ExtensionTerminalOptions) object describing - * the characteristics of the new terminal. - * @return A new Terminal. - */ - export function createTerminal(options: ExtensionTerminalOptions): Terminal; - } - - /** - * Value-object describing what options a virtual process terminal should use. - */ - export interface ExtensionTerminalOptions { - /** - * A human-readable string which will be used to represent the terminal in the UI. - */ - name: string; - - /** - * An implementation of [Pseudoterminal](#Pseudoterminal) that allows an extension to - * control a terminal. - */ - pty: Pseudoterminal; - } - - /** - * Defines the interface of a terminal pty, enabling extensions to control a terminal. - */ - interface Pseudoterminal { - /** - * An event that when fired will write data to the terminal. Unlike - * [Terminal.sendText](#Terminal.sendText) which sends text to the underlying _process_ - * (the pty "slave"), this will write the text to the terminal itself (the pty "master"). - * - * **Example:** Write red text to the terminal - * ```typescript - * const writeEmitter = new vscode.EventEmitter(); - * const pty: vscode.Pseudoterminal = { - * onDidWrite: writeEmitter.event, - * open: () => writeEmitter.fire('\x1b[31mHello world\x1b[0m'), - * close: () => {} - * }; - * vscode.window.createTerminal({ name: 'My terminal', pty }); - * ``` - * - * **Example:** Move the cursor to the 10th row and 20th column and write an asterisk - * ```typescript - * writeEmitter.fire('\x1b[10;20H*'); - * ``` - */ - onDidWrite: Event; - - /** - * An event that when fired allows overriding the [dimensions](#Terminal.dimensions) of the - * terminal. Note that when set, the overridden dimensions will only take effect when they - * are lower than the actual dimensions of the terminal (ie. there will never be a scroll - * bar). Set to `undefined` for the terminal to go back to the regular dimensions (fit to - * the size of the panel). - * - * **Example:** Override the dimensions of a terminal to 20 columns and 10 rows - * ```typescript - * const dimensionsEmitter = new vscode.EventEmitter(); - * const pty: vscode.Pseudoterminal = { - * onDidWrite: writeEmitter.event, - * onDidOverrideDimensions: dimensionsEmitter.event, - * open: () => { - * dimensionsEmitter.fire({ - * columns: 20, - * rows: 10 - * }); - * }, - * close: () => {} - * }; - * vscode.window.createTerminal({ name: 'My terminal', pty }); - * ``` - */ - onDidOverrideDimensions?: Event; - - /** - * An event that when fired will signal that the pty is closed and dispose of the terminal. - * - * A number can be used to provide an exit code for the terminal. Exit codes must be - * positive and a non-zero exit codes signals failure which shows a notification for a - * regular terminal and allows dependent tasks to proceed when used with the - * `CustomExecution2` API. - * - * **Example:** Exit the terminal when "y" is pressed, otherwise show a notification. - * ```typescript - * const writeEmitter = new vscode.EventEmitter(); - * const closeEmitter = new vscode.EventEmitter(); - * const pty: vscode.Pseudoterminal = { - * onDidWrite: writeEmitter.event, - * onDidClose: closeEmitter.event, - * open: () => writeEmitter.fire('Press y to exit successfully'), - * close: () => {} - * handleInput: data => { - * if (data !== 'y') { - * vscode.window.showInformationMessage('Something went wrong'); - * } - * closeEmitter.fire(); - * } - * }; - * vscode.window.createTerminal({ name: 'Exit example', pty }); - */ - onDidClose?: Event; - - /** - * Implement to handle when the pty is open and ready to start firing events. - * - * @param initialDimensions The dimensions of the terminal, this will be undefined if the - * terminal panel has not been opened before this is called. - */ - open(initialDimensions: TerminalDimensions | undefined): void; - - /** - * Implement to handle when the terminal is closed by an act of the user. - */ - close(): void; - - /** - * Implement to handle incoming keystrokes in the terminal or when an extension calls - * [Terminal.sendText](#Terminal.sendText). `data` contains the keystrokes/text serialized into - * their corresponding VT sequence representation. - * - * @param data The incoming data. - * - * **Example:** Echo input in the terminal. The sequence for enter (`\r`) is translated to - * CRLF to go to a new line and move the cursor to the start of the line. - * ```typescript - * const writeEmitter = new vscode.EventEmitter(); - * const pty: vscode.Pseudoterminal = { - * onDidWrite: writeEmitter.event, - * open: () => {}, - * close: () => {}, - * handleInput: data => writeEmitter.fire(data === '\r' ? '\r\n' : data) - * }; - * vscode.window.createTerminal({ name: 'Local echo', pty }); - * ``` - */ - handleInput?(data: string): void; - - /** - * Implement to handle when the number of rows and columns that fit into the terminal panel - * changes, for example when font size changes or when the panel is resized. The initial - * state of a terminal's dimensions should be treated as `undefined` until this is triggered - * as the size of a terminal isn't know until it shows up in the user interface. - * - * When dimensions are overridden by - * [onDidOverrideDimensions](#Pseudoterminal.onDidOverrideDimensions), `setDimensions` will - * continue to be called with the regular panel dimensions, allowing the extension continue - * to react dimension changes. - * - * @param dimensions The new dimensions. - */ - setDimensions?(dimensions: TerminalDimensions): void; - } - //#endregion //#region Joh -> exclusive document filters @@ -1127,40 +941,6 @@ declare module 'vscode' { //#endregion - //#region Joh - CompletionItemTag, https://github.com/microsoft/vscode/issues/23927 - - export enum SymbolTag { - Deprecated = 1 - } - - export interface SymbolInformation { - /** - * - */ - tags?: ReadonlyArray; - } - - export interface DocumentSymbol { - /** - * - */ - tags?: ReadonlyArray; - } - - export enum CompletionItemTag { - Deprecated = 1 - } - - export interface CompletionItem { - - /** - * - */ - tags?: ReadonlyArray; - } - - //#endregion - // #region Ben - extension auth flow (desktop+web) export interface AppUriOptions { diff --git a/src/vs/workbench/api/browser/mainThreadDebugService.ts b/src/vs/workbench/api/browser/mainThreadDebugService.ts index fc830d3ddc2..721187994a6 100644 --- a/src/vs/workbench/api/browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/browser/mainThreadDebugService.ts @@ -35,6 +35,9 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDebugService); this._toDispose.add(debugService.onDidNewSession(session => { this._proxy.$acceptDebugSessionStarted(this.getSessionDto(session)); + this._toDispose.add(session.onDidChangeName(name => { + this._proxy.$acceptDebugSessionNameChanged(this.getSessionDto(session), name); + })); })); // Need to start listening early to new session events because a custom event can come while a session is initialising this._toDispose.add(debugService.onWillNewSession(session => { @@ -225,6 +228,13 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb }); } + public $setDebugSessionName(sessionId: DebugSessionUUID, name: string): void { + const session = this.debugService.getModel().getSession(sessionId); + if (session) { + session.setName(name); + } + } + public $customDebugAdapterRequest(sessionId: DebugSessionUUID, request: string, args: any): Promise { const session = this.debugService.getModel().getSession(sessionId, true); if (session) { diff --git a/src/vs/workbench/api/browser/mainThreadDecorations.ts b/src/vs/workbench/api/browser/mainThreadDecorations.ts index f34105ddf73..08d46a98405 100644 --- a/src/vs/workbench/api/browser/mainThreadDecorations.ts +++ b/src/vs/workbench/api/browser/mainThreadDecorations.ts @@ -93,14 +93,13 @@ export class MainThreadDecorations implements MainThreadDecorationsShape { if (!data) { return undefined; } - const [weight, bubble, tooltip, letter, themeColor, source] = data; + const [weight, bubble, tooltip, letter, themeColor] = data; return { weight: weight || 0, bubble: bubble || false, color: themeColor && themeColor.id, tooltip, - letter, - source, + letter }; }); } 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/mainThreadSCM.ts b/src/vs/workbench/api/browser/mainThreadSCM.ts index 089cb517b45..e71a7c8a007 100644 --- a/src/vs/workbench/api/browser/mainThreadSCM.ts +++ b/src/vs/workbench/api/browser/mainThreadSCM.ts @@ -198,7 +198,7 @@ class MainThreadSCMProvider implements ISCMProvider { for (const [start, deleteCount, rawResources] of groupSlices) { const resources = rawResources.map(rawResource => { - const [handle, sourceUri, icons, tooltip, strikeThrough, faded, source, letter, color] = rawResource; + const [handle, sourceUri, icons, tooltip, strikeThrough, faded] = rawResource; const icon = icons[0]; const iconDark = icons[1] || icon; const decorations = { @@ -206,10 +206,7 @@ class MainThreadSCMProvider implements ISCMProvider { iconDark: iconDark ? URI.parse(iconDark) : undefined, tooltip, strikeThrough, - faded, - source, - letter, - color: color ? color.id : undefined + faded }; return new MainThreadSCMResource( diff --git a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts index 1bd75108c5a..8827222e22c 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; } diff --git a/src/vs/workbench/api/browser/mainThreadTask.ts b/src/vs/workbench/api/browser/mainThreadTask.ts index 7934efb088b..6fc2d150952 100644 --- a/src/vs/workbench/api/browser/mainThreadTask.ts +++ b/src/vs/workbench/api/browser/mainThreadTask.ts @@ -626,6 +626,9 @@ export class MainThreadTask implements MainThreadTaskShape { }); }); }); + }, + getDefaultShellAndArgs: (): Promise<{ shell: string, args: string[] | string | undefined }> => { + return Promise.resolve(this._proxy.$getDefaultShellAndArgs()); } }); } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 0c3a701f733..17cb07b2627 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -514,7 +514,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I } return extHostTerminalService.createTerminalFromOptions(nameOrOptions); } - return extHostTerminalService.createTerminal(nameOrOptions, shellPath, shellArgs); + return extHostTerminalService.createTerminal(nameOrOptions, shellPath, shellArgs); }, registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider): vscode.Disposable { return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, extension); @@ -900,7 +900,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I WorkspaceEdit: extHostTypes.WorkspaceEdit, // proposed CallHierarchyDirection: extHostTypes.CallHierarchyDirection, - CallHierarchyItem: extHostTypes.CallHierarchyItem + CallHierarchyItem: extHostTypes.CallHierarchyItem, + Decoration: extHostTypes.Decoration }; }; } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 140a4c35d51..6565bd8272c 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -667,11 +667,7 @@ export type SCMRawResource = [ string[] /*icons: light, dark*/, string /*tooltip*/, boolean /*strike through*/, - boolean /*faded*/, - - string | undefined /*source*/, - string | undefined /*letter*/, - ThemeColor | null /*color*/ + boolean /*faded*/ ]; export type SCMRawResourceSplice = [ @@ -723,6 +719,7 @@ export interface MainThreadDebugServiceShape extends IDisposable { $unregisterDebugConfigurationProvider(handle: number): void; $unregisterDebugAdapterDescriptorFactory(handle: number): void; $startDebugging(folder: UriComponents | undefined, nameOrConfig: string | IDebugConfiguration, parentSessionID: string | undefined): Promise; + $setDebugSessionName(id: DebugSessionUUID, name: string): void; $customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): Promise; $appendDebugConsole(value: string): void; $startBreakpointEvents(): void; @@ -1199,6 +1196,7 @@ export interface ExtHostTaskShape { $onDidEndTaskProcess(value: tasks.TaskProcessEndedDTO): void; $OnDidEndTask(execution: tasks.TaskExecutionDTO): void; $resolveVariables(workspaceFolder: UriComponents, toResolve: { process?: { name: string; cwd?: string }, variables: string[] }): Promise<{ process?: string; variables: { [key: string]: string } }>; + $getDefaultShellAndArgs(): Thenable<{ shell: string, args: string[] | string | undefined }>; } export interface IBreakpointDto { @@ -1274,6 +1272,7 @@ export interface ExtHostDebugServiceShape { $acceptDebugSessionActiveChanged(session: IDebugSessionDto | undefined): void; $acceptDebugSessionCustomEvent(session: IDebugSessionDto, event: any): void; $acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void; + $acceptDebugSessionNameChanged(session: IDebugSessionDto, name: string): void; } @@ -1283,7 +1282,7 @@ export interface DecorationRequest { readonly uri: UriComponents; } -export type DecorationData = [number, boolean, string, string, ThemeColor, string]; +export type DecorationData = [number, boolean, string, string, ThemeColor]; export type DecorationReply = { [id: number]: DecorationData }; export interface ExtHostDecorationsShape { diff --git a/src/vs/workbench/api/common/extHostDecorations.ts b/src/vs/workbench/api/common/extHostDecorations.ts index b62fc15ee32..a0b0612706a 100644 --- a/src/vs/workbench/api/common/extHostDecorations.ts +++ b/src/vs/workbench/api/common/extHostDecorations.ts @@ -6,7 +6,7 @@ import * as vscode from 'vscode'; import { URI } from 'vs/base/common/uri'; import { MainContext, ExtHostDecorationsShape, MainThreadDecorationsShape, DecorationData, DecorationRequest, DecorationReply } from 'vs/workbench/api/common/extHost.protocol'; -import { Disposable } from 'vs/workbench/api/common/extHostTypes'; +import { Disposable, Decoration } from 'vs/workbench/api/common/extHostTypes'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { asArray } from 'vs/base/common/arrays'; @@ -59,12 +59,14 @@ export class ExtHostDecorations implements IExtHostDecorations { } const { provider, extensionId } = entry; return Promise.resolve(provider.provideDecoration(URI.revive(uri), token)).then(data => { - if (data && data.letter && data.letter.length !== 1) { - console.warn(`INVALID decoration from extension '${extensionId.value}'. The 'letter' must be set and be one character, not '${data.letter}'.`); + if (!data) { + return; } - if (data) { - result[id] = [data.priority, data.bubble, data.title, data.letter, data.color, data.source]; - + try { + Decoration.validate(data); + result[id] = [data.priority, data.bubble, data.title, data.letter, data.color]; + } catch (e) { + console.warn(`INVALID decoration from extension '${extensionId.value}': ${e}`); } }, err => { console.error(err); diff --git a/src/vs/workbench/api/common/extHostSCM.ts b/src/vs/workbench/api/common/extHostSCM.ts index 00b3315f6c7..9ab1b497761 100644 --- a/src/vs/workbench/api/common/extHostSCM.ts +++ b/src/vs/workbench/api/common/extHostSCM.ts @@ -319,11 +319,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG const strikeThrough = r.decorations && !!r.decorations.strikeThrough; const faded = r.decorations && !!r.decorations.faded; - const source = r.decorations && r.decorations.source || undefined; - const letter = r.decorations && r.decorations.letter || undefined; - const color = r.decorations && r.decorations.color || undefined; - - const rawResource = [handle, sourceUri, icons, tooltip, strikeThrough, faded, source, letter, color] as SCMRawResource; + const rawResource = [handle, sourceUri, icons, tooltip, strikeThrough, faded] as SCMRawResource; return { rawResource, handle }; }); diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index d7b513afd22..623297aa26d 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2349,3 +2349,21 @@ export enum ExtensionKind { UI = 1, Workspace = 2 } + +export class Decoration { + + static validate(d: Decoration): void { + if (d.letter && d.letter.length !== 1) { + throw new Error(`The 'letter'-property must be undefined or a single character`); + } + if (!d.bubble && !d.color && !d.letter && !d.priority && !d.title) { + throw new Error(`The decoration is empty`); + } + } + + letter?: string; + title?: string; + color?: vscode.ThemeColor; + priority?: number; + bubble?: boolean; +} diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 82c653c9c37..795b4b1598a 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -687,6 +687,13 @@ export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugSe this._onDidChangeActiveDebugSession.fire(this._activeDebugSession); } + public async $acceptDebugSessionNameChanged(sessionDto: IDebugSessionDto, name: string): Promise { + const session = await this.getSession(sessionDto); + if (session) { + session._acceptNameChanged(name); + } + } + public async $acceptDebugSessionCustomEvent(sessionDto: IDebugSessionDto, event: any): Promise { const session = await this.getSession(sessionDto); const ee: vscode.DebugSessionCustomEvent = { @@ -917,6 +924,15 @@ export class ExtHostDebugSession implements vscode.DebugSession { return this._name; } + public set name(name: string) { + this._name = name; + this._debugServiceProxy.$setDebugSessionName(this._id, name); + } + + _acceptNameChanged(name: string) { + this._name = name; + } + public get workspaceFolder(): vscode.WorkspaceFolder | undefined { return this._workspaceFolder; } diff --git a/src/vs/workbench/api/node/extHostSearch.ts b/src/vs/workbench/api/node/extHostSearch.ts index b0e8753c0cd..639e1f835c1 100644 --- a/src/vs/workbench/api/node/extHostSearch.ts +++ b/src/vs/workbench/api/node/extHostSearch.ts @@ -29,8 +29,8 @@ export class ExtHostSearch implements ExtHostSearchShape { private readonly _fileSearchUsedSchemes = new Set(); private _handlePool: number = 0; - private _internalFileSearchHandle: number; - private _internalFileSearchProvider: SearchService | null; + private _internalFileSearchHandle: number = -1; + private _internalFileSearchProvider: SearchService | null = null; private _fileSearchManager: FileSearchManager; diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index 2e194117598..ccf856d9d80 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -659,6 +659,10 @@ export class ExtHostTask implements ExtHostTaskShape { return result; } + public $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }> { + return this._terminalService.$requestDefaultShellAndArgs(true); + } + private nextHandle(): number { return this._handleCounter++; } diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts index 4fcb6db76f8..afd82468c06 100644 --- a/src/vs/workbench/api/worker/extHostExtensionService.ts +++ b/src/vs/workbench/api/worker/extHostExtensionService.ts @@ -6,74 +6,10 @@ import { createApiFactoryAndRegisterActors } from 'vs/workbench/api/common/extHost.api.impl'; import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHostExtensionActivator'; import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; -import { endsWith, startsWith } from 'vs/base/common/strings'; +import { endsWith } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; -import { joinPath } from 'vs/base/common/resources'; import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor'; -class ExportsTrap { - - static readonly Instance = new ExportsTrap(); - - private readonly _names: string[] = []; - private readonly _exports = new Map(); - - private constructor() { - - const exportsProxy = new Proxy({}, { - set: (target: any, p: PropertyKey, value: any) => { - // store in target - target[p] = value; - // store in named-bucket - const name = this._names[this._names.length - 1]; - this._exports.get(name)![p] = value; - return true; - } - }); - - - const moduleProxy = new Proxy({}, { - - get: (target: any, p: PropertyKey) => { - if (p === 'exports') { - return exportsProxy; - } - - return target[p]; - }, - - set: (target: any, p: PropertyKey, value: any) => { - // store in target - target[p] = value; - - // override bucket - if (p === 'exports') { - const name = this._names[this._names.length - 1]; - this._exports.set(name, value); - } - return true; - } - }); - - (self).exports = exportsProxy; - (self).module = moduleProxy; - } - - add(name: string) { - this._exports.set(name, Object.create(null)); - this._names.push(name); - - return { - claim: () => { - const result = this._exports.get(name); - this._exports.delete(name); - this._names.pop(); - return result; - } - }; - } -} - class WorkerRequireInterceptor extends RequireInterceptor { _installInterceptor() { } @@ -105,43 +41,33 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { await this._fakeModules.install(); } - protected _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + protected async _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { - (self).window = self; // <- that's improper but might help extensions that aren't authored correctly + module = module.with({ path: ensureSuffix(module.path, '.js') }); + const response = await fetch(module.toString(true)); - // FAKE require function that only works for the vscode-module - const moduleStack: URI[] = []; - (self).require = (mod: string) => { + if (response.status !== 200) { + throw new Error(response.statusText); + } - const parent = moduleStack[moduleStack.length - 1]; - const result = this._fakeModules.getModule(mod, parent); + // fetch JS sources as text and create a new function around it + const initFn = new Function('module', 'exports', 'require', 'window', await response.text()); - if (result !== undefined) { - return result; + // define commonjs globals: `module`, `exports`, and `require` + const _exports = {}; + const _module = { exports: _exports }; + const _require = (request: string) => { + const result = this._fakeModules.getModule(request, module); + if (result === undefined) { + throw new Error(`Cannot load module '${request}'`); } - - if (!startsWith(mod, '.')) { - throw new Error(`Cannot load module '${mod}'`); - } - - const next = joinPath(parent, '..', ensureSuffix(mod, '.js')); - moduleStack.push(next); - const trap = ExportsTrap.Instance.add(next.toString()); - importScripts(next.toString(true)); - moduleStack.pop(); - - return trap.claim(); + return result; }; try { activationTimesBuilder.codeLoadingStart(); - module = module.with({ path: ensureSuffix(module.path, '.js') }); - moduleStack.push(module); - const trap = ExportsTrap.Instance.add(module.toString()); - importScripts(module.toString(true)); - moduleStack.pop(); - return Promise.resolve(trap.claim()); - + initFn(_module, _exports, _require, self); + return (_module.exports !== _exports ? _module.exports : _exports); } finally { activationTimesBuilder.codeLoadingStop(); } diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 35a19a119b4..2b5d9be8790 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -14,7 +14,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { IDecorationsService, IResourceDecorationChangeEvent, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; +import { IDecorationsService, IResourceDecorationChangeEvent } from 'vs/workbench/services/decorations/browser/decorations'; import { Schemas } from 'vs/base/common/network'; import { FileKind, FILES_ASSOCIATIONS_CONFIG, IFileService } from 'vs/platform/files/common/files'; import { ITextModel } from 'vs/editor/common/model'; @@ -34,7 +34,7 @@ export interface IResourceLabelProps { export interface IResourceLabelOptions extends IIconLabelValueOptions { fileKind?: FileKind; - fileDecorations?: { colors: boolean, badges: boolean, data?: IDecorationData }; + fileDecorations?: { colors: boolean, badges: boolean }; descriptionVerbosity?: Verbosity; } @@ -468,8 +468,7 @@ class ResourceLabelWidget extends IconLabel { if (this.options && this.options.fileDecorations && resource) { const deco = this.decorationsService.getDecoration( resource, - this.options.fileKind !== FileKind.FILE, - this.options.fileDecorations.data + this.options.fileKind !== FileKind.FILE ); if (deco) { diff --git a/src/vs/workbench/browser/media/part.css b/src/vs/workbench/browser/media/part.css index 60351cbaf21..c051ed6eb22 100644 --- a/src/vs/workbench/browser/media/part.css +++ b/src/vs/workbench/browser/media/part.css @@ -9,6 +9,7 @@ .monaco-workbench .part { box-sizing: border-box; + overflow: hidden; } .monaco-workbench .part > .title { diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 5d56b84987b..1afbdd3e69a 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -198,6 +198,8 @@ export class ActivitybarPart extends Part implements IActivityBarService { this.createGlobalActivityActionBar(globalActivities); + this.element.style.display = this.layoutService.isVisible(Parts.ACTIVITYBAR_PART) ? null : 'none'; + return content; } @@ -368,6 +370,12 @@ export class ActivitybarPart extends Part implements IActivityBarService { .map(v => v.id); } + setVisible(visible: boolean): void { + if (this.element) { + this.element.style.display = visible ? null : 'none'; + } + } + layout(width: number, height: number): void { if (!this.layoutService.isVisible(Parts.ACTIVITYBAR_PART)) { return; 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/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/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 0fb181af83a..30621785f1b 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -32,6 +32,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { EditorMemento } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; /** * The text editor that leverages the diff text editor for the editing experience. @@ -52,7 +53,8 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { @IThemeService themeService: IThemeService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, - @IWindowService windowService: IWindowService + @IWindowService windowService: IWindowService, + @IClipboardService private _clipboardService: IClipboardService, ) { super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, windowService); } @@ -70,7 +72,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { } createEditorControl(parent: HTMLElement, configuration: ICodeEditorOptions): IDiffEditor { - return this.instantiationService.createInstance(DiffEditorWidget, parent, configuration); + return this.instantiationService.createInstance(DiffEditorWidget, parent, configuration, this._clipboardService); } async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { diff --git a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts index 7f410544c6a..b949d8b0e08 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts @@ -236,12 +236,11 @@ export class NotificationsToasts extends Themable { purgeTimeoutHandle = setTimeout(() => { - // If the notification is sticky or prompting and the window does not have - // focus, we wait for the window to gain focus again before triggering - // the timeout again. This prevents an issue where focussing the window - // could immediately hide the notification because the timeout was triggered - // again. - if ((item.sticky || item.hasPrompt()) && !this.windowService.hasFocus) { + // If the window does not have focus, we wait for the window to gain focus + // again before triggering the timeout again. This prevents an issue where + // focussing the window could immediately hide the notification because the + // timeout was triggered again. + if (!this.windowService.hasFocus) { if (!listener) { listener = this.windowService.onDidChangeFocus(focus => { if (focus) { 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/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css index 1037fb4808f..92c49501535 100644 --- a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css +++ b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css @@ -20,6 +20,8 @@ z-index: 5; pointer-events: none; background-color: var(--status-border-top-color); + width: 100%; + height: 1px; } .monaco-workbench .part.statusbar > .left-items, 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/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts index caf44465e73..83f0c3b53c6 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/web.simpleservices.ts @@ -520,18 +520,9 @@ export class SimpleWindowsService implements IWindowsService { const f = args['folder-uri']; if (f) { - let u: URI | undefined; - if (Array.isArray(f)) { - if (f.length > 0) { - u = URI.parse(f[0]); - } - } else { - u = URI.parse(f); - } - if (u) { - gotFolder = true; - addQueryParameter('folder', u.path); - } + const u = URI.parse(f[0]); + gotFolder = true; + addQueryParameter('folder', u.path); } if (!gotFolder) { // request empty window @@ -540,17 +531,8 @@ export class SimpleWindowsService implements IWindowsService { const ep = args['extensionDevelopmentPath']; if (ep) { - let u: string | undefined; - if (Array.isArray(ep)) { - if (ep.length > 0) { - u = ep[0]; - } - } else { - u = ep; - } - if (u) { - addQueryParameter('edp', u); - } + let u = ep[0]; + addQueryParameter('edp', u); } const di = args['debugId']; 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/common/editor/editorGroup.ts b/src/vs/workbench/common/editor/editorGroup.ts index 3eb62c882cd..a1447c830ca 100644 --- a/src/vs/workbench/common/editor/editorGroup.ts +++ b/src/vs/workbench/common/editor/editorGroup.ts @@ -88,7 +88,7 @@ export class EditorGroup extends Disposable { //#endregion - private _id!: GroupIdentifier; + private _id: GroupIdentifier; get id(): GroupIdentifier { return this._id; } private editors: EditorInput[] = []; @@ -109,7 +109,7 @@ export class EditorGroup extends Disposable { super(); if (isSerializedEditorGroup(labelOrSerializedGroup)) { - this.deserialize(labelOrSerializedGroup); + this._id = this.deserialize(labelOrSerializedGroup); } else { this._id = EditorGroup.IDS++; } @@ -661,7 +661,7 @@ export class EditorGroup extends Disposable { }; } - private deserialize(data: ISerializedEditorGroup): void { + private deserialize(data: ISerializedEditorGroup): number { const registry = Registry.as(Extensions.EditorInputFactories); if (typeof data.id === 'number') { @@ -694,5 +694,7 @@ export class EditorGroup extends Disposable { if (typeof data.preview === 'number') { this.preview = this.editors[data.preview]; } + + return this._id; } } 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; private contributedContextMenu: IMenu; private parentSessionToExpand = new Set(); + private selectionNeedsUpdate = false; constructor( private options: IViewletViewOptions, @@ -86,7 +91,10 @@ export class CallStackView extends ViewletPanel { this.tree.updateChildren().then(() => { this.parentSessionToExpand.forEach(s => this.tree.expand(s)); this.parentSessionToExpand.clear(); - this.updateTreeSelection(); + if (this.selectionNeedsUpdate) { + this.selectionNeedsUpdate = false; + this.updateTreeSelection(); + } }); }, 50); } @@ -106,8 +114,8 @@ export class CallStackView extends ViewletPanel { this.dataSource = new CallStackDataSource(this.debugService); this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'CallStackView', treeContainer, new CallStackDelegate(), [ - new SessionsRenderer(), - new ThreadsRenderer(), + new SessionsRenderer(this.instantiationService), + new ThreadsRenderer(this.instantiationService), this.instantiationService.createInstance(StackFramesRenderer), new ErrorsRenderer(), new LoadMoreRenderer(), @@ -201,8 +209,8 @@ export class CallStackView extends ViewletPanel { this.onCallStackChangeScheduler.schedule(); } })); - const onCallStackChange = Event.any(this.debugService.getViewModel().onDidFocusStackFrame, this.debugService.getViewModel().onDidFocusSession); - this._register(onCallStackChange(() => { + const onFocusChange = Event.any(this.debugService.getViewModel().onDidFocusStackFrame, this.debugService.getViewModel().onDidFocusSession); + this._register(onFocusChange(() => { if (this.ignoreFocusStackFrameEvent) { return; } @@ -210,6 +218,10 @@ export class CallStackView extends ViewletPanel { this.needsRefresh = true; return; } + if (this.onCallStackChangeScheduler.isScheduled()) { + this.selectionNeedsUpdate = true; + return; + } this.updateTreeSelection(); })); @@ -227,6 +239,7 @@ export class CallStackView extends ViewletPanel { })); this._register(this.debugService.onDidNewSession(s => { + this._register(s.onDidChangeName(() => this.tree.rerender(s))); if (s.parentSession) { // Auto expand sessions that have sub sessions this.parentSessionToExpand.add(s.parentSession); @@ -334,6 +347,7 @@ interface IThreadTemplateData { state: HTMLElement; stateLabel: HTMLSpanElement; label: HighlightedLabel; + actionBar: ActionBar; } interface ISessionTemplateData { @@ -342,6 +356,7 @@ interface ISessionTemplateData { state: HTMLElement; stateLabel: HTMLSpanElement; label: HighlightedLabel; + actionBar: ActionBar; } interface IErrorTemplateData { @@ -363,6 +378,10 @@ interface IStackFrameTemplateData { class SessionsRenderer implements ITreeRenderer { static readonly ID = 'session'; + constructor( + private readonly instantiationService: IInstantiationService + ) { } + get templateId(): string { return SessionsRenderer.ID; } @@ -373,28 +392,35 @@ class SessionsRenderer implements ITreeRenderer, index: number, data: ISessionTemplateData): void { + renderElement(element: ITreeNode, _: number, data: ISessionTemplateData): void { const session = element.element; data.session.title = nls.localize({ key: 'session', comment: ['Session is a noun'] }, "Session"); data.label.set(session.getLabel(), createMatches(element.filterData)); const stoppedThread = session.getAllThreads().filter(t => t.stopped).pop(); + data.actionBar.clear(); + const actions = getActions(this.instantiationService, element.element); + data.actionBar.push(actions, { icon: true, label: false }); + data.stateLabel.textContent = stoppedThread ? nls.localize('paused', "Paused") : nls.localize({ key: 'running', comment: ['indicates state'] }, "Running"); } disposeTemplate(templateData: ISessionTemplateData): void { - // noop + templateData.actionBar.dispose(); } } class ThreadsRenderer implements ITreeRenderer { static readonly ID = 'thread'; + constructor(private readonly instantiationService: IInstantiationService) { } + get templateId(): string { return ThreadsRenderer.ID; } @@ -405,8 +431,9 @@ class ThreadsRenderer implements ITreeRenderer, index: number, data: IThreadTemplateData): void { @@ -414,10 +441,14 @@ class ThreadsRenderer implements ITreeRenderer { + return [ + thread.stopped ? instantiationService.createInstance(ContinueAction, thread) : instantiationService.createInstance(PauseAction, thread), + instantiationService.createInstance(StepOverAction, thread), + instantiationService.createInstance(StepIntoAction, thread), + instantiationService.createInstance(StepOutAction, thread) + ]; + }; + + if (element instanceof Thread) { + return getThreadActions(element); + } + + const session = element; + const stopOrDisconectAction = isSessionAttach(session) ? instantiationService.createInstance(DisconnectAction, session) : instantiationService.createInstance(StopAction, session); + const restartAction = instantiationService.createInstance(RestartAction, session); + const threads = session.getAllThreads(); + if (threads.length === 1) { + return getThreadActions(threads[0]).concat([ + restartAction, + stopOrDisconectAction + ]); + } + + return [ + restartAction, + stopOrDisconectAction + ]; +} + + +class StopAction extends Action { + + constructor( + private readonly session: IDebugSession, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${STOP_ID}`, STOP_LABEL, 'debug-action stop'); + } + + public run(): Promise { + return this.commandService.executeCommand(STOP_ID, this.session.getId(), this.session); + } +} + +class DisconnectAction extends Action { + + constructor( + private readonly session: IDebugSession, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${DISCONNECT_ID}`, DISCONNECT_LABEL, 'debug-action disconnect'); + } + + public run(): Promise { + return this.commandService.executeCommand(DISCONNECT_ID, this.session.getId(), this.session); + } +} + +class RestartAction extends Action { + + constructor( + private readonly session: IDebugSession, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${RESTART_SESSION_ID}`, RESTART_LABEL, 'debug-action restart'); + } + + public run(): Promise { + return this.commandService.executeCommand(RESTART_SESSION_ID, this.session.getId(), this.session); + } +} + +class StepOverAction extends Action { + + constructor( + private readonly thread: IThread, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${STEP_OVER_ID}`, STEP_OVER_LABEL, 'debug-action step-over', thread.stopped); + } + + public run(): Promise { + return this.commandService.executeCommand(STEP_OVER_ID, this.thread.threadId, this.thread); + } +} + +class StepIntoAction extends Action { + + constructor( + private readonly thread: IThread, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${STEP_INTO_ID}`, STEP_INTO_LABEL, 'debug-action step-into', thread.stopped); + } + + public run(): Promise { + return this.commandService.executeCommand(STEP_INTO_ID, this.thread.threadId, this.thread); + } +} + +class StepOutAction extends Action { + + constructor( + private readonly thread: IThread, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${STEP_OUT_ID}`, STEP_OUT_LABEL, 'debug-action step-out', thread.stopped); + } + + public run(): Promise { + return this.commandService.executeCommand(STEP_OUT_ID, this.thread.threadId, this.thread); + } +} + +class PauseAction extends Action { + + constructor( + private readonly thread: IThread, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${PAUSE_ID}`, PAUSE_LABEL, 'debug-action pause', !thread.stopped); + } + + public run(): Promise { + return this.commandService.executeCommand(PAUSE_ID, this.thread.threadId, this.thread); + } +} + +class ContinueAction extends Action { + + constructor( + private readonly thread: IThread, + @ICommandService private readonly commandService: ICommandService + ) { + super(`action.${CONTINUE_ID}`, CONTINUE_LABEL, 'debug-action continue', thread.stopped); + } + + public run(): Promise { + return this.commandService.executeCommand(CONTINUE_ID, this.thread.threadId, this.thread); + } +} diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index f3dd7181695..80f24ce0604 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -29,7 +29,7 @@ import { StartAction, AddFunctionBreakpointAction, ConfigureAction, DisableAllBr import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar'; import * as service from 'vs/workbench/contrib/debug/browser/debugService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, REVERSE_CONTINUE_ID, STEP_BACK_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID } from 'vs/workbench/contrib/debug/browser/debugCommands'; +import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, REVERSE_CONTINUE_ID, STEP_BACK_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands'; import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider'; import { IViewsRegistry, Extensions as ViewExtensions } from 'vs/workbench/common/views'; @@ -48,6 +48,7 @@ import { WatchExpressionsView } from 'vs/workbench/contrib/debug/browser/watchEx import { VariablesView } from 'vs/workbench/contrib/debug/browser/variablesView'; import { ClearReplAction, Repl } from 'vs/workbench/contrib/debug/browser/repl'; import { DebugContentProvider } from 'vs/workbench/contrib/debug/common/debugContentProvider'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; class OpenDebugViewletAction extends ShowViewletAction { public static readonly ID = VIEWLET_ID; @@ -147,23 +148,16 @@ const registerDebugCommandPaletteItem = (id: string, title: string, when?: Conte } }); }; -const restartLabel = nls.localize('restartDebug', "Restart"); -const stepOverLabel = nls.localize('stepOverDebug', "Step Over"); -const stepIntoLabel = nls.localize('stepIntoDebug', "Step Into"); -const stepOutLabel = nls.localize('stepOutDebug', "Step Out"); -const pauseLabel = nls.localize('pauseDebug', "Pause"); -const disconnectLabel = nls.localize('disconnect', "Disconnect"); -const stopLabel = nls.localize('stop', "Stop"); -const continueLabel = nls.localize('continueDebug', "Continue"); -registerDebugCommandPaletteItem(RESTART_SESSION_ID, restartLabel); + +registerDebugCommandPaletteItem(RESTART_SESSION_ID, RESTART_LABEL); registerDebugCommandPaletteItem(TERMINATE_THREAD_ID, nls.localize('terminateThread', "Terminate Thread"), CONTEXT_IN_DEBUG_MODE); -registerDebugCommandPaletteItem(STEP_OVER_ID, stepOverLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugCommandPaletteItem(STEP_INTO_ID, stepIntoLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugCommandPaletteItem(STEP_OUT_ID, stepOutLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugCommandPaletteItem(PAUSE_ID, pauseLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('running')); -registerDebugCommandPaletteItem(DISCONNECT_ID, disconnectLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_FOCUSED_SESSION_IS_ATTACH); -registerDebugCommandPaletteItem(STOP_ID, stopLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated()); -registerDebugCommandPaletteItem(CONTINUE_ID, continueLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCommandPaletteItem(STEP_OVER_ID, STEP_OVER_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCommandPaletteItem(STEP_INTO_ID, STEP_INTO_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCommandPaletteItem(STEP_OUT_ID, STEP_OUT_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCommandPaletteItem(PAUSE_ID, PAUSE_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('running')); +registerDebugCommandPaletteItem(DISCONNECT_ID, DISCONNECT_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_FOCUSED_SESSION_IS_ATTACH); +registerDebugCommandPaletteItem(STOP_ID, STOP_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated()); +registerDebugCommandPaletteItem(CONTINUE_ID, CONTINUE_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); registerDebugCommandPaletteItem(FOCUS_REPL_ID, nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugFocusConsole' }, 'Focus on Debug Console View')); registerDebugCommandPaletteItem(JUMP_TO_CURSOR_ID, nls.localize('jumpToCursor', "Jump to Cursor"), ContextKeyExpr.and(CONTEXT_JUMP_TO_CURSOR_SUPPORTED)); registerDebugCommandPaletteItem(RunToCursorAction.ID, RunToCursorAction.LABEL, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'))); @@ -264,6 +258,11 @@ configurationRegistry.registerConfiguration({ type: 'boolean', description: nls.localize('debug.focusWindowOnBreak', "Controls whether the workbench window should be focused when the debugger breaks."), default: true + }, + 'debug.onTaskErrors': { + enum: ['debugAnyway', 'showErrors', 'prompt'], + description: nls.localize('debug.onTaskErrors', "Controls what to do when errors are encountered after running a preLaunchTask."), + default: 'prompt' } } }); @@ -273,7 +272,7 @@ Registry.as(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, @@ -282,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, continueLabel, 'continue', 10, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(PAUSE_ID, pauseLabel, 'pause', 10, CONTEXT_DEBUG_STATE.notEqualsTo('stopped')); -registerDebugToolBarItem(STOP_ID, stopLabel, 'stop', 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated()); -registerDebugToolBarItem(DISCONNECT_ID, disconnectLabel, 'disconnect', 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH); -registerDebugToolBarItem(STEP_OVER_ID, stepOverLabel, 'step-over', 20, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(STEP_INTO_ID, stepIntoLabel, 'step-into', 30, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(STEP_OUT_ID, stepOutLabel, 'step-out', 40, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugToolBarItem(RESTART_SESSION_ID, restartLabel, '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') => { @@ -314,13 +313,13 @@ const registerDebugCallstackItem = (id: string, title: string, order: number, wh } }); }; -registerDebugCallstackItem(RESTART_SESSION_ID, restartLabel, 10, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('session')); -registerDebugCallstackItem(STOP_ID, stopLabel, 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('session')); -registerDebugCallstackItem(PAUSE_ID, pauseLabel, 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('running'))); -registerDebugCallstackItem(CONTINUE_ID, continueLabel, 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped'))); -registerDebugCallstackItem(STEP_OVER_ID, stepOverLabel, 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugCallstackItem(STEP_INTO_ID, stepIntoLabel, 30, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugCallstackItem(STEP_OUT_ID, stepOutLabel, 40, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCallstackItem(RESTART_SESSION_ID, RESTART_LABEL, 10, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('session')); +registerDebugCallstackItem(STOP_ID, STOP_LABEL, 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('session')); +registerDebugCallstackItem(PAUSE_ID, PAUSE_LABEL, 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('running'))); +registerDebugCallstackItem(CONTINUE_ID, CONTINUE_LABEL, 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped'))); +registerDebugCallstackItem(STEP_OVER_ID, STEP_OVER_LABEL, 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCallstackItem(STEP_INTO_ID, STEP_INTO_LABEL, 30, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCallstackItem(STEP_OUT_ID, STEP_OUT_LABEL, 40, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')); registerDebugCallstackItem(TERMINATE_THREAD_ID, nls.localize('terminateThread', "Terminate Thread"), 10, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), undefined, 'termination'); registerDebugCallstackItem(RESTART_FRAME_ID, nls.localize('restartFrame', "Restart Frame"), 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('stackFrame'), CONTEXT_RESTART_FRAME_SUPPORTED)); registerDebugCallstackItem(COPY_STACK_TRACE_ID, nls.localize('copyStackTrace', "Copy Call Stack"), 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('stackFrame')); @@ -539,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', @@ -552,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, continueLabel, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'continue-tb.png'); - registerTouchBarEntry(PAUSE_ID, pauseLabel, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), 'pause-tb.png'); - registerTouchBarEntry(STEP_OVER_ID, stepOverLabel, 2, CONTEXT_IN_DEBUG_MODE, 'stepover-tb.png'); - registerTouchBarEntry(STEP_INTO_ID, stepIntoLabel, 3, CONTEXT_IN_DEBUG_MODE, 'stepinto-tb.png'); - registerTouchBarEntry(STEP_OUT_ID, stepOutLabel, 4, CONTEXT_IN_DEBUG_MODE, 'stepout-tb.png'); - registerTouchBarEntry(RESTART_SESSION_ID, restartLabel, 5, CONTEXT_IN_DEBUG_MODE, 'restart-tb.png'); - registerTouchBarEntry(STOP_ID, stopLabel, 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/debugActionViewItems.ts b/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts index 8e4b12fde6c..1904bd302ad 100644 --- a/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts +++ b/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts @@ -209,7 +209,13 @@ export class FocusSessionActionViewItem extends SelectActionViewItem { } })); - this._register(this.debugService.onDidNewSession(() => this.update())); + this._register(this.debugService.onDidNewSession(session => { + this._register(session.onDidChangeName(() => this.update())); + this.update(); + })); + this.getSessions().forEach(session => { + this._register(session.onDidChangeName(() => this.update())); + }); this._register(this.debugService.onDidEndSession(() => this.update())); this.update(); diff --git a/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts index 7acca069182..d24aa5d5c1e 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -51,6 +51,15 @@ export const CONTINUE_ID = 'workbench.action.debug.continue'; export const FOCUS_REPL_ID = 'workbench.debug.action.focusRepl'; export const JUMP_TO_CURSOR_ID = 'debug.jumpToCursor'; +export const RESTART_LABEL = nls.localize('restartDebug', "Restart"); +export const STEP_OVER_LABEL = nls.localize('stepOverDebug', "Step Over"); +export const STEP_INTO_LABEL = nls.localize('stepIntoDebug', "Step Into"); +export const STEP_OUT_LABEL = nls.localize('stepOutDebug', "Step Out"); +export const PAUSE_LABEL = nls.localize('pauseDebug', "Pause"); +export const DISCONNECT_LABEL = nls.localize('disconnect', "Disconnect"); +export const STOP_LABEL = nls.localize('stop', "Stop"); +export const CONTINUE_LABEL = nls.localize('continueDebug', "Continue"); + function getThreadAndRun(accessor: ServicesAccessor, thread: IThread | undefined, run: (thread: IThread) => Promise, ): void { const debugService = accessor.get(IDebugService); if (!(thread instanceof Thread)) { @@ -224,9 +233,9 @@ export function registerCommands(): void { CommandsRegistry.registerCommand({ id: DISCONNECT_ID, - handler: (accessor: ServicesAccessor) => { + handler: (accessor: ServicesAccessor, _: string, session: IDebugSession | undefined) => { const debugService = accessor.get(IDebugService); - const session = debugService.getViewModel().focusedSession; + session = session || debugService.getViewModel().focusedSession; debugService.stopSession(session).then(undefined, onUnexpectedError); } }); 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 95bd40e002a..13898ad10bb 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -37,7 +37,7 @@ import { parse, getFirstFrame } from 'vs/base/common/console'; import { TaskEvent, TaskEventKind, TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { IAction, Action } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; import { deepClone, equals } from 'vs/base/common/objects'; import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; @@ -686,13 +686,18 @@ export class DebugService implements IDebugService { private runTaskAndCheckErrors(root: IWorkspaceFolder | undefined, taskId: string | TaskIdentifier | undefined): Promise { - const debugAnywayAction = new Action('debug.debugAnyway', nls.localize('debugAnyway', "Debug Anyway"), undefined, true, () => Promise.resolve(TaskRunResult.Success)); return this.runTask(root, taskId).then((taskSummary: ITaskSummary) => { + const errorCount = taskId ? this.markerService.getStatistics().errors : 0; const successExitCode = taskSummary && taskSummary.exitCode === 0; const failureExitCode = taskSummary && taskSummary.exitCode !== undefined && taskSummary.exitCode !== 0; - if (successExitCode || (errorCount === 0 && !failureExitCode)) { - return TaskRunResult.Success; + const onTaskErrors = this.configurationService.getValue('debug').onTaskErrors; + if (successExitCode || onTaskErrors === 'debugAnyway' || (errorCount === 0 && !failureExitCode)) { + return TaskRunResult.Success; + } + if (onTaskErrors === 'showErrors') { + this.panelService.openPanel(Constants.MARKERS_PANEL_ID); + return Promise.resolve(TaskRunResult.Failure); } const taskLabel = typeof taskId === 'string' ? taskId : taskId ? taskId.name : ''; @@ -702,14 +707,27 @@ export class DebugService implements IDebugService { ? nls.localize('preLaunchTaskError', "Error exists after running preLaunchTask '{0}'.", taskLabel) : nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", taskLabel, taskSummary.exitCode); - const showErrorsAction = new Action('debug.showErrors', nls.localize('showErrors', "Show Errors"), undefined, true, () => { + return this.dialogService.confirm({ + checkbox: { + label: nls.localize('remember', "Remember my choice in user settings"), + }, + message, + type: 'warning', + primaryButton: nls.localize('debugAnyway', "Debug Anyway"), + secondaryButton: nls.localize('showErrors', "Show Errors"), + }).then(result => { + if (result.checkboxChecked) { + this.configurationService.updateValue('debug.onTaskErrors', result.confirmed ? 'debugAnyway' : 'showErrors'); + } + if (result.confirmed) { + return TaskRunResult.Success; + } + this.panelService.openPanel(Constants.MARKERS_PANEL_ID); return Promise.resolve(TaskRunResult.Failure); }); - - return this.showError(message, [debugAnywayAction, showErrorsAction]); }, (err: TaskError) => { - return this.showError(err.message, [debugAnywayAction, this.taskService.configureAction()]); + return this.showError(err.message, [this.taskService.configureAction()]); }); } diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index 2839f067232..6f78bd0df67 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -55,6 +55,9 @@ export class DebugSession implements IDebugSession { private readonly _onDidChangeREPLElements = new Emitter(); + private name: string | undefined; + private readonly _onDidChangeName = new Emitter(); + constructor( private _configuration: { resolved: IConfig, unresolved: IConfig | undefined }, public root: IWorkspaceFolder, @@ -105,7 +108,13 @@ export class DebugSession implements IDebugSession { getLabel(): string { const includeRoot = this.workspaceContextService.getWorkspace().folders.length > 1; - return includeRoot && this.root ? `${this.configuration.name} (${resources.basenameOrAuthority(this.root.uri)})` : this.configuration.name; + const name = this.name || this.configuration.name; + return includeRoot && this.root ? `${name} (${resources.basenameOrAuthority(this.root.uri)})` : name; + } + + setName(name: string): void { + this.name = name; + this._onDidChangeName.fire(name); } get state(): State { @@ -144,6 +153,10 @@ export class DebugSession implements IDebugSession { return this._onDidChangeREPLElements.event; } + get onDidChangeName(): Event { + return this._onDidChangeName.event; + } + //---- DAP events get onDidCustomEvent(): Event { @@ -908,11 +921,11 @@ export class DebugSession implements IDebugSession { } async addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise { - const viewModel = this.debugService.getViewModel(); - 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. - this.debugService.focusStackFrame(viewModel.focusedStackFrame, viewModel.focusedThread, viewModel.focusedSession); 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/loadedScriptsView.ts b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts index e5bb9b72a6c..da8e4c728e8 100644 --- a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts +++ b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts @@ -466,7 +466,21 @@ export class LoadedScriptsView extends ViewletPanel { } })); - const registerLoadedSourceListener = (session: IDebugSession) => { + const scheduleRefreshOnVisible = () => { + if (this.isBodyVisible()) { + this.changeScheduler.schedule(); + } else { + this.treeNeedsRefreshOnVisible = true; + } + }; + + const registerSessionListeners = (session: IDebugSession) => { + this._register(session.onDidChangeName(() => { + // Re-add session, this will trigger proper sorting and id recalculation. + root.remove(session.getId()); + root.add(session); + scheduleRefreshOnVisible(); + })); this._register(session.onDidLoadedSource(event => { let sessionRoot: SessionTreeItem; switch (event.reason) { @@ -474,11 +488,7 @@ export class LoadedScriptsView extends ViewletPanel { case 'changed': sessionRoot = root.add(session); sessionRoot.addPath(event.source); - if (this.isBodyVisible()) { - this.changeScheduler.schedule(); - } else { - this.treeNeedsRefreshOnVisible = true; - } + scheduleRefreshOnVisible(); if (event.reason === 'changed') { DebugContentProvider.refreshDebugContent(event.source.uri); } @@ -486,11 +496,7 @@ export class LoadedScriptsView extends ViewletPanel { case 'removed': sessionRoot = root.find(session); if (sessionRoot && sessionRoot.removePath(event.source)) { - if (this.isBodyVisible()) { - this.changeScheduler.schedule(); - } else { - this.treeNeedsRefreshOnVisible = true; - } + scheduleRefreshOnVisible(); } break; default: @@ -501,8 +507,8 @@ export class LoadedScriptsView extends ViewletPanel { })); }; - this._register(this.debugService.onDidNewSession(registerLoadedSourceListener)); - this.debugService.getModel().getSessions().forEach(registerLoadedSourceListener); + this._register(this.debugService.onDidNewSession(registerSessionListeners)); + this.debugService.getModel().getSessions().forEach(registerSessionListeners); this._register(this.debugService.onDidEndSession(session => { root.remove(session.getId()); diff --git a/src/vs/workbench/contrib/debug/browser/media/continue-white.svg b/src/vs/workbench/contrib/debug/browser/media/continue-white.svg new file mode 100644 index 00000000000..69d48e9984e --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/continue-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css index 5255891ea42..2ed61ccf6b0 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css @@ -179,6 +179,27 @@ text-transform: uppercase; } +.debug-viewlet .debug-call-stack .thread:hover > .state, +.debug-viewlet .debug-call-stack .session:hover > .state, +.debug-viewlet .debug-call-stack .monaco-list-row.focused .state { + display: none; +} + +.debug-viewlet .debug-call-stack .monaco-list-row .monaco-action-bar { + display: none; +} + +.debug-viewlet .debug-call-stack .monaco-list-row.focused .monaco-action-bar, +.debug-viewlet .debug-call-stack .monaco-list-row:hover .monaco-action-bar { + display: initial; +} + +.monaco-workbench .debug-viewlet .debug-call-stack .monaco-action-bar .action-item > .action-label { + width: 16px; + height: 100%; + margin-right: 8px; +} + .debug-viewlet .debug-call-stack .thread > .state > .label, .debug-viewlet .debug-call-stack .session > .state > .label { background: rgba(136, 136, 136, 0.3); @@ -257,6 +278,102 @@ overflow: hidden; } +.debug-viewlet .debug-call-stack .debug-action.stop { + background: url('stop-light.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.stop { + background: url('stop-white.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.stop { + background: url('stop-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.disconnect { + background: url('disconnect-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.disconnect { + background: url('disconnect-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.disconnect { + background: url('disconnect-white.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.restart { + background: url('restart-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.restart { + background: url('restart-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.restart { + background: url('restart-white.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.step-over { + background: url('step-over-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.step-over { + background: url('step-over-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.step-over { + background: url('step-over-white.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.step-into { + background: url('step-into-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.step-into { + background: url('step-into-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.step-into { + background: url('step-into-white.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.step-out { + background: url('step-out-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.step-out { + background: url('step-out-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.step-out { + background: url('step-out-white.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.pause { + background: url('pause-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.pause { + background: url('pause-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.pause { + background: url('pause-white.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .debug-action.continue { + background: url('continue-light.svg') center center no-repeat; +} + +.vs-dark .debug-viewlet .debug-call-stack .debug-action.continue { + background: url('continue-dark.svg') center center no-repeat; +} + +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.continue { + background: url('continue-white.svg') center center no-repeat; +} + /* Variables & Expression view */ .debug-viewlet .scope { 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/pause-white.svg b/src/vs/workbench/contrib/debug/browser/media/pause-white.svg new file mode 100644 index 00000000000..bd634a35a5a --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/pause-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/media/restart-white.svg b/src/vs/workbench/contrib/debug/browser/media/restart-white.svg new file mode 100644 index 00000000000..cf498da0c7f --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/restart-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/step-into-white.svg b/src/vs/workbench/contrib/debug/browser/media/step-into-white.svg new file mode 100644 index 00000000000..77ef1cbf34b --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/step-into-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/step-out-white.svg b/src/vs/workbench/contrib/debug/browser/media/step-out-white.svg new file mode 100644 index 00000000000..906cd8d33ca --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/step-out-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/step-over-white.svg b/src/vs/workbench/contrib/debug/browser/media/step-over-white.svg new file mode 100644 index 00000000000..bac3022c88f --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/step-over-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/media/stop-white.svg b/src/vs/workbench/contrib/debug/browser/media/stop-white.svg new file mode 100644 index 00000000000..f33eb6181db --- /dev/null +++ b/src/vs/workbench/contrib/debug/browser/media/stop-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts index d8ad2212ace..7fde27d1231 100644 --- a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts @@ -583,15 +583,17 @@ export class RawDebugSession { const v = args[key]; if (v) { - if (Array.isArray(v)) { - v.push(value); - } else { - args[key] = [v, value]; - } + v.push(value); } else { - args[key] = value; + args[key] = [value]; + } + } else if (key === 'extensionDevelopmentPath') { + const v = args[key]; + if (v) { + v.push(value); + } else { + args[key] = [value]; } - } else { (args)[key] = value; } 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 165e135a452..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 { @@ -157,6 +157,8 @@ export interface IDebugSession extends ITreeElement { setSubId(subId: string | undefined): void; + setName(name: string): void; + readonly onDidChangeName: Event; getLabel(): string; getSourceForUri(modelUri: uri): Source | undefined; @@ -308,6 +310,7 @@ export interface IStackFrame extends ITreeElement { restart(): Promise; toString(): string; openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean): Promise; + equals(other: IStackFrame): boolean; } export interface IEnablement extends ITreeElement { @@ -452,6 +455,7 @@ export interface IDebugConfiguration { wordWrap: boolean; }; focusWindowOnBreak: boolean; + onTaskErrors: 'debugAnyway' | 'showErrors' | 'prompt'; } export interface IGlobalConfig { diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts index 676811f3fd6..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 { @@ -395,6 +339,10 @@ export class StackFrame implements IStackFrame { return !this.source.available ? Promise.resolve(null) : this.source.openInEditor(editorService, this.range, preserveFocus, sideBySide, pinned); } + + equals(other: IStackFrame): boolean { + return (this.name === other.name) && (other.thread === this.thread) && (other.source === this.source) && (Range.equalsRange(this.range, other.range)); + } } export class Thread implements IThread { @@ -901,7 +849,16 @@ export class DebugModel implements IDebugModel { if (!this.schedulers.has(thread.getId())) { this.schedulers.set(thread.getId(), new RunOnceScheduler(() => { thread.fetchCallStack(19).then(() => { - this._onDidChangeCallStack.fire(); + const stale = thread.getStaleCallStack(); + const current = thread.getCallStack(); + let bottomOfCallStackChanged = stale.length !== current.length; + for (let i = 1; i < stale.length && !bottomOfCallStackChanged; i++) { + bottomOfCallStackChanged = !stale[i].equals(current[i]); + } + + if (bottomOfCallStackChanged) { + this._onDidChangeCallStack.fire(); + } c(); }); }, 420)); diff --git a/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts b/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts index 8854146a484..5091ba1a598 100644 --- a/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts +++ b/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts @@ -10,7 +10,7 @@ declare module DebugProtocol { /** Base class of requests, responses, and events. */ export interface ProtocolMessage { - /** Sequence number. */ + /** Sequence number. For protocol messages of type 'request' this number can be used to cancel the request. */ seq: number; /** Message type. Values: 'request', 'response', 'event', etc. @@ -59,6 +59,25 @@ declare module DebugProtocol { }; } + /** Cancel request; value of command field is 'cancel'. + This request can be used to cancel another request. Clients should only call this request if the capability 'supportsCancelRequest' is true. + A request that got canceled still needs to send a response back. This can either be a partial result or an error response. + */ + export interface CancelRequest extends Request { + // command: 'cancel'; + arguments?: CancelArguments; + } + + /** Arguments for 'cancel' request. */ + export interface CancelArguments { + /** The ID (attribute 'seq') of the request to cancel. */ + requestId?: number; + } + + /** Response to 'cancel' request. This is just an acknowledgement, so no body field is required. */ + export interface CancelResponse extends Response { + } + /** Event message for 'initialized' event type. This event indicates that the debug adapter is ready to accept configuration requests (e.g. SetBreakpointsRequest, SetExceptionBreakpointsRequest). A debug adapter is expected to send this event when it is ready to accept configuration requests (but not before the 'initialize' request has finished). @@ -1330,6 +1349,8 @@ declare module DebugProtocol { supportsReadMemoryRequest?: boolean; /** The debug adapter supports the 'disassemble' request. */ supportsDisassembleRequest?: boolean; + /** The debug adapter supports the 'cancel' request. */ + supportsCancelRequest?: boolean; } /** An ExceptionBreakpointsFilter is shown in the UI as an option for configuring how exceptions are dealt with. */ diff --git a/src/vs/workbench/contrib/debug/common/debugUtils.ts b/src/vs/workbench/contrib/debug/common/debugUtils.ts index da2f6569e06..1c3e291b23c 100644 --- a/src/vs/workbench/contrib/debug/common/debugUtils.ts +++ b/src/vs/workbench/contrib/debug/common/debugUtils.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { equalsIgnoreCase } from 'vs/base/common/strings'; -import { IConfig, IDebuggerContribution, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; +import { IConfig, IDebuggerContribution, IDebugService, IDebugSession } from 'vs/workbench/contrib/debug/common/debug'; import { URI as uri } from 'vs/base/common/uri'; import { isAbsolute } from 'vs/base/common/path'; import { deepClone } from 'vs/base/common/objects'; @@ -42,6 +42,10 @@ export function formatPII(value: string, excludePII: boolean, args: { [key: stri }); } +export function isSessionAttach(session: IDebugSession): boolean { + return !session.parentSession && session.configuration.request === 'attach' && !isExtensionHostDebugging(session.configuration); +} + export function isExtensionHostDebugging(config: IConfig) { return config.type && equalsIgnoreCase(config.type === 'vslsShare' ? (config).adapterProxy.configuration.type : config.type, 'extensionhost'); } diff --git a/src/vs/workbench/contrib/debug/common/debugViewModel.ts b/src/vs/workbench/contrib/debug/common/debugViewModel.ts index 2f31cde6142..f261025e49d 100644 --- a/src/vs/workbench/contrib/debug/common/debugViewModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugViewModel.ts @@ -6,7 +6,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { CONTEXT_EXPRESSION_SELECTED, IViewModel, IStackFrame, IDebugSession, IThread, IExpression, IFunctionBreakpoint, CONTEXT_BREAKPOINT_SELECTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { isExtensionHostDebugging } from 'vs/workbench/contrib/debug/common/debugUtils'; +import { isSessionAttach } from 'vs/workbench/contrib/debug/common/debugUtils'; export class ViewModel implements IViewModel { @@ -71,7 +71,7 @@ export class ViewModel implements IViewModel { this.stepBackSupportedContextKey.set(session ? !!session.capabilities.supportsStepBack : false); this.restartFrameSupportedContextKey.set(session ? !!session.capabilities.supportsRestartFrame : false); this.jumpToCursorSupported.set(session ? !!session.capabilities.supportsGotoTargetsRequest : false); - const attach = !!session && !session.parentSession && session.configuration.request === 'attach' && !isExtensionHostDebugging(session.configuration); + const attach = !!session && isSessionAttach(session); this.focusedSessionIsAttach.set(attach); if (shouldEmitForSession) { 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/debug/test/common/mockDebug.ts b/src/vs/workbench/contrib/debug/test/common/mockDebug.ts index 1e83d444965..f70b8aee729 100644 --- a/src/vs/workbench/contrib/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/contrib/debug/test/common/mockDebug.ts @@ -180,6 +180,10 @@ export class MockSession implements IDebugSession { return 'mockname'; } + setName(name: string): void { + throw new Error('not implemented'); + } + getSourceForUri(modelUri: uri): Source { throw new Error('not implemented'); } @@ -204,6 +208,10 @@ export class MockSession implements IDebugSession { throw new Error('not implemented'); } + get onDidChangeName(): Event { + throw new Error('not implemented'); + } + setConfiguration(configuration: { resolved: IConfig, unresolved: IConfig }) { } getAllThreads(): IThread[] { diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 71a2b755343..fbdabd31fd4 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -1605,7 +1605,7 @@ export class ShowRecommendedExtensionsAction extends Action { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => { - viewlet.search('@recommended '); + viewlet.search('@recommended ', true); viewlet.focus(); }); } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index d9aef35dae5..b4b05abc5ec 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -59,11 +59,6 @@ import { RemoteNameContext } from 'vs/workbench/browser/contextkeys'; import { ILabelService } from 'vs/platform/label/common/label'; import { MementoObject } from 'vs/workbench/common/memento'; -interface SearchInputEvent extends Event { - target: HTMLInputElement; - immediate?: boolean; -} - const NonEmptyWorkspaceContext = new RawContextKey('nonEmptyWorkspace', false); const DefaultViewsContext = new RawContextKey('defaultExtensionViews', true); const SearchMarketplaceExtensionsContext = new RawContextKey('searchMarketplaceExtensions', false); @@ -488,12 +483,13 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio return this.secondaryActions; } - search(value: string): void { + search(value: string, refresh: boolean = false): void { if (this.searchBox) { - const event = new Event('input', { bubbles: true }) as SearchInputEvent; - event.immediate = true; - - this.searchBox.setValue(value); + if (this.searchBox.getValue() !== value) { + this.searchBox.setValue(value); + } else if (refresh) { + this.doSearch(); + } } } diff --git a/src/vs/workbench/contrib/extensions/common/extensions.ts b/src/vs/workbench/contrib/extensions/common/extensions.ts index 126a008a66b..402f9e0a2fe 100644 --- a/src/vs/workbench/contrib/extensions/common/extensions.ts +++ b/src/vs/workbench/contrib/extensions/common/extensions.ts @@ -23,7 +23,7 @@ export const VIEW_CONTAINER: ViewContainer = Registry.as { }); setup(() => { - instantiationService.stub(IEnvironmentService, >{ extensionDevelopmentPath: false }); + instantiationService.stub(IEnvironmentService, >{}); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', []); instantiationService.stub(IExtensionGalleryService, 'isEnabled', true); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(...mockExtensionGallery)); 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/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index bb0f7e04b7f..52583917ba0 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -50,7 +50,6 @@ import { first } from 'vs/base/common/arrays'; import { withNullAsUndefined } from 'vs/base/common/types'; import { IFileService, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; import { dispose } from 'vs/base/common/lifecycle'; -import { timeout } from 'vs/base/common/async'; export class ExplorerView extends ViewletPanel { static readonly ID: string = 'workbench.explorer.fileView'; @@ -522,8 +521,6 @@ export class ExplorerView extends ViewletPanel { while (item && item.resource.toString() !== resource.toString()) { await this.tree.expand(item); - // Tree returns too early from the expand, need to wait for next tick #77106 - await timeout(0); item = first(values(item.children), i => isEqualOrParent(resource, i.resource)); } diff --git a/src/vs/workbench/contrib/markers/browser/markersPanel.ts b/src/vs/workbench/contrib/markers/browser/markersPanel.ts index cea80184fe4..bbc4392c7f7 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanel.ts @@ -25,9 +25,9 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { localize } from 'vs/nls'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { Iterator } from 'vs/base/common/iterator'; -import { ITreeElement, ITreeNode, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree'; +import { ITreeElement, ITreeNode, ITreeContextMenuEvent, ITreeRenderer } from 'vs/base/browser/ui/tree/tree'; import { Relay, Event, Emitter } from 'vs/base/common/event'; -import { WorkbenchObjectTree, TreeResourceNavigator2 } from 'vs/platform/list/browser/listService'; +import { WorkbenchObjectTree, TreeResourceNavigator2, IListService } from 'vs/platform/list/browser/listService'; import { FilterOptions } from 'vs/workbench/contrib/markers/browser/markersFilterOptions'; import { IExpression } from 'vs/base/common/glob'; import { deepClone } from 'vs/base/common/objects'; @@ -40,11 +40,13 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; import { domEvent } from 'vs/base/browser/event'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ResourceLabels } from 'vs/workbench/browser/labels'; import { IMarker } from 'vs/platform/markers/common/markers'; import { withUndefinedAsNull } from 'vs/base/common/types'; import { MementoObject } from 'vs/workbench/common/memento'; +import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; +import { IObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree'; +import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; function createModelIterator(model: MarkersModel): Iterator> { const resourcesIt = Iterator.fromArray(model.resourceMarkers); @@ -69,30 +71,26 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { private lastSelectedRelativeTop: number = 0; private currentActiveResource: URI | null = null; - private tree: WorkbenchObjectTree; - private treeLabels: ResourceLabels; - private rangeHighlightDecorations: RangeHighlightDecorations; + private readonly rangeHighlightDecorations: RangeHighlightDecorations; + private readonly filter: Filter; - private actions: IAction[]; - private collapseAllAction: IAction; - private filterAction: MarkersFilterAction; - private filterInputActionViewItem: MarkersFilterActionViewItem; + private tree!: MarkersTree; + private messageBoxContainer!: HTMLElement; + private ariaLabelElement!: HTMLElement; + + private readonly collapseAllAction: IAction; + private readonly filterAction: MarkersFilterAction; + private filterInputActionViewItem: MarkersFilterActionViewItem | null = null; - private treeContainer: HTMLElement; - private messageBoxContainer: HTMLElement; - private ariaLabelElement: HTMLElement; private readonly panelState: MementoObject; private panelFoucusContextKey: IContextKey; - private filter: Filter; - private _onDidFilter = this._register(new Emitter()); readonly onDidFilter: Event = this._onDidFilter.event; private cachedFilterStats: { total: number; filtered: number; } | undefined = undefined; private currentResourceGotAddedToMarkersData: boolean = false; readonly markersViewModel: MarkersViewModel; - private disposables: IDisposable[] = []; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -111,15 +109,21 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { super(Constants.MARKERS_PANEL_ID, telemetryService, themeService, storageService); this.panelFoucusContextKey = Constants.MarkerPanelFocusContextKey.bindTo(contextKeyService); this.panelState = this.getMemento(StorageScope.WORKSPACE); - this.markersViewModel = instantiationService.createInstance(MarkersViewModel, this.panelState['multiline']); - this.markersViewModel.onDidChange(this.onDidChangeViewState, this, this.disposables); + this.markersViewModel = this._register(instantiationService.createInstance(MarkersViewModel, this.panelState['multiline'])); + this._register(this.markersViewModel.onDidChange(marker => this.onDidChangeViewState(marker))); this.setCurrentActiveEditor(); + + this.filter = new Filter(new FilterOptions()); + this.rangeHighlightDecorations = this._register(this.instantiationService.createInstance(RangeHighlightDecorations)); + + // actions + this.collapseAllAction = this._register(new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, async () => this.collapseAll())); + this.filterAction = this._register(this.instantiationService.createInstance(MarkersFilterAction, { filterText: this.panelState['filter'] || '', filterHistory: this.panelState['filterHistory'] || [], useFilesExclude: !!this.panelState['useFilesExclude'] })); } public create(parent: HTMLElement): void { super.create(parent); - this.rangeHighlightDecorations = this._register(this.instantiationService.createInstance(RangeHighlightDecorations)); dom.addClass(parent, 'markers-panel'); @@ -128,7 +132,6 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { this.createArialLabelElement(container); this.createMessageBox(container); this.createTree(container); - this.createActions(); this.createListeners(); this.updateFilter(); @@ -152,7 +155,6 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } public layout(dimension: dom.Dimension): void { - this.treeContainer.style.height = `${dimension.height}px`; this.tree.layout(dimension.height, dimension.width); if (this.filterInputActionViewItem) { this.filterInputActionViewItem.toggleLayout(dimension.width < 1200); @@ -178,10 +180,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } public getActions(): IAction[] { - if (!this.actions) { - this.createActions(); - } - return this.actions; + return [this.filterAction, this.collapseAllAction]; } public showQuickFixes(marker: Marker): void { @@ -254,7 +253,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } const { total, filtered } = this.getFilterStats(); - dom.toggleClass(this.treeContainer, 'hidden', total === 0 || filtered === 0); + this.tree.toggleVisibility(total === 0 || filtered === 0); this.renderMessage(); this._onDidFilter.fire(); } @@ -271,7 +270,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { this._onDidFilter.fire(); const { total, filtered } = this.getFilterStats(); - dom.toggleClass(this.treeContainer, 'hidden', total === 0 || filtered === 0); + this.tree.toggleVisibility(total === 0 || filtered === 0); this.renderMessage(); } @@ -302,19 +301,16 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } private createTree(parent: HTMLElement): void { - this.treeContainer = dom.append(parent, dom.$('.tree-container.show-file-icons')); - const onDidChangeRenderNodeCount = new Relay>(); - this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this)); + const treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this)); const virtualDelegate = new VirtualDelegate(this.markersViewModel); const renderers = [ - this.instantiationService.createInstance(ResourceMarkersRenderer, this.treeLabels, onDidChangeRenderNodeCount.event), + this.instantiationService.createInstance(ResourceMarkersRenderer, treeLabels, onDidChangeRenderNodeCount.event), this.instantiationService.createInstance(MarkerRenderer, this.markersViewModel), this.instantiationService.createInstance(RelatedInformationRenderer) ]; - this.filter = new Filter(new FilterOptions()); const accessibilityProvider = this.instantiationService.createInstance(MarkersTreeAccessibilityProvider); const identityProvider = { @@ -323,9 +319,9 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } }; - this.tree = this.instantiationService.createInstance(WorkbenchObjectTree, + this.tree = this._register(this.instantiationService.createInstance(MarkersTree, 'MarkersPanel', - this.treeContainer, + dom.append(parent, dom.$('.tree-container.show-file-icons')), virtualDelegate, renderers, { @@ -335,7 +331,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { dnd: new ResourceDragAndDrop(this.instantiationService), expandOnlyOnTwistieClick: (e: TreeElement) => e instanceof Marker && e.relatedInformation.length > 0 } - ); + )); onDidChangeRenderNodeCount.input = this.tree.onDidChangeRenderNodeCount; @@ -396,17 +392,12 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { })); } - private createActions(): void { - this.collapseAllAction = new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, async () => { - this.tree.collapseAll(); - this.tree.setSelection([]); - this.tree.setFocus([]); - this.tree.getHTMLElement().focus(); - this.tree.focusFirst(); - }); - - this.filterAction = this.instantiationService.createInstance(MarkersFilterAction, { filterText: this.panelState['filter'] || '', filterHistory: this.panelState['filterHistory'] || [], useFilesExclude: !!this.panelState['useFilesExclude'] }); - this.actions = [this.filterAction, this.collapseAllAction]; + private collapseAll(): void { + this.tree.collapseAll(); + this.tree.setSelection([]); + this.tree.setFocus([]); + this.tree.getHTMLElement().focus(); + this.tree.focusFirst(); } private createListeners(): void { @@ -423,7 +414,6 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { this.updateFilter(); } })); - this.actions.forEach(a => this._register(a)); } private onDidChangeModel(change: MarkerChangesEvent) { @@ -485,7 +475,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { private render(): void { this.cachedFilterStats = undefined; this.tree.setChildren(null, createModelIterator(this.markersWorkbenchService.markersModel)); - dom.toggleClass(this.treeContainer, 'hidden', this.isEmpty()); + this.tree.toggleVisibility(this.isEmpty()); this.renderMessage(); } @@ -735,10 +725,33 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { super.saveState(); } - public dispose(): void { - super.dispose(); - this.tree.dispose(); - this.markersViewModel.dispose(); - this.disposables = dispose(this.disposables); - } +} + +class MarkersTree extends WorkbenchObjectTree { + + constructor( + user: string, + readonly container: HTMLElement, + delegate: IListVirtualDelegate, + renderers: ITreeRenderer[], + options: IObjectTreeOptions, + @IContextKeyService contextKeyService: IContextKeyService, + @IListService listService: IListService, + @IThemeService themeService: IThemeService, + @IConfigurationService configurationService: IConfigurationService, + @IKeybindingService keybindingService: IKeybindingService, + @IAccessibilityService accessibilityService: IAccessibilityService + ) { + super(user, container, delegate, renderers, options, contextKeyService, listService, themeService, configurationService, keybindingService, accessibilityService); + } + + layout(height: number, width: number): void { + this.container.style.height = `${height}px`; + super.layout(height, width); + } + + toggleVisibility(hide: boolean): void { + dom.toggleClass(this.container, 'hidden', hide); + } + } diff --git a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts index f2747c02b15..c45dee82e5d 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts @@ -118,10 +118,9 @@ export interface IMarkerFilterController { export class MarkersFilterActionViewItem extends BaseActionViewItem { private delayedFilterUpdate: Delayer; - private container: HTMLElement; - private filterInputBox: HistoryInputBox; - private controlsContainer: HTMLInputElement; - private filterBadge: HTMLInputElement; + private container: HTMLElement | null = null; + private filterInputBox: HistoryInputBox | null = null; + private filterBadge: HTMLElement | null = null; private focusContextKey: IContextKey; constructor( @@ -172,13 +171,13 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { this.filterInputBox.inputElement.setAttribute('aria-labelledby', 'markers-panel-arialabel'); this._register(attachInputBoxStyler(this.filterInputBox, this.themeService)); this.filterInputBox.value = this.action.filterText; - this._register(this.filterInputBox.onDidChange(filter => this.delayedFilterUpdate.trigger(() => this.onDidInputChange(this.filterInputBox)))); + this._register(this.filterInputBox.onDidChange(filter => this.delayedFilterUpdate.trigger(() => this.onDidInputChange(this.filterInputBox!)))); this._register(this.action.onDidChange((event: IMarkersFilterActionChangeEvent) => { if (event.filterText) { - this.filterInputBox.value = this.action.filterText; + this.filterInputBox!.value = this.action.filterText; } })); - this._register(DOM.addStandardDisposableListener(this.filterInputBox.inputElement, DOM.EventType.KEY_DOWN, (e: any) => this.onInputKeyDown(e, this.filterInputBox))); + this._register(DOM.addStandardDisposableListener(this.filterInputBox.inputElement, DOM.EventType.KEY_DOWN, (e: any) => this.onInputKeyDown(e, this.filterInputBox!))); this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_DOWN, this.handleKeyboardEvent)); this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_UP, this.handleKeyboardEvent)); @@ -189,24 +188,24 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { } private createControls(container: HTMLElement): void { - this.controlsContainer = DOM.append(container, DOM.$('.markers-panel-filter-controls')); - this.createBadge(this.controlsContainer); - this.createFilesExcludeCheckbox(this.controlsContainer); + const controlsContainer = DOM.append(container, DOM.$('.markers-panel-filter-controls')); + this.createBadge(controlsContainer); + this.createFilesExcludeCheckbox(controlsContainer); } private createBadge(container: HTMLElement): void { - this.filterBadge = DOM.append(container, DOM.$('.markers-panel-filter-badge')); + const filterBadge = this.filterBadge = DOM.append(container, DOM.$('.markers-panel-filter-badge')); this._register(attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { const background = colors.badgeBackground ? colors.badgeBackground.toString() : null; const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : null; const border = colors.contrastBorder ? colors.contrastBorder.toString() : null; - this.filterBadge.style.backgroundColor = background; + filterBadge.style.backgroundColor = background; - this.filterBadge.style.borderWidth = border ? '1px' : null; - this.filterBadge.style.borderStyle = border ? 'solid' : null; - this.filterBadge.style.borderColor = border; - this.filterBadge.style.color = foreground; + filterBadge.style.borderWidth = border ? '1px' : null; + filterBadge.style.borderStyle = border ? 'solid' : null; + filterBadge.style.borderColor = border; + filterBadge.style.color = foreground; })); this.updateBadge(); this._register(this.filterController.onDidFilter(() => this.updateBadge())); @@ -241,14 +240,18 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { } private updateBadge(): void { - const { total, filtered } = this.filterController.getFilterStats(); - DOM.toggleClass(this.filterBadge, 'hidden', total === filtered || filtered === 0); - this.filterBadge.textContent = localize('showing filtered problems', "Showing {0} of {1}", filtered, total); - this.adjustInputBox(); + if (this.filterBadge) { + const { total, filtered } = this.filterController.getFilterStats(); + DOM.toggleClass(this.filterBadge, 'hidden', total === filtered || filtered === 0); + this.filterBadge.textContent = localize('showing filtered problems', "Showing {0} of {1}", filtered, total); + this.adjustInputBox(); + } } private adjustInputBox(): void { - this.filterInputBox.inputElement.style.paddingRight = DOM.hasClass(this.container, 'small') || DOM.hasClass(this.filterBadge, 'hidden') ? '25px' : '150px'; + if (this.container && this.filterInputBox && this.filterBadge) { + this.filterInputBox.inputElement.style.paddingRight = DOM.hasClass(this.container, 'small') || DOM.hasClass(this.filterBadge, 'hidden') ? '25px' : '150px'; + } } // Action toolbar is swallowing some keys for action items which should not be for an input box diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index 156c52dd125..bf6546b0d72 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -510,7 +510,7 @@ export class MarkerViewModel extends Disposable { } } - private _quickFixAction: QuickFixAction; + private _quickFixAction: QuickFixAction | null = null; get quickFixAction(): QuickFixAction { if (!this._quickFixAction) { this._quickFixAction = this._register(this.instantiationService.createInstance(QuickFixAction, this.marker)); @@ -616,7 +616,7 @@ export class MarkersViewModel extends Disposable { private bulkUpdate: boolean = false; - private hoveredMarker: Marker | null; + private hoveredMarker: Marker | null = null; private hoverDelayer: Delayer = new Delayer(300); constructor( 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/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/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index 4e724b3d988..356f87830bd 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -63,15 +63,15 @@ export class PreferencesEditor extends BaseEditor { private defaultSettingsEditorContextKey: IContextKey; private defaultSettingsJSONEditorContextKey: IContextKey; private searchFocusContextKey: IContextKey; - private headerContainer: HTMLElement; - private searchWidget: SearchWidget; - private sideBySidePreferencesWidget: SideBySidePreferencesWidget; - private preferencesRenderers: PreferencesRenderersController; + private headerContainer!: HTMLElement; + private searchWidget!: SearchWidget; + private sideBySidePreferencesWidget!: SideBySidePreferencesWidget; + private preferencesRenderers!: PreferencesRenderersController; private delayedFilterLogging: Delayer; private localSearchDelayer: Delayer; private remoteSearchThrottle: ThrottledDelayer; - private _lastReportedFilter: string; + private _lastReportedFilter: string | null = null; private lastFocusedWidget: SearchWidget | SideBySidePreferencesWidget | undefined = undefined; @@ -298,7 +298,7 @@ export class PreferencesEditor extends BaseEditor { return result; } - private reportFilteringUsed(filter: string, filterResult: IFilterResult | undefined): void { + private reportFilteringUsed(filter: string, filterResult: IFilterResult | null): void { if (filter && filter !== this._lastReportedFilter) { const metadata = filterResult && filterResult.metadata; const counts = filterResult && this._countById(filterResult.filteredGroups); @@ -354,20 +354,20 @@ interface IPreferencesCount { class PreferencesRenderersController extends Disposable { - private _defaultPreferencesRenderer: IPreferencesRenderer; + private _defaultPreferencesRenderer!: IPreferencesRenderer; private _defaultPreferencesRendererDisposables: IDisposable[] = []; - private _editablePreferencesRenderer: IPreferencesRenderer; + private _editablePreferencesRenderer!: IPreferencesRenderer; private _editablePreferencesRendererDisposables: IDisposable[] = []; - private _settingsNavigator: SettingsNavigator; - private _remoteFilterCancelToken: CancellationTokenSource | undefined; + private _settingsNavigator: SettingsNavigator | null = null; + private _remoteFilterCancelToken: CancellationTokenSource | null = null; private _prefsModelsForSearch = new Map(); - private _currentLocalSearchProvider: ISearchProvider; - private _currentRemoteSearchProvider: ISearchProvider | undefined; - private _lastQuery: string; - private _lastFilterResult: IFilterResult | undefined; + private _currentLocalSearchProvider: ISearchProvider | null = null; + private _currentRemoteSearchProvider: ISearchProvider | null = null; + private _lastQuery = ''; + private _lastFilterResult: IFilterResult | null = null; private readonly _onDidFilterResultsCountChange: Emitter = this._register(new Emitter()); readonly onDidFilterResultsCountChange: Event = this._onDidFilterResultsCountChange.event; @@ -382,7 +382,7 @@ class PreferencesRenderersController extends Disposable { super(); } - get lastFilterResult(): IFilterResult | undefined { + get lastFilterResult(): IFilterResult | null { return this._lastFilterResult; } @@ -445,16 +445,16 @@ class PreferencesRenderersController extends Disposable { if (this._remoteFilterCancelToken) { this._remoteFilterCancelToken.cancel(); this._remoteFilterCancelToken.dispose(); - this._remoteFilterCancelToken = undefined; + this._remoteFilterCancelToken = null; } - this._currentRemoteSearchProvider = (updateCurrentResults && this._currentRemoteSearchProvider) || this.preferencesSearchService.getRemoteSearchProvider(query); + this._currentRemoteSearchProvider = (updateCurrentResults && this._currentRemoteSearchProvider) || this.preferencesSearchService.getRemoteSearchProvider(query) || null; this._remoteFilterCancelToken = new CancellationTokenSource(); return this.filterOrSearchPreferences(query, this._currentRemoteSearchProvider!, 'nlpResult', nls.localize('nlpResult', "Natural Language Results"), 1, this._remoteFilterCancelToken.token, updateCurrentResults).then(() => { if (this._remoteFilterCancelToken) { this._remoteFilterCancelToken.dispose(); - this._remoteFilterCancelToken = undefined; + this._remoteFilterCancelToken = null; } }, err => { if (isPromiseCanceledError(err)) { @@ -489,11 +489,11 @@ class PreferencesRenderersController extends Disposable { let [editableFilterResult, defaultFilterResult] = results; if (!defaultFilterResult && editableContentOnly) { - defaultFilterResult = this.lastFilterResult; + defaultFilterResult = this.lastFilterResult!; } this.consolidateAndUpdate(defaultFilterResult, editableFilterResult); - this._lastFilterResult = defaultFilterResult; + this._lastFilterResult = withUndefinedAsNull(defaultFilterResult); return !!(defaultFilterResult && defaultFilterResult.exactMatch); }); @@ -766,7 +766,7 @@ class SideBySidePreferencesWidget extends Widget { private defaultPreferencesHeader: HTMLElement; private defaultPreferencesEditor: DefaultPreferencesEditor; - private editablePreferencesEditor: BaseEditor; + private editablePreferencesEditor: BaseEditor | null = null; private defaultPreferencesEditorContainer: HTMLElement; private editablePreferencesEditorContainer: HTMLElement; @@ -780,7 +780,7 @@ class SideBySidePreferencesWidget extends Widget { private splitview: SplitView; - private isVisible: boolean; + private isVisible = false; private group: IEditorGroup | undefined; get minimumWidth(): number { return this.splitview.minimumSize; } @@ -850,7 +850,7 @@ class SideBySidePreferencesWidget extends Widget { this.settingsTargetsWidget.settingsTarget = this.getSettingsTarget(editablePreferencesEditorInput.getResource()!); return Promise.all([ this.updateInput(this.defaultPreferencesEditor, defaultPreferencesEditorInput, DefaultSettingsEditorContribution.ID, editablePreferencesEditorInput.getResource()!, options, token), - this.updateInput(this.editablePreferencesEditor, editablePreferencesEditorInput, SettingsEditorContribution.ID, defaultPreferencesEditorInput.getResource()!, options, token) + this.updateInput(this.editablePreferencesEditor!, editablePreferencesEditorInput, SettingsEditorContribution.ID, defaultPreferencesEditorInput.getResource()!, options, token) ]) .then(([defaultPreferencesRenderer, editablePreferencesRenderer]) => { if (token.isCancellationRequested) { @@ -1078,7 +1078,7 @@ interface ISettingsEditorContribution extends editorCommon.IEditorContribution { abstract class AbstractSettingsEditorContribution extends Disposable implements ISettingsEditorContribution { - private preferencesRendererCreationPromise: Promise | null> | null; + private preferencesRendererCreationPromise: Promise | null> | null = null; constructor(protected editor: ICodeEditor, @IInstantiationService protected instantiationService: IInstantiationService, diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts index ccede6e64c6..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; @@ -56,7 +57,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend private editSettingActionRenderer: EditSettingRenderer; private highlightMatchesRenderer: HighlightMatchesRenderer; private modelChangeDelayer: Delayer = new Delayer(200); - private associatedPreferencesModel: IPreferencesEditorModel; + private associatedPreferencesModel!: IPreferencesEditorModel; private readonly _onFocusPreference = this._register(new Emitter()); readonly onFocusPreference: Event = this._onFocusPreference.event; @@ -228,7 +229,7 @@ export class FolderSettingsRenderer extends UserSettingsRenderer implements IPre export class DefaultSettingsRenderer extends Disposable implements IPreferencesRenderer { - private _associatedPreferencesModel: IPreferencesEditorModel; + private _associatedPreferencesModel!: IPreferencesEditorModel; private settingHighlighter: SettingHighlighter; private settingsHeaderRenderer: DefaultSettingsHeaderRenderer; private settingsGroupTitleRenderer: SettingsGroupTitleRenderer; @@ -362,7 +363,7 @@ export interface HiddenAreasProvider { export class BracesHidingRenderer extends Disposable implements HiddenAreasProvider { private _result: IFilterResult | undefined; - private _settingsGroups: ISettingsGroup[]; + private _settingsGroups!: ISettingsGroup[]; constructor(private editor: ICodeEditor) { super(); @@ -444,9 +445,9 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea private readonly _onHiddenAreasChanged = this._register(new Emitter()); readonly onHiddenAreasChanged: Event = this._onHiddenAreasChanged.event; - private settingsGroups: ISettingsGroup[]; + private settingsGroups!: ISettingsGroup[]; private hiddenGroups: ISettingsGroup[] = []; - private settingsGroupTitleWidgets: SettingsGroupTitleWidget[]; + private settingsGroupTitleWidgets!: SettingsGroupTitleWidget[]; private readonly renderDisposables = this._register(new DisposableStore()); constructor(private editor: ICodeEditor, @@ -648,7 +649,7 @@ class EditSettingRenderer extends Disposable { private editPreferenceWidgetForMouseMove: EditPreferenceWidget; private settingsGroups: ISettingsGroup[] = []; - associatedPreferencesModel: IPreferencesEditorModel; + associatedPreferencesModel!: IPreferencesEditorModel; private toggleEditPreferencesForMouseMoveDelayer: Delayer; private readonly _onUpdateSetting: Emitter<{ key: string, value: any, source: IIndexedSetting }> = new Emitter<{ key: string, value: any, source: IIndexedSetting }>(); @@ -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(); @@ -915,7 +916,7 @@ class SettingHighlighter extends Disposable { private fixedHighlighter: RangeHighlightDecorations; private volatileHighlighter: RangeHighlightDecorations; - private highlightedSetting: ISetting; + private highlightedSetting!: ISetting; constructor(private editor: ICodeEditor, private readonly focusEventEmitter: Emitter, private readonly clearFocusEventEmitter: Emitter, @IInstantiationService instantiationService: IInstantiationService @@ -1090,7 +1091,7 @@ class UnsupportedSettingsRenderer extends Disposable { class WorkspaceConfigurationRenderer extends Disposable { private decorationIds: string[] = []; - private associatedSettingsEditorModel: IPreferencesEditorModel; + private associatedSettingsEditorModel!: IPreferencesEditorModel; private renderingDelayer: Delayer = new Delayer(200); constructor(private editor: ICodeEditor, private workspaceSettingsEditorModel: SettingsEditorModel, diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts index 66678cbfffb..c683b6dab4c 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts @@ -33,14 +33,15 @@ 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 { - private id: string; - private _domNode: HTMLElement; + private id!: string; + private _domNode!: HTMLElement; - protected titleContainer: HTMLElement; - private messageElement: HTMLElement; + protected titleContainer!: HTMLElement; + private messageElement!: HTMLElement; constructor(protected editor: ICodeEditor, private title: string) { super(); @@ -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'; } } @@ -121,18 +123,18 @@ export class DefaultSettingsHeaderWidget extends SettingsHeaderWidget { export class SettingsGroupTitleWidget extends Widget implements IViewZone { - private id: string; - private _afterLineNumber: number; - private _domNode: HTMLElement; + private id!: string; + private _afterLineNumber!: number; + private _domNode!: HTMLElement; - private titleContainer: HTMLElement; - private icon: HTMLElement; - private title: HTMLElement; + private titleContainer!: HTMLElement; + private icon!: HTMLElement; + private title!: HTMLElement; private _onToggled = this._register(new Emitter()); readonly onToggled: Event = this._onToggled.event; - private previousPosition: Position; + private previousPosition: Position | null = null; constructor(private editor: ICodeEditor, public settingsGroup: ISettingsGroup) { super(); @@ -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; } @@ -296,11 +299,11 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { private _folder: IWorkspaceFolder | null; private _folderSettingCounts = new Map(); - private container: HTMLElement; - private anchorElement: HTMLElement; - private labelElement: HTMLElement; - private detailsElement: HTMLElement; - private dropDownElement: HTMLElement; + private container!: HTMLElement; + private anchorElement!: HTMLElement; + private labelElement!: HTMLElement; + private detailsElement!: HTMLElement; + private dropDownElement!: HTMLElement; constructor( action: IAction, @@ -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); } } @@ -468,14 +467,14 @@ export interface ISettingsTargetsWidgetOptions { export class SettingsTargetsWidget extends Widget { - private settingsSwitcherBar: ActionBar; - private userLocalSettings: Action; - private userRemoteSettings: Action; - private workspaceSettings: Action; - private folderSettings: FolderSettingsActionViewItem; + private settingsSwitcherBar!: ActionBar; + private userLocalSettings!: Action; + private userRemoteSettings!: Action; + private workspaceSettings!: Action; + private folderSettings!: FolderSettingsActionViewItem; private options: ISettingsTargetsWidgetOptions; - private _settingsTarget: SettingsTarget; + private _settingsTarget: SettingsTarget | null = null; private readonly _onDidTargetChange = this._register(new Emitter()); readonly onDidTargetChange: Event = this._onDidTargetChange.event; @@ -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(); @@ -525,11 +525,11 @@ export class SettingsTargetsWidget extends Widget { this.settingsSwitcherBar.push([this.userLocalSettings, this.userRemoteSettings, this.workspaceSettings, folderSettingsAction]); } - get settingsTarget(): SettingsTarget { + get settingsTarget(): SettingsTarget | null { return this._settingsTarget; } - set settingsTarget(settingsTarget: SettingsTarget) { + set settingsTarget(settingsTarget: SettingsTarget | null) { this._settingsTarget = settingsTarget; this.userLocalSettings.checked = ConfigurationTarget.USER_LOCAL === this.settingsTarget; this.userRemoteSettings.checked = ConfigurationTarget.USER_REMOTE === this.settingsTarget; @@ -602,12 +602,12 @@ export interface SearchOptions extends IInputOptions { export class SearchWidget extends Widget { - domNode: HTMLElement; + domNode!: HTMLElement; - private countElement: HTMLElement; - private searchContainer: HTMLElement; - inputBox: InputBox; - private controlsDiv: HTMLElement; + private countElement!: HTMLElement; + private searchContainer!: HTMLElement; + inputBox!: InputBox; + private controlsDiv!: HTMLElement; private readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; @@ -739,8 +739,8 @@ export class EditPreferenceWidget extends Disposable { static readonly GLYPH_MARGIN_CLASS_NAME = 'edit-preferences-widget'; - private _line: number; - private _preferences: T[]; + private _line: number = -1; + private _preferences: T[] = []; private _editPreferenceDecoration: string[]; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 9a49fcd1425..7e3bca1e76f 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -85,54 +85,55 @@ export class SettingsEditor2 extends BaseEditor { type === SettingValueType.Exclude; } - private defaultSettingsEditorModel: Settings2EditorModel; + // (!) Lots of props that are set once on the first render + private defaultSettingsEditorModel!: Settings2EditorModel; - private rootElement: HTMLElement; - private headerContainer: HTMLElement; - private searchWidget: SuggestEnabledInput; - private countElement: HTMLElement; - private settingsTargetsWidget: SettingsTargetsWidget; + private rootElement!: HTMLElement; + private headerContainer!: HTMLElement; + private searchWidget!: SuggestEnabledInput; + private countElement!: HTMLElement; + private settingsTargetsWidget!: SettingsTargetsWidget; - private settingsTreeContainer: HTMLElement; - private settingsTree: SettingsTree; - private settingRenderers: SettingTreeRenderers; - private tocTreeModel: TOCTreeModel; - private settingsTreeModel: SettingsTreeModel; - private noResultsMessage: HTMLElement; - private clearFilterLinkContainer: HTMLElement; + private settingsTreeContainer!: HTMLElement; + private settingsTree!: SettingsTree; + private settingRenderers!: SettingTreeRenderers; + private tocTreeModel!: TOCTreeModel; + private settingsTreeModel!: SettingsTreeModel; + private noResultsMessage!: HTMLElement; + private clearFilterLinkContainer!: HTMLElement; - private tocTreeContainer: HTMLElement; - private tocTree: TOCTree; + private tocTreeContainer!: HTMLElement; + private tocTree!: TOCTree; - private settingsAriaExtraLabelsContainer: HTMLElement; + private settingsAriaExtraLabelsContainer!: HTMLElement; private delayedFilterLogging: Delayer; private localSearchDelayer: Delayer; private remoteSearchThrottle: ThrottledDelayer; - private searchInProgress: CancellationTokenSource | null; + private searchInProgress: CancellationTokenSource | null = null; private settingFastUpdateDelayer: Delayer; private settingSlowUpdateDelayer: Delayer; - private pendingSettingUpdate: { key: string, value: any } | null; + private pendingSettingUpdate: { key: string, value: any } | null = null; private readonly viewState: ISettingsEditorViewState; - private _searchResultModel: SearchResultModel | null; + private _searchResultModel: SearchResultModel | null = null; private tocRowFocused: IContextKey; private inSettingsEditorContextKey: IContextKey; private searchFocusContextKey: IContextKey; private scheduledRefreshes: Map; - private lastFocusedSettingElement: string; + private lastFocusedSettingElement: string | null = null; /** Don't spam warnings */ - private hasWarnedMissingSettings: boolean; + private hasWarnedMissingSettings = false; private editorMemento: IEditorMemento; - private tocFocusedElement: SettingsTreeGroupElement | null; + private tocFocusedElement: SettingsTreeGroupElement | null = null; private settingsTreeScrollTop = 0; - private dimension: DOM.Dimension; + private dimension!: DOM.Dimension; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -463,7 +464,7 @@ export class SettingsEditor2 extends BaseEditor { return this.openSettingsFile(query.query); } - private openSettingsFile(query?: string): Promise { + private async openSettingsFile(query?: string): Promise { const currentSettingsTarget = this.settingsTargetsWidget.settingsTarget; const options: ISettingsEditorOptions = { query }; @@ -473,9 +474,11 @@ export class SettingsEditor2 extends BaseEditor { return this.preferencesService.openRemoteSettings(); } else if (currentSettingsTarget === ConfigurationTarget.WORKSPACE) { return this.preferencesService.openWorkspaceSettings(true, options); - } else { + } else if (URI.isUri(currentSettingsTarget)) { return this.preferencesService.openFolderSettings(currentSettingsTarget, true, options); } + + return undefined; } private createBody(parent: HTMLElement): void { diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts index efe952907cd..eb76fe7dbd4 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts @@ -33,6 +33,11 @@ export abstract class SettingsTreeElement { * Index assigned in display order, used for paging. */ index: number; + + constructor(_id: string, _index: number) { + this.id = _id; + this.index = _index; + } } export type SettingsTreeGroupChild = (SettingsTreeGroupElement | SettingsTreeSettingElement | SettingsTreeNewExtensionsElement); @@ -43,8 +48,8 @@ export class SettingsTreeGroupElement extends SettingsTreeElement { level: number; isFirstGroup: boolean; - private _childSettingKeys: Set; - private _children: SettingsTreeGroupChild[]; + private _childSettingKeys: Set = new Set(); + private _children: SettingsTreeGroupChild[] = []; get children(): SettingsTreeGroupChild[] { return this._children; @@ -61,6 +66,15 @@ export class SettingsTreeGroupElement extends SettingsTreeElement { }); } + constructor(_id: string, _index: number, count: number | undefined, label: string, level: number, isFirstGroup: boolean) { + super(_id, _index); + + this.count = count; + this.label = label; + this.level = level; + this.isFirstGroup = isFirstGroup; + } + /** * Returns whether this group contains the given child key (to a depth of 1 only) */ @@ -70,7 +84,9 @@ export class SettingsTreeGroupElement extends SettingsTreeElement { } export class SettingsTreeNewExtensionsElement extends SettingsTreeElement { - extensionIds: string[]; + constructor(_id: string, _index: number, public readonly extensionIds: string[]) { + super(_id, _index); + } } export class SettingsTreeSettingElement extends SettingsTreeElement { @@ -78,8 +94,8 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { setting: ISetting; - private _displayCategory: string; - private _displayLabel: string; + private _displayCategory: string | null = null; + private _displayLabel: string | null = null; /** * scopeValue || defaultValue, for rendering convenience. @@ -99,19 +115,17 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { /** * Whether the setting is configured in the selected scope. */ - isConfigured: boolean; + isConfigured = false; tags?: Set; - overriddenScopeList: string[]; - description: string; - valueType: SettingValueType; + overriddenScopeList: string[] = []; + description!: string; + valueType!: SettingValueType; constructor(setting: ISetting, parent: SettingsTreeGroupElement, index: number, inspectResult: IInspectResult) { - super(); - this.index = index; + super(sanitizeId(parent.id + '_' + setting.key), index); this.setting = setting; this.parent = parent; - this.id = sanitizeId(parent.id + '_' + setting.key); this.update(inspectResult); } @@ -121,7 +135,7 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { this.initLabel(); } - return this._displayCategory; + return this._displayCategory!; } get displayLabel(): string { @@ -129,7 +143,7 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { this.initLabel(); } - return this._displayLabel; + return this._displayLabel!; } private initLabel(): void { @@ -270,10 +284,10 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { } export class SettingsTreeModel { - protected _root: SettingsTreeGroupElement; + protected _root!: SettingsTreeGroupElement; protected _treeElementsById = new Map(); private _treeElementsBySettingName = new Map(); - private _tocRoot: ITOCEntry; + private _tocRoot!: ITOCEntry; constructor( protected _viewState: ISettingsEditorViewState, @@ -320,13 +334,10 @@ export class SettingsTreeModel { } private createSettingsTreeGroupElement(tocEntry: ITOCEntry, parent?: SettingsTreeGroupElement): SettingsTreeGroupElement { - const element = new SettingsTreeGroupElement(); + const index = this._treeElementsById.size; - element.index = index; - element.id = tocEntry.id; - element.label = tocEntry.label; - element.parent = parent; - element.level = this.getDepth(element); + const depth = parent ? this.getDepth(parent) + 1 : 0; + const element = new SettingsTreeGroupElement(tocEntry.id, index, undefined, tocEntry.label, depth, false); const children: SettingsTreeGroupChild[] = []; if (tocEntry.settings) { @@ -482,9 +493,9 @@ export const enum SearchResultIdx { } export class SearchResultModel extends SettingsTreeModel { - private rawSearchResults: ISearchResult[]; - private cachedUniqueSearchResults: ISearchResult[] | undefined; - private newExtensionSearchResults: ISearchResult; + private rawSearchResults: ISearchResult[] | null = null; + private cachedUniqueSearchResults: ISearchResult[] | null = null; + private newExtensionSearchResults: ISearchResult | null = null; readonly id = 'searchResultModel'; @@ -526,11 +537,11 @@ export class SearchResultModel extends SettingsTreeModel { } getRawResults(): ISearchResult[] { - return this.rawSearchResults; + return this.rawSearchResults || []; } setResult(order: SearchResultIdx, result: ISearchResult | null): void { - this.cachedUniqueSearchResults = undefined; + this.cachedUniqueSearchResults = null; this.rawSearchResults = this.rawSearchResults || []; if (!result) { delete this.rawSearchResults[order]; @@ -554,17 +565,14 @@ export class SearchResultModel extends SettingsTreeModel { .filter(child => child instanceof SettingsTreeSettingElement && child.matchesAllTags(this._viewState.tagFilters) && child.matchesScope(this._viewState.settingsTarget, isRemote) && child.matchesAnyExtension(this._viewState.extensionFilters)); if (this.newExtensionSearchResults && this.newExtensionSearchResults.filterMatches.length) { - const newExtElement = new SettingsTreeNewExtensionsElement(); - newExtElement.index = this._treeElementsById.size; - newExtElement.parent = this._root; - newExtElement.id = 'newExtensions'; - this._treeElementsById.set(newExtElement.id, newExtElement); - const resultExtensionIds = this.newExtensionSearchResults.filterMatches .map(result => (result.setting)) .filter(setting => setting.extensionName && setting.extensionPublisher) .map(setting => `${setting.extensionPublisher}.${setting.extensionName}`); - newExtElement.extensionIds = arrays.distinct(resultExtensionIds); + + const newExtElement = new SettingsTreeNewExtensionsElement('newExtensions', this._treeElementsById.size, arrays.distinct(resultExtensionIds)); + newExtElement.parent = this._root; + this._treeElementsById.set(newExtElement.id, newExtElement); this._root.children.push(newExtElement); } } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts index a52e919c7bf..798a9b00514 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts @@ -136,8 +136,8 @@ type EditKey = 'none' | 'create' | number; export class ListSettingListModel { private _dataItems: IListDataItem[] = []; - private _editKey: EditKey; - private _selectedIdx: number | null; + private _editKey: EditKey | null = null; + private _selectedIdx: number | null = null; get items(): IListViewItem[] { const items = this._dataItems.map((item, i) => { diff --git a/src/vs/workbench/contrib/preferences/browser/tocTree.ts b/src/vs/workbench/contrib/preferences/browser/tocTree.ts index 6a4df8af7d0..0576d491913 100644 --- a/src/vs/workbench/contrib/preferences/browser/tocTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/tocTree.ts @@ -23,8 +23,8 @@ const $ = DOM.$; export class TOCTreeModel { - private _currentSearchModel: SearchResultModel | null; - private _settingsTreeRoot: SettingsTreeGroupElement; + private _currentSearchModel: SearchResultModel | null = null; + private _settingsTreeRoot!: SettingsTreeGroupElement; constructor( private _viewState: ISettingsEditorViewState, diff --git a/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts b/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts index 9bfb056d4ed..a0090bae844 100644 --- a/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts @@ -62,7 +62,7 @@ class CommandsHistory extends Disposable { private static readonly PREF_KEY_CACHE = 'commandPalette.mru.cache'; private static readonly PREF_KEY_COUNTER = 'commandPalette.mru.counter'; - private commandHistoryLength!: number; + private commandHistoryLength = 0; constructor( @IStorageService private readonly storageService: IStorageService, 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/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index 404f5a2a78d..8ec38b3795e 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -7,7 +7,7 @@ import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as import { Registry } from 'vs/platform/registry/common/platform'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { ILabelService } from 'vs/platform/label/common/label'; -import { OperatingSystem } from 'vs/base/common/platform'; +import { OperatingSystem, isWeb } from 'vs/base/common/platform'; import { Schemas } from 'vs/base/common/network'; import { IRemoteAgentService, RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService'; import { ILogService } from 'vs/platform/log/common/log'; @@ -61,7 +61,8 @@ export class LabelContribution implements IWorkbenchContribution { label: '${path}', separator: remoteEnvironment.os === OperatingSystem.Windows ? '\\' : '/', tildify: remoteEnvironment.os !== OperatingSystem.Windows, - normalizeDriveLetter: remoteEnvironment.os === OperatingSystem.Windows + normalizeDriveLetter: remoteEnvironment.os === OperatingSystem.Windows, + workspaceSuffix: isWeb ? undefined : Schemas.vscodeRemote } }); } diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts deleted file mode 100644 index dfad93af11f..00000000000 --- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts +++ /dev/null @@ -1,137 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { URI } from 'vs/base/common/uri'; - -//#region --- lib.webworker.d.ts madness --- - -interface ExtendableEvent extends Event { - waitUntil(f: any): void; -} - -interface FetchEvent extends ExtendableEvent { - readonly clientId: string; - readonly preloadResponse: Promise; - readonly replacesClientId: string; - readonly request: Request; - readonly resultingClientId: string; - respondWith(r: Response | Promise): void; -} -interface ExtendableMessageEvent extends ExtendableEvent { - readonly data: any; - readonly lastEventId: string; - readonly origin: string; - readonly ports: ReadonlyArray; - readonly source: ServiceWorker | MessagePort | null; -} - -interface ServiceWorkerGlobalScopeEventMap { - 'activate': ExtendableEvent; - 'fetch': FetchEvent; - 'install': ExtendableEvent; - 'message': ExtendableMessageEvent; - 'messageerror': MessageEvent; -} - -interface Clients { - claim(): Promise; - get(id: string): Promise; -} - -interface ServiceWorkerGlobalScope { - readonly clients: Clients; - onactivate: ((this: ServiceWorkerGlobalScope, ev: ExtendableEvent) => any) | null; - onfetch: ((this: ServiceWorkerGlobalScope, ev: FetchEvent) => any) | null; - oninstall: ((this: ServiceWorkerGlobalScope, ev: ExtendableEvent) => any) | null; - onmessage: ((this: ServiceWorkerGlobalScope, ev: ExtendableMessageEvent) => any) | null; - onmessageerror: ((this: ServiceWorkerGlobalScope, ev: MessageEvent) => any) | null; - readonly registration: ServiceWorkerRegistration; - skipWaiting(): Promise; - addEventListener(type: K, listener: (this: ServiceWorkerGlobalScope, ev: ServiceWorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; - removeEventListener(type: K, listener: (this: ServiceWorkerGlobalScope, ev: ServiceWorkerGlobalScopeEventMap[K]) => any, options?: boolean | EventListenerOptions): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; -} - -//#endregion - -declare var self: ServiceWorkerGlobalScope; - -//#region --- installing/activating - -self.addEventListener('install', _event => { - console.log('SW#install'); - self.skipWaiting(); -}); - -self.addEventListener('activate', event => { - console.log('SW#activate'); - event.waitUntil((async () => { - // (1) enable navigation preloads! - // (2) delete caches with each new version - // (3) become available to all pages - if (self.registration.navigationPreload) { - await self.registration.navigationPreload.enable(); - } - await caches.delete(_cacheName); - await self.clients.claim(); - })()); -}); - -//#endregion - -//#region --- fetching/caching - -const _cacheName = 'vscode-extension-resources'; -const _resourcePrefix = '/vscode-remote-resource'; -const _pendingFetch = new Map(); - -self.addEventListener('message', event => { - const fn = _pendingFetch.get(event.data.token); - if (fn) { - fn(event.data.data, event.data.isExtensionResource); - _pendingFetch.delete(event.data.token); - } -}); - -self.addEventListener('fetch', async (event: FetchEvent) => { - - const uri = URI.parse(event.request.url); - if (uri.path !== _resourcePrefix) { - // not a /vscode-resources/fetch-url and therefore - // not (yet?) interesting for us - event.respondWith(respondWithDefault(event)); - return; - } - - event.respondWith(respondWithResource(event, uri)); -}); - -async function respondWithDefault(event: FetchEvent): Promise { - if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { - // https://bugs.chromium.org/p/chromium/issues/detail?id=823392 - // https://stackoverflow.com/questions/48463483/what-causes-a-failed-to-execute-fetch-on-serviceworkerglobalscope-only-if#49719964 - // https://developer.mozilla.org/en-US/docs/Web/API/Request/cache - return new Response(undefined, { status: 504, statusText: 'Gateway Timeout (dev tools: https://bugs.chromium.org/p/chromium/issues/detail?id=823392)' }); - } - return await event.preloadResponse || await fetch(event.request); -} - -async function respondWithResource(event: FetchEvent, uri: URI): Promise { - - const cachedValue = await caches.open(_cacheName).then(cache => cache.match(event.request)); - if (cachedValue) { - return cachedValue; - } - - const response: Response = await event.preloadResponse || await fetch(event.request); - if (response.headers.get('X-VSCode-Extension') === 'true') { - await caches.open(_cacheName).then(cache => cache.put(event.request, response.clone())); - } - - return response; -} - -//#endregion diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts deleted file mode 100644 index 935753f002d..00000000000 --- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts +++ /dev/null @@ -1,36 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; -import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { ILogService } from 'vs/platform/log/common/log'; - -class ResourceServiceWorker { - - private static _url = require.toUrl('./resourceServiceWorkerMain.js'); - - constructor( - @ILogService private readonly _logService: ILogService, - ) { - navigator.serviceWorker.register(ResourceServiceWorker._url, { scope: '/' }).then(reg => { - this._logService.trace('SW#reg', reg); - return reg.update(); - }).then(() => { - this._logService.info('SW#ready'); - }).catch(err => { - this._logService.error('SW#init', err); - }); - - } - -} - -Registry.as(Extensions.Workbench).registerWorkbenchContribution( - ResourceServiceWorker, - LifecyclePhase.Ready -); - - diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts deleted file mode 100644 index 89e7d32eae6..00000000000 --- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts +++ /dev/null @@ -1,26 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -// This file is to bootstrap AMD so that we can program as usual -// Note the fetch, install, activate event handler must be registered -// when loading the service worker and despite AMD's async nature this -// works. That's because the/our AMD loader uses the sync importScripts -// statement. - -// trigger service worker updates -const _tag = '23549971-9b8d-41bb-92ae-d7f6a68c9702'; - -// loader world -const baseUrl = '../../../../../'; -importScripts(baseUrl + 'vs/loader.js'); -require.config({ - baseUrl, - catchError: true -}); -require(['vs/workbench/contrib/resources/browser/resourceServiceWorker'], - () => { }, - err => console.error(err) -); - 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/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index 6c1b3ed6182..e01dbff4d32 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -495,7 +495,7 @@ class ResourceRenderer implements IListRenderer const theme = this.themeService.getTheme(); const icon = theme.type === LIGHT ? resource.decorations.icon : resource.decorations.iconDark; - template.fileLabel.setFile(resource.sourceUri, { fileDecorations: { colors: false, badges: !icon, data: resource.decorations } }); + template.fileLabel.setFile(resource.sourceUri, { fileDecorations: { colors: false, badges: !icon } }); template.actionBar.clear(); template.actionBar.context = resource; diff --git a/src/vs/workbench/contrib/scm/common/scm.ts b/src/vs/workbench/contrib/scm/common/scm.ts index 5e1afd2d5fb..106a85c5f81 100644 --- a/src/vs/workbench/contrib/scm/common/scm.ts +++ b/src/vs/workbench/contrib/scm/common/scm.ts @@ -10,7 +10,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Command } from 'vs/editor/common/modes'; -import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; import { ISequence } from 'vs/base/common/sequence'; export const VIEWLET_ID = 'workbench.view.scm'; @@ -28,10 +27,6 @@ export interface ISCMResourceDecorations { tooltip?: string; strikeThrough?: boolean; faded?: boolean; - - source?: string; - letter?: string; - color?: ColorIdentifier; } export interface ISCMResource { diff --git a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts index c6851d2fa40..2dc5484c534 100644 --- a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts +++ b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts @@ -29,14 +29,14 @@ export class PatternInputWidget extends Widget { static OPTION_CHANGE: string = 'optionChange'; - inputFocusTracker: dom.IFocusTracker; + inputFocusTracker!: dom.IFocusTracker; private width: number; private placeholder: string; private ariaLabel: string; - private domNode: HTMLElement; - protected inputBox: HistoryInputBox; + private domNode!: HTMLElement; + protected inputBox!: HistoryInputBox; private _onSubmit = this._register(new Emitter()); onSubmit: CommonEvent = this._onSubmit.event; @@ -148,7 +148,7 @@ export class PatternInputWidget extends Widget { this.setInputWidth(); } - protected renderSubcontrols(controlsDiv: HTMLDivElement): void { + protected renderSubcontrols(_controlsDiv: HTMLDivElement): void { } private onInputKeyUp(keyboardEvent: IKeyboardEvent) { @@ -174,7 +174,7 @@ export class ExcludePatternInputWidget extends PatternInputWidget { super(parent, contextViewProvider, options, themeService, contextKeyService); } - private useExcludesAndIgnoreFilesBox: Checkbox; + private useExcludesAndIgnoreFilesBox!: Checkbox; dispose(): void { super.dispose(); @@ -209,4 +209,4 @@ export class ExcludePatternInputWidget extends PatternInputWidget { controlsDiv.appendChild(this.useExcludesAndIgnoreFilesBox.domNode); super.renderSubcontrols(controlsDiv); } -} \ 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 4399e11c6fa..e4993dde0bd 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -78,9 +78,9 @@ export class SearchView extends ViewletPanel { private static readonly WIDE_VIEW_SIZE = 1000; private static readonly ACTIONS_RIGHT_CLASS_NAME = 'actions-right'; - private isDisposed: boolean; + private isDisposed = false; - private container: HTMLElement; + private container!: HTMLElement; private queryBuilder: QueryBuilder; private viewModel: SearchModel; private memento: Memento; @@ -99,31 +99,31 @@ export class SearchView extends ViewletPanel { private matchFocused: IContextKey; private hasSearchResultsKey: IContextKey; - private state: SearchUIState; + private state: SearchUIState = SearchUIState.Idle; private actions: Array = []; private cancelAction: CancelSearchAction; private refreshAction: RefreshAction; - private contextMenu: IMenu; + private contextMenu: IMenu | null = null; - private tree: WorkbenchObjectTree; - private treeLabels: ResourceLabels; + private tree!: WorkbenchObjectTree; + private treeLabels!: ResourceLabels; private viewletState: MementoObject; - private messagesElement: HTMLElement; + private messagesElement!: HTMLElement; private messageDisposables: IDisposable[] = []; - private searchWidgetsContainerElement: HTMLElement; - private searchWidget: SearchWidget; - private size: dom.Dimension; - private queryDetails: HTMLElement; - private toggleQueryDetailsButton: HTMLElement; - private inputPatternExcludes: ExcludePatternInputWidget; - private inputPatternIncludes: PatternInputWidget; - private resultsElement: HTMLElement; + private searchWidgetsContainerElement!: HTMLElement; + private searchWidget!: SearchWidget; + private size!: dom.Dimension; + private queryDetails!: HTMLElement; + private toggleQueryDetailsButton!: HTMLElement; + private inputPatternExcludes!: ExcludePatternInputWidget; + private inputPatternIncludes!: PatternInputWidget; + private resultsElement!: HTMLElement; private currentSelectedFileMatch: FileMatch | undefined; private delayedRefresh: Delayer; - private changedWhileHidden: boolean; + private changedWhileHidden: boolean = false; private searchWithoutFolderMessageElement: HTMLElement | undefined; @@ -441,7 +441,7 @@ export class SearchView extends ViewletPanel { private refreshAndUpdateCount(event?: IChangeEvent): void { this.searchWidget.setReplaceAllActionState(!this.viewModel.searchResult.isEmpty()); - this.updateSearchResultCount(this.viewModel.searchResult.query.userDisabledExcludesAndIgnoreFiles); + this.updateSearchResultCount(this.viewModel.searchResult.query!.userDisabledExcludesAndIgnoreFiles); return this.refreshTree(event); } @@ -711,7 +711,7 @@ export class SearchView extends ViewletPanel { const [selected] = this.tree.getSelection(); // Expand the initial selected node, if needed - if (selected instanceof FileMatch) { + if (selected && !(selected instanceof Match)) { if (this.tree.isCollapsed(selected)) { this.tree.expand(selected); } @@ -721,23 +721,24 @@ export class SearchView extends ViewletPanel { let next = navigator.next(); if (!next) { - // Reached the end - get a new navigator from the root. - navigator = this.tree.navigate(); next = navigator.first(); } - // Expand and go past FileMatch nodes + // Expand until first child is a Match while (!(next instanceof Match)) { if (this.tree.isCollapsed(next)) { this.tree.expand(next); } - // Select the FileMatch's first child + // Select the first child next = navigator.next(); } // Reveal the newly selected element if (next) { + if (next === selected) { + this.tree.setFocus([]); + } this.tree.setFocus([next], getSelectionKeyboardEvent(undefined, false)); this.tree.reveal(next); } @@ -749,34 +750,24 @@ export class SearchView extends ViewletPanel { let prev = navigator.previous(); - // Expand and go past FileMatch nodes - if (!(prev instanceof Match)) { - prev = navigator.previous(); - if (!prev) { - // Wrap around - prev = navigator.last(); + // Select previous until find a Match or a collapsed item + while (!prev || (!(prev instanceof Match) && !this.tree.isCollapsed(prev))) { + prev = prev ? navigator.previous() : navigator.last(); + } - // This is complicated because .last will set the navigator to the last FileMatch, - // so expand it and FF to its last child - this.tree.expand(prev); - let tmp: RenderableMatch | null; - while (tmp = navigator.next()) { - prev = tmp; - } - } - - if (!(prev instanceof Match)) { - // There is a second non-Match result, which must be a collapsed FileMatch. - // Expand it then select its last child. - const nextItem = navigator.next(); - this.tree.expand(prev); - navigator = this.tree.navigate(nextItem); // recreate navigator because modifying the tree can invalidate it - prev = navigator.previous(); - } + // Expand until last child is a Match + while (!(prev instanceof Match)) { + const nextItem = navigator.next(); + this.tree.expand(prev); + navigator = this.tree.navigate(nextItem); // recreate navigator because modifying the tree can invalidate it + prev = nextItem ? navigator.previous() : navigator.last(); // select last child } // Reveal the newly selected element if (prev) { + if (prev === selected) { + this.tree.setFocus([]); + } this.tree.setFocus([prev], getSelectionKeyboardEvent(undefined, false)); this.tree.reveal(prev); } @@ -1232,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 26b29b280c1..634e3aaa00e 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -58,7 +58,7 @@ class ReplaceAllAction extends Action { return ReplaceAllAction.fgInstance; } - private _searchWidget: SearchWidget; + private _searchWidget: SearchWidget | null = null; constructor() { super(ReplaceAllAction.ID, '', 'action-replace-all', false); @@ -84,25 +84,25 @@ export class SearchWidget extends Widget { return appendKeyBindingLabel(nls.localize('search.action.replaceAll.enabled.label', "Replace All"), kb, keyBindingService2); } - domNode: HTMLElement; + domNode!: HTMLElement; - searchInput: FindInput; - searchInputFocusTracker: dom.IFocusTracker; + searchInput!: FindInput; + searchInputFocusTracker!: dom.IFocusTracker; private searchInputBoxFocused: IContextKey; - private replaceContainer: HTMLElement; - replaceInput: HistoryInputBox; - private toggleReplaceButton: Button; - private replaceAllAction: ReplaceAllAction; + private replaceContainer!: HTMLElement; + replaceInput!: HistoryInputBox; + private toggleReplaceButton!: Button; + private replaceAllAction!: ReplaceAllAction; private replaceActive: IContextKey; - private replaceActionBar: ActionBar; - replaceInputFocusTracker: dom.IFocusTracker; + private replaceActionBar!: ActionBar; + replaceInputFocusTracker!: dom.IFocusTracker; private replaceInputBoxFocused: IContextKey; private _replaceHistoryDelayer: Delayer; - private _preserveCase: Checkbox; + private _preserveCase!: Checkbox; private ignoreGlobalFindBufferOnNextFocus = false; - private previousGlobalFindBufferValue: string; + private previousGlobalFindBufferValue: string | null = null; private _onSearchSubmit = this._register(new Emitter()); readonly onSearchSubmit: Event = this._onSearchSubmit.event; @@ -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/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index 7d003d61cd4..4596fe3173a 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -188,11 +188,11 @@ export class FileMatch extends Disposable implements IFileMatch { readonly onDispose: Event = this._onDispose.event; private _resource: URI; - private _model: ITextModel | null; - private _modelListener: IDisposable; + private _model: ITextModel | null = null; + private _modelListener: IDisposable | null = null; private _matches: Map; private _removedMatches: Set; - private _selectedMatch: Match | null; + private _selectedMatch: Match | null = null; private _updateScheduler: RunOnceScheduler; private _modelDecorations: string[] = []; @@ -244,7 +244,7 @@ export class FileMatch extends Disposable implements IFileMatch { this._updateScheduler.cancel(); this._model.deltaDecorations(this._modelDecorations, []); this._model = null; - this._modelListener.dispose(); + this._modelListener!.dispose(); } } @@ -633,10 +633,10 @@ export class SearchResult extends Disposable { readonly onChange: Event = this._onChange.event; private _folderMatches: FolderMatchWithResource[] = []; - private _otherFilesMatch: FolderMatch; + private _otherFilesMatch: FolderMatch | null = null; private _folderMatchesMap: TernarySearchTree = TernarySearchTree.forPaths(); - private _showHighlights: boolean; - private _query: ITextQuery; + private _showHighlights: boolean = false; + private _query: ITextQuery | null = null; private _rangeHighlightDecorations: RangeHighlightDecorations; @@ -653,14 +653,18 @@ export class SearchResult extends Disposable { this._register(this.modelService.onModelAdded(model => this.onModelAdded(model))); } - get query(): ITextQuery { + get query(): ITextQuery | null { return this._query; } - set query(query: ITextQuery) { + set query(query: ITextQuery | null) { // When updating the query we could change the roots, so ensure we clean up the old roots first. this.clear(); - this._folderMatches = (query.folderQueries || []) + if (!query) { + return; + } + + this._folderMatches = (query && query.folderQueries || []) .map(fq => fq.folder) .map((resource, index) => this.createFolderMatchWithResource(resource, resource.toString(), index, query)); @@ -717,6 +721,8 @@ export class SearchResult extends Disposable { clear(): void { this.folderMatches().forEach((folderMatch) => folderMatch.clear()); this.disposeMatches(); + this._folderMatches = []; + this._otherFilesMatch = null; } remove(matches: FileMatch | FolderMatch | (FileMatch | FolderMatch)[]): void { @@ -835,7 +841,7 @@ export class SearchResult extends Disposable { private getFolderMatch(resource: URI): FolderMatch { const folderMatch = this._folderMatchesMap.findSubstr(resource.toString()); - return folderMatch ? folderMatch : this._otherFilesMatch; + return folderMatch ? folderMatch : this._otherFilesMatch!; } private set replacingAll(running: boolean) { @@ -896,7 +902,7 @@ export class SearchModel extends Disposable { private readonly _onReplaceTermChanged: Emitter = this._register(new Emitter()); readonly onReplaceTermChanged: Event = this._onReplaceTermChanged.event; - private currentCancelTokenSource: CancellationTokenSource; + private currentCancelTokenSource: CancellationTokenSource | null = null; constructor( @ISearchService private readonly searchService: ISearchService, @@ -976,21 +982,19 @@ export class SearchModel extends Disposable { */ onFirstRenderStopwatch(duration => this.telemetryService.publicLog('searchResultsFirstRender', { duration })); - const onDoneStopwatch = Event.stopwatch(onDone); const start = Date.now(); - - /* __GDPR__ - "searchResultsFinished" : { - "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true } - } - */ - onDoneStopwatch(duration => this.telemetryService.publicLog('searchResultsFinished', { duration })); - currentRequest.then( value => this.onSearchCompleted(value, Date.now() - start), e => this.onSearchError(e, Date.now() - start)); - return currentRequest; + return currentRequest.finally(() => { + /* __GDPR__ + "searchResultsFinished" : { + "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true } + } + */ + this.telemetryService.publicLog('searchResultsFinished', { duration: Date.now() - start }); + }); } private onSearchCompleted(completed: ISearchComplete | null, duration: number): ISearchComplete | null { @@ -1064,7 +1068,7 @@ export type RenderableMatch = FolderMatch | FolderMatchWithResource | FileMatch export class SearchWorkbenchService implements ISearchWorkbenchService { _serviceBrand: undefined; - private _searchModel: SearchModel; + private _searchModel: SearchModel | null = null; constructor(@IInstantiationService private readonly instantiationService: IInstantiationService) { } diff --git a/src/vs/workbench/contrib/search/test/common/searchModel.test.ts b/src/vs/workbench/contrib/search/test/common/searchModel.test.ts index 7ad9e679d1f..38d90f655d0 100644 --- a/src/vs/workbench/contrib/search/test/common/searchModel.test.ts +++ b/src/vs/workbench/contrib/search/test/common/searchModel.test.ts @@ -21,14 +21,14 @@ import { SearchModel } from 'vs/workbench/contrib/search/common/searchModel'; import * as process from 'vs/base/common/process'; const nullEvent = new class { - id: number; - topic: string; - name: string; - description: string; + id: number = -1; + topic!: string; + name!: string; + description!: string; data: any; - startTime: Date; - stopTime: Date; + startTime!: Date; + stopTime!: Date; stop(): void { return; 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 2f8360d29be..9fc55917fc8 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -2152,7 +2152,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return taskPromise.then((taskMap) => { type EntryType = (IQuickPickItem & { task: Task; }) | (IQuickPickItem & { folder: IWorkspaceFolder; }); let entries: QuickPickInput[] = []; - if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { + if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY) { let tasks = taskMap.all(); let needsCreateOrOpen: boolean = true; if (tasks.length > 0) { diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index 354af731840..f03460bfdee 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -60,7 +60,7 @@ interface ActiveTerminalData { class VariableResolver { - constructor(public workspaceFolder: IWorkspaceFolder, public taskSystemInfo: TaskSystemInfo | undefined, private _values: Map, private _service: IConfigurationResolverService | undefined) { + constructor(public workspaceFolder: IWorkspaceFolder | undefined, public taskSystemInfo: TaskSystemInfo | undefined, private _values: Map, private _service: IConfigurationResolverService | undefined) { } resolve(value: string): string { return value.replace(/\$\{(.*?)\}/g, (match: string, variable: string) => { @@ -389,7 +389,7 @@ export class TerminalTaskSystem implements ITaskSystem { } } - private resolveVariablesFromSet(taskSystemInfo: TaskSystemInfo | undefined, workspaceFolder: IWorkspaceFolder, task: CustomTask | ContributedTask, variables: Set): Promise { + private resolveVariablesFromSet(taskSystemInfo: TaskSystemInfo | undefined, workspaceFolder: IWorkspaceFolder | undefined, task: CustomTask | ContributedTask, variables: Set): Promise { let isProcess = task.command && task.command.runtime === RuntimeType.Process; let options = task.command && task.command.options ? task.command.options : undefined; let cwd = options ? options.cwd : undefined; @@ -406,7 +406,7 @@ export class TerminalTaskSystem implements ITaskSystem { } let resolvedVariables: Promise; - if (taskSystemInfo) { + if (taskSystemInfo && workspaceFolder) { let resolveSet: ResolveSet = { variables }; @@ -463,10 +463,7 @@ export class TerminalTaskSystem implements ITaskSystem { private executeCommand(task: CustomTask | ContributedTask, trigger: string): Promise { const workspaceFolder = this.currentTask.workspaceFolder = task.getWorkspaceFolder(); - if (workspaceFolder === undefined) { - return Promise.reject(new Error(`Must have workspace folder${task._label}`)); - } - const systemInfo = this.currentTask.systemInfo = this.taskSystemInfoResolver(workspaceFolder); + const systemInfo: TaskSystemInfo | undefined = this.currentTask.systemInfo = workspaceFolder ? this.taskSystemInfoResolver(workspaceFolder) : undefined; let variables = new Set(); this.collectTaskVariables(variables, task); @@ -515,7 +512,7 @@ export class TerminalTaskSystem implements ITaskSystem { } } - private async executeInTerminal(task: CustomTask | ContributedTask, trigger: string, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder): Promise { + private async executeInTerminal(task: CustomTask | ContributedTask, trigger: string, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder | undefined): Promise { let terminal: ITerminalInstance | undefined = undefined; let executedCommand: string | undefined = undefined; let error: TaskError | undefined = undefined; @@ -761,7 +758,7 @@ export class TerminalTaskSystem implements ITaskSystem { }); } - private createTerminalName(task: CustomTask | ContributedTask, workspaceFolder: IWorkspaceFolder): string { + private createTerminalName(task: CustomTask | ContributedTask): string { const needsFolderQualification = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; return nls.localize('TerminalTaskSystem.terminalName', 'Task - {0}', needsFolderQualification ? task.getQualifiedLabel() : task.configurationProperties.name); } @@ -774,14 +771,14 @@ export class TerminalTaskSystem implements ITaskSystem { return URI.from({ scheme: Schemas.file, path: this.environmentService.userHome }); } - private async createShellLaunchConfig(task: CustomTask | ContributedTask, workspaceFolder: IWorkspaceFolder, variableResolver: VariableResolver, platform: Platform.Platform, options: CommandOptions, command: CommandString, args: CommandString[], waitOnExit: boolean | string): Promise { + private async createShellLaunchConfig(task: CustomTask | ContributedTask, workspaceFolder: IWorkspaceFolder | undefined, variableResolver: VariableResolver, platform: Platform.Platform, options: CommandOptions, command: CommandString, args: CommandString[], waitOnExit: boolean | string): Promise { let shellLaunchConfig: IShellLaunchConfig; let isShellCommand = task.command.runtime === RuntimeType.Shell; let needsFolderQualification = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; - let terminalName = this.createTerminalName(task, workspaceFolder); + let terminalName = this.createTerminalName(task); let originalCommand = task.command.name; if (isShellCommand) { - const defaultConfig = await this.terminalInstanceService.getDefaultShellAndArgs(true, platform); + const defaultConfig = variableResolver.taskSystemInfo ? await variableResolver.taskSystemInfo.getDefaultShellAndArgs() : await this.terminalInstanceService.getDefaultShellAndArgs(true, platform); shellLaunchConfig = { name: terminalName, executable: defaultConfig.shell, args: defaultConfig.args, waitOnExit }; let shellSpecified: boolean = false; let shellOptions: ShellConfiguration | undefined = task.command.options && task.command.options.shell; @@ -846,7 +843,7 @@ export class TerminalTaskSystem implements ITaskSystem { shellArgs.push(commandLine); shellLaunchConfig.args = windowsShellArgs ? shellArgs.join(' ') : shellArgs; if (task.command.presentation && task.command.presentation.echo) { - if (needsFolderQualification) { + if (needsFolderQualification && workspaceFolder) { shellLaunchConfig.initialText = `\x1b[1m> Executing task in folder ${workspaceFolder.name}: ${commandLine} <\x1b[0m\n`; } else { shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${commandLine} <\x1b[0m\n`; @@ -875,7 +872,7 @@ export class TerminalTaskSystem implements ITaskSystem { } return args.join(' '); }; - if (needsFolderQualification) { + if (needsFolderQualification && workspaceFolder) { shellLaunchConfig.initialText = `\x1b[1m> Executing task in folder ${workspaceFolder.name}: ${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)} <\x1b[0m\n`; } else { shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)} <\x1b[0m\n`; @@ -886,7 +883,6 @@ export class TerminalTaskSystem implements ITaskSystem { if (options.cwd) { let cwd = options.cwd; if (!path.isAbsolute(cwd)) { - let workspaceFolder = task.getWorkspaceFolder(); if (workspaceFolder && (workspaceFolder.uri.scheme === 'file')) { cwd = path.join(workspaceFolder.uri.fsPath, cwd); } @@ -900,7 +896,7 @@ export class TerminalTaskSystem implements ITaskSystem { return shellLaunchConfig; } - private async createTerminal(task: CustomTask | ContributedTask, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder): Promise<[ITerminalInstance | undefined, string | undefined, TaskError | undefined]> { + private async createTerminal(task: CustomTask | ContributedTask, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder | undefined): Promise<[ITerminalInstance | undefined, string | undefined, TaskError | undefined]> { let platform = resolver.taskSystemInfo ? resolver.taskSystemInfo.platform : Platform.platform; let options = this.resolveOptions(resolver, task.command.options); @@ -929,7 +925,7 @@ export class TerminalTaskSystem implements ITaskSystem { this.currentTask.shellLaunchConfig = launchConfigs = { isExtensionTerminal: true, waitOnExit, - name: this.createTerminalName(task, workspaceFolder), + name: this.createTerminalName(task), initialText: task.command.presentation && task.command.presentation.echo ? `\x1b[1m> Executing task: ${task._label} <\x1b[0m\n` : undefined }; } else { diff --git a/src/vs/workbench/contrib/tasks/common/taskSystem.ts b/src/vs/workbench/contrib/tasks/common/taskSystem.ts index e1ffe3a49c2..c844be5ec26 100644 --- a/src/vs/workbench/contrib/tasks/common/taskSystem.ts +++ b/src/vs/workbench/contrib/tasks/common/taskSystem.ts @@ -119,6 +119,7 @@ export interface TaskSystemInfo { context: any; uriProvider: (this: void, path: string) => URI; resolveVariables(workspaceFolder: IWorkspaceFolder, toResolve: ResolveSet): Promise; + getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }>; } export interface TaskSystemInfoResolver { @@ -137,4 +138,4 @@ export interface ITaskSystem { terminateAll(): Promise; revealTask(task: Task): boolean; customExecutionComplete(task: Task, result: number): Promise; -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index 4009bfe4cf5..be6edf706dc 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -72,8 +72,6 @@ } .monaco-workbench .panel.integrated-terminal .split-view-view { - /* Make relative as terminal absolute positioning needs it deeper in the tree */ - position: relative; box-sizing: border-box; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts index 79138f8545a..3e0b3e13d4d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts @@ -10,7 +10,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ITerminalConfiguration, ITerminalFont, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, TERMINAL_CONFIG_SECTION, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, MINIMUM_LETTER_SPACING, LinuxDistro, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; import Severity from 'vs/base/common/severity'; -import { Terminal as XTermTerminal } from 'xterm'; import { INotificationService, NeverShowAgainScope } from 'vs/platform/notification/common/notification'; import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal'; import { Emitter, Event } from 'vs/base/common/event'; @@ -21,6 +20,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { InstallRecommendedExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { IProductService } from 'vs/platform/product/common/product'; +import { XTermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; const MINIMUM_FONT_SIZE = 6; const MAXIMUM_FONT_SIZE = 25; @@ -129,7 +129,7 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper { * Gets the font information based on the terminal.integrated.fontFamily * terminal.integrated.fontSize, terminal.integrated.lineHeight configuration properties */ - public getFont(xterm?: XTermTerminal, excludeDimensions?: boolean): ITerminalFont { + public getFont(xtermCore?: XTermCore, excludeDimensions?: boolean): ITerminalFont { const editorConfig = this._configurationService.getValue('editor'); let fontFamily = this.config.fontFamily || editorConfig.fontFamily || EDITOR_FONT_DEFAULTS.fontFamily; @@ -161,15 +161,15 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper { } // Get the character dimensions from xterm if it's available - if (xterm) { - if (xterm._core._charSizeService && xterm._core._charSizeService.width && xterm._core._charSizeService.height) { + if (xtermCore) { + if (xtermCore._charSizeService && xtermCore._charSizeService.width && xtermCore._charSizeService.height) { return { fontFamily, fontSize, letterSpacing, lineHeight, - charHeight: xterm._core._charSizeService.height, - charWidth: xterm._core._charSizeService.width + charHeight: xtermCore._charSizeService.height, + charWidth: xtermCore._charSizeService.width }; } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index c210bb9d05d..2cc1f6ed491 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -38,6 +38,7 @@ import { Terminal as XTermTerminal, IBuffer, ITerminalAddon } from 'xterm'; import { SearchAddon, ISearchOptions } from 'xterm-addon-search'; import { CommandTrackerAddon } from 'vs/workbench/contrib/terminal/browser/addons/commandTrackerAddon'; import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/addons/navigationModeAddon'; +import { XTermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; // How long in milliseconds should an average frame take to render for a notification to appear // which suggests the fallback DOM-based renderer @@ -184,6 +185,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _title: string = ''; private _wrapperElement: (HTMLElement & { xterm?: XTermTerminal }) | undefined; private _xterm: XTermTerminal | undefined; + private _xtermCore: XTermCore | undefined; private _xtermSearch: SearchAddon | undefined; private _xtermElement: HTMLDivElement | undefined; private _terminalHasTextContextKey: IContextKey; @@ -351,7 +353,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return null; } - const font = this._configHelper.getFont(this._xterm); + const font = this._configHelper.getFont(this._xtermCore); if (!font.charWidth || !font.charHeight) { this._setLastKnownColsAndRows(); return null; @@ -399,7 +401,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _getDimension(width: number, height: number): ICanvasDimensions | undefined { // The font needs to have been initialized - const font = this._configHelper.getFont(this._xterm); + const font = this._configHelper.getFont(this._xtermCore); if (!font || !font.charWidth || !font.charHeight) { return undefined; } @@ -412,8 +414,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // needs to happen otherwise its scrollTop value is invalid when the panel is toggled as // it gets removed and then added back to the DOM (resetting scrollTop to 0). // Upstream issue: https://github.com/sourcelair/xterm.js/issues/291 - if (this._xterm) { - this._xterm._core._onScroll.fire(this._xterm.buffer.viewportY); + if (this._xterm && this._xtermCore) { + this._xtermCore._onScroll.fire(this._xterm.buffer.viewportY); } } @@ -472,6 +474,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType }); this._xterm = xterm; + this._xtermCore = (xterm as any)._core as XTermCore; this.updateAccessibilitySupport(); this._terminalInstanceService.getXtermSearchConstructor().then(Addon => { this._xtermSearch = new Addon(); @@ -674,9 +677,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } private async _measureRenderTime(): Promise { - const xterm = await this._xtermReadyPromise; + await this._xtermReadyPromise; const frameTimes: number[] = []; - const textRenderLayer = xterm._core._renderService._renderer._renderLayers[0]; + const textRenderLayer = this._xtermCore!._renderService._renderer._renderLayers[0]; const originalOnGridChanged = textRenderLayer.onGridChanged; const evaluateCanvasRenderer = () => { @@ -893,12 +896,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (this._wrapperElement) { dom.toggleClass(this._wrapperElement, 'active', visible); } - if (visible && this._xterm) { + if (visible && this._xterm && this._xtermCore) { // Trigger a manual scroll event which will sync the viewport and scroll bar. This is // necessary if the number of rows in the terminal has decreased while it was in the // background since scrollTop changes take no effect but the terminal's position does // change since the number of visible rows decreases. - this._xterm._core._onScroll.fire(this._xterm.buffer.viewportY); + this._xtermCore._onScroll.fire(this._xterm.buffer.viewportY); if (this._container && this._container.parentElement) { // Force a layout when the instance becomes invisible. This is particularly important // for ensuring that terminals that are created in the background by an extension will @@ -1322,11 +1325,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { let cols = this.cols; let rows = this.rows; - if (this._xterm) { + if (this._xterm && this._xtermCore) { // Only apply these settings when the terminal is visible so that // the characters are measured correctly. if (this._isVisible) { - const font = this._configHelper.getFont(this._xterm); + const font = this._configHelper.getFont(this._xtermCore); const config = this._configHelper.config; this._safeSetOption('letterSpacing', font.letterSpacing); this._safeSetOption('lineHeight', font.lineHeight); @@ -1354,7 +1357,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // maximize on Windows/Linux would fire an event saying that the terminal was not // visible. if (this._xterm.getOption('rendererType') === 'canvas') { - this._xterm._core._renderService._onIntersectionChange({ intersectionRatio: 1 }); + this._xtermCore._renderService._onIntersectionChange({ intersectionRatio: 1 }); // HACK: Force a refresh of the screen to ensure links are refresh corrected. // This can probably be removed when the above hack is fixed in Chromium. this._xterm.refresh(0, this._xterm.rows - 1); diff --git a/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts b/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts new file mode 100644 index 00000000000..50aa2e843a8 --- /dev/null +++ b/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export interface XTermCore { + _onScroll: IEventEmitter; + _onKey: IEventEmitter<{ key: string }>; + + _charSizeService: { + width: number; + height: number; + }; + + _coreService: { + triggerDataEvent(data: string, wasUserInput?: boolean): void; + }; + + _renderService: { + _renderer: { + _renderLayers: any[]; + }; + _onIntersectionChange: any; + }; + + // TODO: Remove below once a synchronous write API is added + // The below are only used in tests + writeBuffer: string[]; + _innerWrite(): void; +} + +export interface IEventEmitter { + fire(e: T): void; +} diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts index 2c74cd54682..f6198e4428c 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts @@ -4,17 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { Terminal, TerminalCore } from 'xterm'; +import { Terminal } from 'xterm'; import { CommandTrackerAddon } from 'vs/workbench/contrib/terminal/browser/addons/commandTrackerAddon'; import { isWindows } from 'vs/base/common/platform'; - -interface TestTerminalCore extends TerminalCore { - writeBuffer: string[]; - _innerWrite(): void; -} +import { XTermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; interface TestTerminal extends Terminal { - _core: TestTerminalCore; + _core: XTermCore; } function syncWrite(term: TestTerminal, data: string): void { 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/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index da4b46c3991..68abd9e52f5 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -71,7 +71,6 @@ const TextInputActions: IAction[] = [ export class ElectronWindow extends Disposable { private touchBarMenu: IMenu | undefined; - private touchBarUpdater: RunOnceScheduler | undefined; private readonly touchBarDisposables = this._register(new DisposableStore()); private lastInstalledTouchedBar: ICommandAction[][] | undefined; @@ -394,16 +393,15 @@ export class ElectronWindow extends Disposable { this.touchBarMenu = undefined; // Create new (delayed) - this.touchBarUpdater = new RunOnceScheduler(() => this.doUpdateTouchbarMenu(), 300); - this.touchBarDisposables.add(this.touchBarUpdater); - this.touchBarUpdater.schedule(); + const scheduler: RunOnceScheduler = this.touchBarDisposables.add(new RunOnceScheduler(() => this.doUpdateTouchbarMenu(scheduler), 300)); + scheduler.schedule(); } - private doUpdateTouchbarMenu(): void { + private doUpdateTouchbarMenu(scheduler: RunOnceScheduler): void { if (!this.touchBarMenu) { this.touchBarMenu = this.editorService.invokeWithinEditorContext(accessor => this.menuService.createMenu(MenuId.TouchBarContext, accessor.get(IContextKeyService))); this.touchBarDisposables.add(this.touchBarMenu); - this.touchBarDisposables.add(this.touchBarMenu.onDidChange(() => this.touchBarUpdater!.schedule())); + this.touchBarDisposables.add(this.touchBarMenu.onDidChange(() => scheduler.schedule())); } const actions: Array = []; 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/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/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 214118a2c2c..69a276b3bc4 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -18,14 +18,12 @@ export interface IDecorationData { readonly letter?: string; readonly tooltip?: string; readonly bubble?: boolean; - readonly source?: string; } export interface IDecoration { readonly tooltip: string; readonly labelClassName: string; readonly badgeClassName: string; - update(data: IDecorationData): IDecoration; } export interface IDecorationsProvider { @@ -46,5 +44,5 @@ export interface IDecorationsService { registerDecorationsProvider(provider: IDecorationsProvider): IDisposable; - getDecoration(uri: URI, includeChildren: boolean, overwrite?: IDecorationData): IDecoration | undefined; + getDecoration(uri: URI, includeChildren: boolean): IDecoration | undefined; } diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 7721cb6d802..a10d68678a5 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -144,17 +144,7 @@ class DecorationStyles extends Disposable { return { labelClassName, badgeClassName, - tooltip, - update: (replace) => { - let newData = data.slice(); - for (let i = 0; i < newData.length; i++) { - if (newData[i].source === replace.source) { - // replace - newData[i] = replace; - } - } - return this.asDecoration(newData, onlyChildren); - } + tooltip }; } @@ -402,7 +392,7 @@ export class FileDecorationsService implements IDecorationsService { }); } - getDecoration(uri: URI, includeChildren: boolean, overwrite?: IDecorationData): IDecoration | undefined { + getDecoration(uri: URI, includeChildren: boolean): IDecoration | undefined { let data: IDecorationData[] = []; let containsChildren: boolean = false; for (let iter = this._data.iterator(), next = iter.next(); !next.done; next = iter.next()) { @@ -414,22 +404,9 @@ export class FileDecorationsService implements IDecorationsService { }); } - if (data.length === 0) { - // nothing, maybe overwrite data - if (overwrite) { - return this._decorationStyles.asDecoration([overwrite], containsChildren); - } else { - return undefined; - } - } else { - // result, maybe overwrite - let result = this._decorationStyles.asDecoration(data, containsChildren); - if (overwrite) { - return result.update(overwrite); - } else { - return result; - } - } + return data.length === 0 + ? undefined + : this._decorationStyles.asDecoration(data, containsChildren); } } function getColor(theme: ITheme, color: string | undefined) { @@ -442,4 +419,4 @@ function getColor(theme: ITheme, color: string | undefined) { return 'inherit'; } -registerSingleton(IDecorationsService, FileDecorationsService); \ No newline at end of file +registerSingleton(IDecorationsService, FileDecorationsService); diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index 19be0060161..bd6a66f3fbb 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -146,32 +146,6 @@ suite('DecorationsService', function () { assert.equal(typeof deco.tooltip, 'string'); }); - test('Overwrite data', function () { - - let someUri = URI.parse('file:///some/path/some/file.txt'); - let deco = service.getDecoration(someUri, false); - assert.equal(deco, undefined); - - deco = service.getDecoration(someUri, false, { tooltip: 'Overwrite' })!; - assert.equal(deco.tooltip, 'Overwrite'); - - let reg = service.registerDecorationsProvider({ - label: 'Test', - onDidChange: Event.None, - provideDecorations(uri: URI) { - return { tooltip: 'FromMe', source: 'foo' }; - } - }); - - deco = service.getDecoration(someUri, false)!; - assert.equal(deco.tooltip, 'FromMe'); - - deco = service.getDecoration(someUri, false, { source: 'foo', tooltip: 'O' })!; - assert.equal(deco.tooltip, 'O'); - - reg.dispose(); - }); - test('Decorations not showing up for second root folder #48502', async function () { let cancelCount = 0; diff --git a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts index 7e9d2b3763a..7dec2cfe039 100644 --- a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts @@ -20,6 +20,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { isWeb } from 'vs/base/common/platform'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; export class FileDialogService implements IFileDialogService { @@ -32,7 +33,8 @@ export class FileDialogService implements IFileDialogService { @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IFileService private readonly fileService: IFileService + @IFileService private readonly fileService: IFileService, + @IOpenerService private readonly openerService: IOpenerService ) { } defaultFilePath(schemeFilter = this.getSchemeFilterForWindow()): URI | undefined { @@ -85,10 +87,10 @@ export class FileDialogService implements IFileDialogService { }; } - private shouldUseSimplified(schema: string): boolean { - const setting = this.configurationService.getValue('files.simpleDialog.enable'); + private shouldUseSimplified(schema: string): { useSimplified: boolean, isSetting: boolean } { + const setting = (this.configurationService.getValue('files.simpleDialog.enable') === true); - return (schema !== Schemas.file) || (setting === true); + return { useSimplified: (schema !== Schemas.file) || setting, isSetting: (schema === Schemas.file) && setting }; } private addFileSchemaIfNeeded(schema: string): string[] { @@ -108,7 +110,8 @@ export class FileDialogService implements IFileDialogService { options.defaultUri = this.defaultFilePath(schema); } - if (this.shouldUseSimplified(schema)) { + const shouldUseSimplified = this.shouldUseSimplified(schema); + if (shouldUseSimplified.useSimplified) { const title = nls.localize('openFileOrFolder.title', 'Open File Or Folder'); const availableFileSystems = this.addFileSchemaIfNeeded(schema); @@ -118,7 +121,11 @@ export class FileDialogService implements IFileDialogService { const stat = await this.fileService.resolve(uri); const toOpen: IURIToOpen = stat.isDirectory ? { folderUri: uri } : { fileUri: uri }; - return this.windowService.openWindow([toOpen], { forceNewWindow: options.forceNewWindow }); + if (stat.isDirectory || options.forceNewWindow || shouldUseSimplified.isSetting) { + return this.windowService.openWindow([toOpen], { forceNewWindow: options.forceNewWindow }); + } else { + return this.openerService.open(uri); + } } return; @@ -134,13 +141,18 @@ export class FileDialogService implements IFileDialogService { options.defaultUri = this.defaultFilePath(schema); } - if (this.shouldUseSimplified(schema)) { + const shouldUseSimplified = this.shouldUseSimplified(schema); + if (shouldUseSimplified.useSimplified) { const title = nls.localize('openFile.title', 'Open File'); const availableFileSystems = this.addFileSchemaIfNeeded(schema); const uri = await this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }); if (uri) { - return this.windowService.openWindow([{ fileUri: uri }], { forceNewWindow: options.forceNewWindow }); + if (options.forceNewWindow || shouldUseSimplified.isSetting) { + return this.windowService.openWindow([{ fileUri: uri }], { forceNewWindow: options.forceNewWindow }); + } else { + return this.openerService.open(uri); + } } return; @@ -156,7 +168,7 @@ export class FileDialogService implements IFileDialogService { options.defaultUri = this.defaultFolderPath(schema); } - if (this.shouldUseSimplified(schema)) { + if (this.shouldUseSimplified(schema).useSimplified) { const title = nls.localize('openFolder.title', 'Open Folder'); const availableFileSystems = this.addFileSchemaIfNeeded(schema); @@ -178,7 +190,7 @@ export class FileDialogService implements IFileDialogService { options.defaultUri = this.defaultWorkspacePath(schema); } - if (this.shouldUseSimplified(schema)) { + if (this.shouldUseSimplified(schema).useSimplified) { const title = nls.localize('openWorkspace.title', 'Open Workspace'); const filters: FileFilter[] = [{ name: nls.localize('filterName.workspace', 'Workspace'), extensions: [WORKSPACE_EXTENSION] }]; const availableFileSystems = this.addFileSchemaIfNeeded(schema); @@ -196,7 +208,7 @@ export class FileDialogService implements IFileDialogService { async pickFileToSave(options: ISaveDialogOptions): Promise { const schema = this.getFileSystemSchema(options); - if (this.shouldUseSimplified(schema)) { + if (this.shouldUseSimplified(schema).useSimplified) { if (!options.availableFileSystems) { options.availableFileSystems = this.addFileSchemaIfNeeded(schema); } @@ -225,7 +237,7 @@ export class FileDialogService implements IFileDialogService { async showSaveDialog(options: ISaveDialogOptions): Promise { const schema = this.getFileSystemSchema(options); - if (this.shouldUseSimplified(schema)) { + if (this.shouldUseSimplified(schema).useSimplified) { if (!options.availableFileSystems) { options.availableFileSystems = this.addFileSchemaIfNeeded(schema); } @@ -243,7 +255,7 @@ export class FileDialogService implements IFileDialogService { async showOpenDialog(options: IOpenDialogOptions): Promise { const schema = this.getFileSystemSchema(options); - if (this.shouldUseSimplified(schema)) { + if (this.shouldUseSimplified(schema).useSimplified) { if (!options.availableFileSystems) { options.availableFileSystems = this.addFileSchemaIfNeeded(schema); } diff --git a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts index 28fb4787d24..9354baad058 100644 --- a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts +++ b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts @@ -101,7 +101,7 @@ export class RemoteFileDialog { } public async showOpenDialog(options: IOpenDialogOptions = {}): Promise { - this.scheme = this.getScheme(options.availableFileSystems); + this.scheme = this.getScheme(options.availableFileSystems, options.defaultUri); this.userHome = await this.getUserHome(); const newOptions = await this.getOptions(options); if (!newOptions) { @@ -112,7 +112,7 @@ export class RemoteFileDialog { } public async showSaveDialog(options: ISaveDialogOptions): Promise { - this.scheme = this.getScheme(options.availableFileSystems); + this.scheme = this.getScheme(options.availableFileSystems, options.defaultUri); this.userHome = await this.getUserHome(); this.requiresTrailing = true; const newOptions = await this.getOptions(options, true); @@ -157,8 +157,14 @@ export class RemoteFileDialog { return resources.toLocalResource(URI.from({ scheme: this.scheme, path }), this.scheme === Schemas.file ? undefined : this.remoteAuthority); } - private getScheme(available: string[] | undefined): string { - return available ? available[0] : Schemas.file; + private getScheme(available: string[] | undefined, defaultUri: URI | undefined): string { + if (available) { + if (defaultUri && (available.indexOf(defaultUri.scheme) >= 0)) { + return defaultUri.scheme; + } + return available[0]; + } + return Schemas.file; } private async getRemoteAgentEnvironment(): Promise { @@ -215,7 +221,7 @@ export class RemoteFileDialog { this.filePickBox.autoFocusOnList = false; this.filePickBox.ignoreFocusOut = true; this.filePickBox.ok = true; - if (this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1) && (this.options.availableFileSystems.indexOf(Schemas.file) > -1)) { + if ((this.scheme !== Schemas.file) && this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1) && (this.options.availableFileSystems.indexOf(Schemas.file) > -1)) { this.filePickBox.customButton = true; this.filePickBox.customLabel = nls.localize('remoteFileDialog.local', 'Show Local'); let action; diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts index bcfa887b1a4..8bd6d25f2ca 100644 --- a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts @@ -443,7 +443,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx class ProposedApiController { - private readonly enableProposedApiFor: string | string[]; + private readonly enableProposedApiFor: string[]; private readonly enableProposedApiForAll: boolean; private readonly productAllowProposedApi: Set; @@ -451,15 +451,8 @@ class ProposedApiController { @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IProductService productService: IProductService ) { - this.enableProposedApiFor = environmentService.args['enable-proposed-api'] || []; - if (this.enableProposedApiFor.length) { - // Make enabled proposed API be lowercase for case insensitive comparison - if (Array.isArray(this.enableProposedApiFor)) { - this.enableProposedApiFor = this.enableProposedApiFor.map(id => id.toLowerCase()); - } else { - this.enableProposedApiFor = this.enableProposedApiFor.toLowerCase(); - } - } + // Make enabled proposed API be lowercase for case insensitive comparison + this.enableProposedApiFor = (environmentService.args['enable-proposed-api'] || []).map(id => id.toLowerCase()); this.enableProposedApiForAll = !environmentService.isBuilt || (!!environmentService.extensionDevelopmentLocationURI && productService.nameLong !== 'Visual Studio Code') || diff --git a/src/vs/workbench/services/extensions/common/extensionUrlHandler.ts b/src/vs/workbench/services/extensions/common/extensionUrlHandler.ts index c8d9d320630..4299e57ff73 100644 --- a/src/vs/workbench/services/extensions/common/extensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/common/extensionUrlHandler.ts @@ -28,7 +28,6 @@ const FIVE_MINUTES = 5 * 60 * 1000; const THIRTY_SECONDS = 30 * 1000; const URL_TO_HANDLE = 'extensionUrlHandler.urlToHandle'; const CONFIRMED_EXTENSIONS_CONFIGURATION_KEY = 'extensions.confirmedUriHandlerExtensionIds'; -const CONFIRMED_EXTENSIONS_STORAGE_KEY = 'extensionUrlHandler.confirmedExtensions'; function isExtensionId(value: string): boolean { return /^[a-z0-9][a-z0-9\-]*\.[a-z0-9][a-z0-9\-]*$/i.test(value); @@ -114,11 +113,11 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } const result = await this.dialogService.confirm({ - message: localize('confirmUrl', "Allow an extension to open this URL?", extensionId), + message: localize('confirmUrl', "Allow an extension to open this URI?", extensionId), checkbox: { label: localize('rememberConfirmUrl', "Don't ask again for this extension."), }, - detail: `${extension.displayName || extension.name} (${extensionId}) wants to open a URL:\n\n${uriString}`, + detail: `${extension.displayName || extension.name} (${extensionId}) wants to open a URI:\n\n${uriString}`, primaryButton: localize('open', "&&Open"), type: 'question' }); @@ -128,7 +127,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } if (result.checkboxChecked) { - this.addConfirmedExtensionIdToStorage(extensionId); + await this.addConfirmedExtensionIdToStorage(extensionId); } } @@ -290,10 +289,8 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } private getConfirmedExtensionIds(): Set { - const ids = [ - ...this.getConfirmedExtensionIdsFromStorage(), - ...this.getConfirmedExtensionIdsFromConfiguration(), - ].map(extensionId => ExtensionIdentifier.toKey(extensionId)); + const ids = this.getConfirmedExtensionIdsFromConfiguration() + .map(extensionId => ExtensionIdentifier.toKey(extensionId)); return new Set(ids); } @@ -308,26 +305,12 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { return confirmedExtensionIds; } - private getConfirmedExtensionIdsFromStorage(): Array { - const confirmedExtensionIdsJson = this.storageService.get(CONFIRMED_EXTENSIONS_STORAGE_KEY, StorageScope.GLOBAL, '[]'); + private async addConfirmedExtensionIdToStorage(extensionId: string): Promise { + const confirmedExtensionIds = this.configurationService.getValue>(CONFIRMED_EXTENSIONS_CONFIGURATION_KEY); + const set = new Set(confirmedExtensionIds); + set.add(extensionId); - try { - return JSON.parse(confirmedExtensionIdsJson); - } catch (err) { - return []; - } - } - - private addConfirmedExtensionIdToStorage(extensionId: string): void { - const existingConfirmedExtensionIds = this.getConfirmedExtensionIdsFromStorage(); - this.storageService.store( - CONFIRMED_EXTENSIONS_STORAGE_KEY, - JSON.stringify([ - ...existingConfirmedExtensionIds, - ExtensionIdentifier.toKey(extensionId), - ]), - StorageScope.GLOBAL, - ); + await this.configurationService.updateValue(CONFIRMED_EXTENSIONS_CONFIGURATION_KEY, [...set.values()]); } dispose(): void { diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index d568f30b170..c70804f0568 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -120,8 +120,9 @@ export class HistoryService extends Disposable implements IHistoryService { private lastEditLocation: IStackEntry | undefined; - private history: Array | undefined; + private history!: Array; private recentlyClosedFiles: IRecentlyClosedFile[]; + private loaded: boolean; private resourceFilter: ResourceGlobMatcher; private fileInputFactory: IFileInputFactory; @@ -154,6 +155,7 @@ export class HistoryService extends Disposable implements IHistoryService { this.lastIndex = -1; this.stack = []; this.recentlyClosedFiles = []; + this.loaded = false; this.resourceFilter = this._register(instantiationService.createInstance( ResourceGlobMatcher, (root?: URI) => this.getExcludes(root), @@ -487,17 +489,17 @@ export class HistoryService extends Disposable implements IHistoryService { return; } - const history = this.ensureHistoryLoaded(); + this.ensureHistoryLoaded(); const historyInput = this.preferResourceInput(input); // Remove any existing entry and add to the beginning this.removeFromHistory(input); - history.unshift(historyInput); + this.history.unshift(historyInput); // Respect max entries setting - if (history.length > HistoryService.MAX_HISTORY_ITEMS) { - this.clearOnEditorDispose(history.pop()!, this.editorHistoryListeners); + if (this.history.length > HistoryService.MAX_HISTORY_ITEMS) { + this.clearOnEditorDispose(this.history.pop()!, this.editorHistoryListeners); } // Remove this from the history unless the history input is a resource @@ -553,9 +555,9 @@ export class HistoryService extends Disposable implements IHistoryService { } private removeExcludedFromHistory(): void { - const history = this.ensureHistoryLoaded(); + this.ensureHistoryLoaded(); - this.history = history.filter(e => { + this.history = this.history.filter(e => { const include = this.include(e); // Cleanup any listeners associated with the input when removing from history @@ -568,9 +570,9 @@ export class HistoryService extends Disposable implements IHistoryService { } private removeFromHistory(arg1: IEditorInput | IResourceInput | FileChangesEvent): void { - const history = this.ensureHistoryLoaded(); + this.ensureHistoryLoaded(); - this.history = history.filter(e => { + this.history = this.history.filter(e => { const matches = this.matches(arg1, e); // Cleanup any listeners associated with the input when removing from history @@ -847,17 +849,17 @@ export class HistoryService extends Disposable implements IHistoryService { } getHistory(): Array { - const history = this.ensureHistoryLoaded(); + this.ensureHistoryLoaded(); - return history.slice(0); + return this.history.slice(0); } - private ensureHistoryLoaded(): Array { - if (!this.history) { - this.history = this.loadHistory(); + private ensureHistoryLoaded(): void { + if (!this.loaded) { + this.loadHistory(); } - return this.history; + this.loaded = true; } private saveState(): void { @@ -891,7 +893,7 @@ export class HistoryService extends Disposable implements IHistoryService { this.storageService.store(HistoryService.STORAGE_KEY, JSON.stringify(entries), StorageScope.WORKSPACE); } - private loadHistory(): Array { + private loadHistory(): void { let entries: ISerializedEditorHistoryEntry[] = []; const entriesRaw = this.storageService.get(HistoryService.STORAGE_KEY, StorageScope.WORKSPACE); @@ -901,7 +903,7 @@ export class HistoryService extends Disposable implements IHistoryService { const registry = Registry.as(EditorExtensions.EditorInputFactories); - return coalesce(entries.map(entry => { + this.history = coalesce(entries.map(entry => { try { return this.safeLoadHistoryEntry(registry, entry); } catch (error) { 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/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index 4f138914750..a5934abc85d 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -17,7 +17,6 @@ import { isWindows } from 'vs/base/common/platform'; import { tildify, getPathLabel } from 'vs/base/common/labels'; import { ltrim, endsWith } from 'vs/base/common/strings'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, WORKSPACE_EXTENSION, toWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { Schemas } from 'vs/base/common/network'; import { ILabelService, ResourceLabelFormatter, ResourceLabelFormatting } from 'vs/platform/label/common/label'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { match } from 'vs/base/common/glob'; @@ -283,12 +282,8 @@ export class LabelService implements ILabelService { } private appendWorkspaceSuffix(label: string, uri: URI): string { - if (uri.scheme === Schemas.file) { - return label; - } - const formatting = this.findFormatting(uri); - const suffix = formatting && (typeof formatting.workspaceSuffix === 'string') ? formatting.workspaceSuffix : uri.scheme; + const suffix = formatting && (typeof formatting.workspaceSuffix === 'string') ? formatting.workspaceSuffix : undefined; return suffix ? `${label} [${suffix}]` : label; } } 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/remote/common/remoteAgentEnvironmentChannel.ts b/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts index fe15f2b644e..a1877e037aa 100644 --- a/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts +++ b/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts @@ -14,7 +14,7 @@ import { RemoteAuthorities } from 'vs/base/common/network'; export interface IGetEnvironmentDataArguments { language: string; remoteAuthority: string; - extensionDevelopmentPath: UriComponents | UriComponents[] | undefined; + extensionDevelopmentPath: UriComponents[] | undefined; } export interface IRemoteAgentEnvironmentDTO { diff --git a/src/vs/workbench/services/search/common/replace.ts b/src/vs/workbench/services/search/common/replace.ts index 99f610bbcf5..764873d247a 100644 --- a/src/vs/workbench/services/search/common/replace.ts +++ b/src/vs/workbench/services/search/common/replace.ts @@ -27,7 +27,7 @@ export class ReplacePattern { } else { searchPatternInfo = arg2; parseParameters = !!searchPatternInfo.isRegExp; - this._regExp = strings.createRegExp(searchPatternInfo.pattern, !!searchPatternInfo.isRegExp, { matchCase: searchPatternInfo.isCaseSensitive, wholeWord: searchPatternInfo.isWordMatch, multiline: searchPatternInfo.isMultiline, global: false }); + this._regExp = strings.createRegExp(searchPatternInfo.pattern, !!searchPatternInfo.isRegExp, { matchCase: searchPatternInfo.isCaseSensitive, wholeWord: searchPatternInfo.isWordMatch, multiline: searchPatternInfo.isMultiline, global: false, unicode: true }); } if (parseParameters) { diff --git a/src/vs/workbench/services/search/common/search.ts b/src/vs/workbench/services/search/common/search.ts index bb47b117377..f66e10720cb 100644 --- a/src/vs/workbench/services/search/common/search.ts +++ b/src/vs/workbench/services/search/common/search.ts @@ -132,6 +132,7 @@ export interface IPatternInfo { isWordMatch?: boolean; wordSeparators?: string; isMultiline?: boolean; + isUnicode?: boolean; isCaseSensitive?: boolean; } @@ -516,7 +517,7 @@ export class QueryGlobTester { private _excludeExpression: glob.IExpression; private _parsedExcludeExpression: glob.ParsedExpression; - private _parsedIncludeExpression: glob.ParsedExpression; + private _parsedIncludeExpression: glob.ParsedExpression | null = null; constructor(config: ISearchQuery, folderQuery: IFolderQuery) { this._excludeExpression = { diff --git a/src/vs/workbench/services/search/common/searchExtTypes.ts b/src/vs/workbench/services/search/common/searchExtTypes.ts index 6e75b70b491..6c818f7fda7 100644 --- a/src/vs/workbench/services/search/common/searchExtTypes.ts +++ b/src/vs/workbench/services/search/common/searchExtTypes.ts @@ -33,8 +33,8 @@ export class Range { this.end = new Position(endLine, endCol); } - isEmpty: boolean; - isSingleLine: boolean; + isEmpty = false; + isSingleLine = false; contains(positionOrRange: Position | Range): boolean { return false; } isEqual(other: Range): boolean { return false; } intersection(range: Range): Range | undefined { return undefined; } @@ -410,4 +410,4 @@ export interface FindTextInFilesOptions { * Number of lines of context to include after each match. */ afterContext?: number; -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/search/common/searchService.ts b/src/vs/workbench/services/search/common/searchService.ts index c6c01de1548..cdb840a46b3 100644 --- a/src/vs/workbench/services/search/common/searchService.ts +++ b/src/vs/workbench/services/search/common/searchService.ts @@ -26,7 +26,7 @@ export class SearchService extends Disposable implements ISearchService { _serviceBrand: undefined; - protected diskSearch: ISearchResultProvider; + protected diskSearch: ISearchResultProvider | null = null; private readonly fileSearchProviders = new Map(); private readonly textSearchProviders = new Map(); diff --git a/src/vs/workbench/services/search/node/fileSearch.ts b/src/vs/workbench/services/search/node/fileSearch.ts index 5ade08b60ca..fc838b95e80 100644 --- a/src/vs/workbench/services/search/node/fileSearch.ts +++ b/src/vs/workbench/services/search/node/fileSearch.ts @@ -43,20 +43,20 @@ process.on('exit', () => { export class FileWalker { private config: IFileQuery; private filePattern: string; - private normalizedFilePatternLowercase: string; + private normalizedFilePatternLowercase: string | null = null; private includePattern: glob.ParsedExpression | undefined; private maxResults: number | null; private exists: boolean; - private maxFilesize: number | null; + private maxFilesize: number | null = null; private isLimitHit: boolean; private resultCount: number; - private isCanceled: boolean; - private fileWalkSW: StopWatch; + private isCanceled = false; + private fileWalkSW: StopWatch | null = null; private directoriesWalked: number; private filesWalked: number; private errors: string[]; - private cmdSW: StopWatch; - private cmdResultCount: number; + private cmdSW: StopWatch | null = null; + private cmdResultCount: number = 0; private folderExcludePatterns: Map; private globalExcludePattern: glob.ParsedExpression | undefined; @@ -139,8 +139,8 @@ export class FileWalker { rootFolderDone(null, undefined); } }); - }, (errors, result) => { - this.fileWalkSW.stop(); + }, (errors, _result) => { + this.fileWalkSW!.stop(); const err = errors ? arrays.coalesce(errors)[0] : null; done(err, this.isLimitHit); }); @@ -455,8 +455,8 @@ export class FileWalker { getStats(): ISearchEngineStats { return { - cmdTime: this.cmdSW && this.cmdSW.elapsed(), - fileWalkTime: this.fileWalkSW.elapsed(), + cmdTime: this.cmdSW!.elapsed(), + fileWalkTime: this.fileWalkSW!.elapsed(), directoriesWalked: this.directoriesWalked, filesWalked: this.filesWalked, cmdResultCount: this.cmdResultCount @@ -578,7 +578,9 @@ export class FileWalker { return true; // support the all-matching wildcard } - return strings.fuzzyContains(path, this.normalizedFilePatternLowercase); + if (this.normalizedFilePatternLowercase) { + return strings.fuzzyContains(path, this.normalizedFilePatternLowercase); + } } // No patterns means we match all diff --git a/src/vs/workbench/services/search/node/rawSearchService.ts b/src/vs/workbench/services/search/node/rawSearchService.ts index 2a27d205aac..c0d0e6d6358 100644 --- a/src/vs/workbench/services/search/node/rawSearchService.ts +++ b/src/vs/workbench/services/search/node/rawSearchService.ts @@ -254,7 +254,7 @@ export class SearchService implements IRawSearchService { const query = prepareQuery(config.filePattern || ''); const compare = (matchA: IRawFileMatch, matchB: IRawFileMatch) => compareItemsByScore(matchA, matchB, query, true, FileMatchItemAccessor, scorerCache); - const maxResults = config.maxResults || Number.MAX_VALUE; + const maxResults = typeof config.maxResults === 'number' ? config.maxResults : Number.MAX_VALUE; return arrays.topAsync(results, compare, maxResults, 10000, token); } diff --git a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts index ee39b55b8e8..84d73b811cc 100644 --- a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts +++ b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts @@ -394,13 +394,11 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[] args.push('--encoding', options.encoding); } - let pattern = query.pattern; - // Ripgrep handles -- as a -- arg separator. Only --. // - is ok, --- is ok, --some-flag is also ok. Need to special case. - if (pattern === '--') { + if (query.pattern === '--') { query.isRegExp = true; - pattern = '\\-\\-'; + query.pattern = '\\-\\-'; } if (query.isMultiline && !query.isRegExp) { @@ -413,7 +411,7 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[] } if (query.isRegExp) { - pattern = unicodeEscapesToPCRE2(pattern); + query.pattern = unicodeEscapesToPCRE2(query.pattern); } // Allow $ to match /r/n @@ -421,7 +419,7 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[] let searchPatternAfterDoubleDashes: Maybe; if (query.isWordMatch) { - const regexp = createRegExp(pattern, !!query.isRegExp, { wholeWord: query.isWordMatch }); + const regexp = createRegExp(query.pattern, !!query.isRegExp, { wholeWord: query.isWordMatch }); const regexpStr = regexp.source.replace(/\\\//g, '/'); // RegExp.source arbitrarily returns escaped slashes. Search and destroy. args.push('--regexp', regexpStr); } else if (query.isRegExp) { @@ -430,7 +428,7 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[] args.push('--regexp', fixedRegexpQuery); args.push('--auto-hybrid-regex'); } else { - searchPatternAfterDoubleDashes = pattern; + searchPatternAfterDoubleDashes = query.pattern; args.push('--fixed-strings'); } @@ -479,11 +477,18 @@ export function spreadGlobComponents(globArg: string): string[] { } export function unicodeEscapesToPCRE2(pattern: string): string { - const reg = /((?:[^\\]|^)(?:\\\\)*)\\u([a-z0-9]{4})(?!\d)/g; - // Replace an unescaped $ at the end of the pattern with \r?$ - // Match $ preceeded by none or even number of literal \ - while (pattern.match(reg)) { - pattern = pattern.replace(reg, `$1\\x{$2}`); + // Match \u1234 + const unicodePattern = /((?:[^\\]|^)(?:\\\\)*)\\u([a-z0-9]{4})/g; + + while (pattern.match(unicodePattern)) { + pattern = pattern.replace(unicodePattern, `$1\\x{$2}`); + } + + // Match \u{1234} + // \u with 5-6 characters will be left alone because \x only takes 4 characters. + const unicodePatternWithBraces = /((?:[^\\]|^)(?:\\\\)*)\\u\{([a-z0-9]{4})\}/g; + while (pattern.match(unicodePatternWithBraces)) { + pattern = pattern.replace(unicodePatternWithBraces, `$1\\x{$2}`); } return pattern; diff --git a/src/vs/workbench/services/search/node/textSearchManager.ts b/src/vs/workbench/services/search/node/textSearchManager.ts index b7ac01c436b..e7586a912cd 100644 --- a/src/vs/workbench/services/search/node/textSearchManager.ts +++ b/src/vs/workbench/services/search/node/textSearchManager.ts @@ -7,8 +7,8 @@ import * as path from 'vs/base/common/path'; import { mapArrayOrNot } from 'vs/base/common/arrays'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { toErrorMessage } from 'vs/base/common/errorMessage'; -import * as glob from 'vs/base/common/glob'; import * as resources from 'vs/base/common/resources'; +import * as glob from 'vs/base/common/glob'; import { URI } from 'vs/base/common/uri'; import { toCanonicalName } from 'vs/base/node/encoding'; import * as pfs from 'vs/base/node/pfs'; @@ -17,9 +17,9 @@ import { TextSearchProvider, TextSearchResult, TextSearchMatch, TextSearchComple export class TextSearchManager { - private collector: TextSearchResultsCollector; + private collector: TextSearchResultsCollector | null = null; - private isLimitHit: boolean; + private isLimitHit = false; private resultCount = 0; constructor(private query: ITextQuery, private provider: TextSearchProvider, private _pfs: typeof pfs = pfs) { @@ -52,7 +52,7 @@ export class TextSearchManager { const newResultSize = this.resultSize(result); this.resultCount += newResultSize; if (newResultSize > 0) { - this.collector.add(result, folderIdx); + this.collector!.add(result, folderIdx); } } }; @@ -62,7 +62,7 @@ export class TextSearchManager { return this.searchInFolder(fq, r => onResult(r, i), tokenSource.token); })).then(results => { tokenSource.dispose(); - this.collector.flush(); + this.collector!.flush(); const someFolderHitLImit = results.some(result => !!result && !!result.limitHit); resolve({ @@ -198,8 +198,8 @@ function patternInfoToQuery(patternInfo: IPatternInfo): TextSearchQuery { export class TextSearchResultsCollector { private _batchedCollector: BatchedCollector; - private _currentFolderIdx: number; - private _currentUri: URI; + private _currentFolderIdx: number = -1; + private _currentUri: URI | undefined; private _currentFileMatch: IFileMatch | null = null; constructor(private _onResult: (result: IFileMatch[]) => void) { diff --git a/src/vs/workbench/services/search/test/node/rawSearchService.test.ts b/src/vs/workbench/services/search/test/node/rawSearchService.test.ts index 4060adff5f0..c0a85168b80 100644 --- a/src/vs/workbench/services/search/test/node/rawSearchService.test.ts +++ b/src/vs/workbench/services/search/test/node/rawSearchService.test.ts @@ -185,6 +185,25 @@ suite('RawSearchService', () => { assert.strictEqual(result.results.length, 1, 'Result'); }); + test('Handles maxResults=0 correctly', async function () { + this.timeout(testTimeout); + const service = new RawSearchService(); + + const query: IFileQuery = { + type: QueryType.File, + folderQueries: MULTIROOT_QUERIES, + maxResults: 0, + sortByScore: true, + includePattern: { + '*.txt': true, + '*.js': true + }, + }; + + const result = await DiskSearch.collectResultsFromEvent(service.fileSearch(query)); + assert.strictEqual(result.results.length, 0, 'Result'); + }); + test('Multi-root with include pattern and exists', async function () { this.timeout(testTimeout); const service = new RawSearchService(); diff --git a/src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts b/src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts index fb307c68bfd..d1b0f31042f 100644 --- a/src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts +++ b/src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts @@ -17,9 +17,12 @@ suite('RipgrepTextSearchEngine', () => { assert.equal(unicodeEscapesToPCRE2('\\\\\\u1234'), '\\\\\\x{1234}'); assert.equal(unicodeEscapesToPCRE2('foo\\\\\\u1234'), 'foo\\\\\\x{1234}'); + assert.equal(unicodeEscapesToPCRE2('\\u{1234}'), '\\x{1234}'); + assert.equal(unicodeEscapesToPCRE2('\\u{1234}\\u{0001}'), '\\x{1234}\\x{0001}'); + assert.equal(unicodeEscapesToPCRE2('foo\\u{1234}bar'), 'foo\\x{1234}bar'); + + assert.equal(unicodeEscapesToPCRE2('foo\\u{123456}7bar'), 'foo\\u{123456}7bar'); assert.equal(unicodeEscapesToPCRE2('\\u123'), '\\u123'); - assert.equal(unicodeEscapesToPCRE2('\\u12345'), '\\u12345'); - assert.equal(unicodeEscapesToPCRE2('\\\\u12345'), '\\\\u12345'); assert.equal(unicodeEscapesToPCRE2('foo'), 'foo'); assert.equal(unicodeEscapesToPCRE2(''), ''); }); diff --git a/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts b/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts index 6f39df77250..ce38358933e 100644 --- a/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts +++ b/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts @@ -69,6 +69,26 @@ suite('Search-integration', function () { return doSearchTest(config, 4); }); + test('Text: GameOfLife (unicode escape sequences)', () => { + const config: ITextQuery = { + type: QueryType.Text, + folderQueries: ROOT_FOLDER_QUERY, + contentPattern: { pattern: 'G\\u{0061}m\\u0065OfLife', isRegExp: true } + }; + + return doSearchTest(config, 4); + }); + + test('Text: GameOfLife (unicode escape sequences, force PCRE2)', () => { + const config: ITextQuery = { + type: QueryType.Text, + folderQueries: ROOT_FOLDER_QUERY, + contentPattern: { pattern: '(? { const config: ITextQuery = { type: QueryType.Text, 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.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 681fc606b6a..e67d61f7e0e 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -72,9 +72,6 @@ registerSingleton(IContextMenuService, ContextMenuService); //#region --- workbench contributions -// Resource Service Worker -import 'vs/workbench/contrib/resources/browser/resourceServiceWorkerClient'; - // Preferences import 'vs/workbench/contrib/preferences/browser/keyboardLayoutPicker'; diff --git a/test/smoke/package.json b/test/smoke/package.json index 99e9ddf0852..718ad5e9e07 100644 --- a/test/smoke/package.json +++ b/test/smoke/package.json @@ -31,6 +31,7 @@ "mocha-multi-reporters": "^1.1.7", "ncp": "^2.0.0", "portastic": "^1.0.1", + "puppeteer": "^1.19.0", "rimraf": "^2.6.1", "strip-json-comments": "^2.0.1", "tmp": "0.0.33", diff --git a/test/smoke/src/application.ts b/test/smoke/src/application.ts index f7510ca502c..315bd951f7a 100644 --- a/test/smoke/src/application.ts +++ b/test/smoke/src/application.ts @@ -142,7 +142,7 @@ export class Application { await this.code.waitForElement('.monaco-workbench'); if (this.remote) { - await this.code.waitForElement('.monaco-workbench .statusbar-item[id="status.host"]'); + await this.code.waitForTextContent('.monaco-workbench .statusbar-item[id="status.host"]', ' TestResolver'); } // wait a bit, since focus might be stolen off widgets diff --git a/test/smoke/src/areas/debug/debugSmoke.ts b/test/smoke/src/areas/debug/debugSmoke.ts index 4132ec5a9cc..25b17010703 100644 --- a/test/smoke/src/areas/debug/debugSmoke.ts +++ b/test/smoke/src/areas/debug/debugSmoke.ts @@ -28,7 +28,7 @@ const STACK_FRAME = `${VIEWLET} .monaco-list-row .stack-frame`; const SPECIFIC_STACK_FRAME = filename => `${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/test/smoke/src/areas/multiroot/multiroot.test.ts b/test/smoke/src/areas/multiroot/multiroot.test.ts index d6c656bc433..bfc70dbf8ca 100644 --- a/test/smoke/src/areas/multiroot/multiroot.test.ts +++ b/test/smoke/src/areas/multiroot/multiroot.test.ts @@ -47,8 +47,7 @@ export function setup() { const app = this.app as Application; await app.workbench.quickopen.openQuickOpen('*.*'); - // TODO roblourens: Go to files finds welcome page: issue 74875 - await app.workbench.quickopen.waitForQuickOpenElements(names => names.length === 6 || names.length === 7); + await app.workbench.quickopen.waitForQuickOpenElements(names => names.length === 6); await app.workbench.quickopen.closeQuickOpen(); }); @@ -57,4 +56,4 @@ export function setup() { await app.code.waitForTitle(title => /smoketest \(Workspace\)/i.test(title)); }); }); -} \ No newline at end of file +} diff --git a/test/smoke/yarn.lock b/test/smoke/yarn.lock index 81f81a3f414..18aa689cc3e 100644 --- a/test/smoke/yarn.lock +++ b/test/smoke/yarn.lock @@ -81,6 +81,13 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + ajv@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda" @@ -204,6 +211,11 @@ async-each@^1.0.0: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -319,6 +331,11 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -463,6 +480,16 @@ concat-stream@1.6.0: readable-stream "^2.2.2" typedarray "^0.0.6" +concat-stream@1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + concurrently@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-3.5.1.tgz#ee8b60018bbe86b02df13e5249453c6ececd2521" @@ -566,6 +593,13 @@ debug@^3.0.0, debug@^3.2.6: dependencies: ms "^2.1.1" +debug@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -709,6 +743,18 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + escape-string-regexp@1.0.5, escape-string-regexp@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -799,6 +845,16 @@ extract-zip@^1.0.3: mkdirp "0.5.0" yauzl "2.4.1" +extract-zip@^1.6.6: + version "1.6.7" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" + integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k= + dependencies: + concat-stream "1.6.2" + debug "2.6.9" + mkdirp "0.5.1" + yauzl "2.4.1" + extsprintf@1.3.0, extsprintf@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -1114,6 +1170,14 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +https-proxy-agent@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz#271ea8e90f836ac9f119daccd39c19ff7dfb0793" + integrity sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg== + dependencies: + agent-base "^4.3.0" + debug "^3.1.0" + iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -1553,6 +1617,11 @@ mime-types@^2.1.12, mime-types@~2.1.17: dependencies: mime-db "~1.30.0" +mime@^2.0.3: + version "2.4.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" + integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== + minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -1967,11 +2036,35 @@ progress-stream@^1.1.0: speedometer "~0.1.2" through2 "~0.2.3" +progress@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +proxy-from-env@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" + integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4= + punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= +puppeteer@^1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.19.0.tgz#e3b7b448c2c97933517078d7a2c53687361bebea" + integrity sha512-2S6E6ygpoqcECaagDbBopoSOPDv0pAZvTbnBgUY+6hq0/XDFDOLEMNlHF/SKJlzcaZ9ckiKjKDuueWI3FN/WXw== + dependencies: + debug "^4.1.0" + extract-zip "^1.6.6" + https-proxy-agent "^2.2.1" + mime "^2.0.3" + progress "^2.0.1" + proxy-from-env "^1.0.0" + rimraf "^2.6.1" + ws "^6.1.0" + qs@~6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" @@ -2655,6 +2748,13 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +ws@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" + integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + dependencies: + async-limiter "~1.0.0" + xml@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" diff --git a/yarn.lock b/yarn.lock index 9d0ed2b8177..d1417b2eae6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1723,7 +1723,7 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@1.6.2, concat-stream@^1.5.0, concat-stream@^1.6.0: +concat-stream@^1.5.0, concat-stream@^1.6.0: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -2842,16 +2842,6 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-zip@^1.6.6: - version "1.6.7" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" - integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k= - dependencies: - concat-stream "1.6.2" - debug "2.6.9" - mkdirp "0.5.1" - yauzl "2.4.1" - extsprintf@1.3.0, extsprintf@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -3707,10 +3697,10 @@ gulp-symdest@^1.1.1: queue "^3.1.0" vinyl-fs "^2.4.3" -gulp-tsb@2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/gulp-tsb/-/gulp-tsb-2.0.7.tgz#0e8c5cc20643d304979a59e90a6448260b314eba" - integrity sha512-9cllqseEkotum/aWHnCTQX/ATD3kyEi1aVzkGp0AEe768uNuU1DqPzRxvyVrfuIPcdYUUvtvmKvEvgIMffNmNA== +gulp-tsb@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/gulp-tsb/-/gulp-tsb-4.0.1.tgz#be2d8900d9227abf0e728a33139891e49b9e85d3" + integrity sha512-HHR5qMjj/NyFlYdY6AIql7bWosFAknNfeJumwdkPkNaw6GtHVoaK+hPmWgmyK9Otf9nqcETtI5KI2vIla6Vhdw== dependencies: ansi-colors "^1.0.1" fancy-log "^1.3.2" @@ -5290,11 +5280,6 @@ mime@^1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^2.0.3: - version "2.4.4" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" - integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== - mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" @@ -6667,7 +6652,7 @@ progress@^1.1.8: resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74= -progress@^2.0.0, progress@^2.0.1: +progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== @@ -6690,11 +6675,6 @@ proxy-addr@~2.0.2: forwarded "~0.1.2" ipaddr.js "1.5.2" -proxy-from-env@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" - integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4= - prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -6777,20 +6757,6 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -puppeteer@^1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.19.0.tgz#e3b7b448c2c97933517078d7a2c53687361bebea" - integrity sha512-2S6E6ygpoqcECaagDbBopoSOPDv0pAZvTbnBgUY+6hq0/XDFDOLEMNlHF/SKJlzcaZ9ckiKjKDuueWI3FN/WXw== - dependencies: - debug "^4.1.0" - extract-zip "^1.6.6" - https-proxy-agent "^2.2.1" - mime "^2.0.3" - progress "^2.0.1" - proxy-from-env "^1.0.0" - rimraf "^2.6.1" - ws "^6.1.0" - q@^1.0.1, q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -9125,13 +9091,6 @@ ws@^3.3.3: safe-buffer "~5.1.0" ultron "~1.1.0" -ws@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" - integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== - dependencies: - async-limiter "~1.0.0" - xml-name-validator@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-1.0.0.tgz#dcf82ee092322951ef8cc1ba596c9cbfd14a83f1" @@ -9199,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" @@ -9275,13 +9234,6 @@ yargs@^7.1.0: y18n "^3.2.1" yargs-parser "^5.0.0" -yauzl@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" - integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU= - dependencies: - fd-slicer "~1.0.1" - yauzl@^2.2.1, yauzl@^2.3.1: version "2.9.1" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f"