diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index f03be115d34..034d02fcbbe 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -1,12 +1,12 @@ [ { "name": "ms-vscode.node-debug", - "version": "1.20.3", + "version": "1.20.4", "repo": "https://github.com/Microsoft/vscode-node-debug" }, { "name": "ms-vscode.node-debug2", - "version": "1.20.1", + "version": "1.20.2", "repo": "https://github.com/Microsoft/vscode-node-debug2" } ] \ No newline at end of file diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index 42f1d92e2ce..385b024609b 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -20,6 +20,7 @@ const sourcemaps = require('gulp-sourcemaps'); const nlsDev = require('vscode-nls-dev'); const root = path.dirname(__dirname); const commit = util.getVersion(root); +const i18n = require('./lib/i18n'); const extensionsPath = path.join(path.dirname(__dirname), 'extensions'); @@ -29,7 +30,8 @@ const compilations = glob.sync('**/tsconfig.json', { }); const getBaseUrl = out => `https://ticino.blob.core.windows.net/sourcemaps/${commit}/${out}`; -const languages = ['chs', 'cht', 'jpn', 'kor', 'deu', 'fra', 'esn', 'rus', 'ita']; + +const languages = i18n.defaultLanguages.concat(process.env.VSCODE_QUALITY !== 'stable' ? i18n.extraLanguages: []); const tasks = compilations.map(function (tsconfigFile) { const absolutePath = path.join(extensionsPath, tsconfigFile); @@ -55,9 +57,19 @@ const tasks = compilations.map(function (tsconfigFile) { const srcBase = path.join(root, 'src'); const src = path.join(srcBase, '**'); const out = path.join(root, 'out'); - const i18n = path.join(__dirname, '..', 'i18n'); + const i18nPath = path.join(__dirname, '..', 'i18n'); const baseUrl = getBaseUrl(out); + let headerId, headerOut; + let index = relativeDirname.indexOf('/'); + if (index < 0) { + headerId = relativeDirname; + headerOut = 'out'; + } else { + headerId = relativeDirname.substr(0, index); + headerOut = relativeDirname.substr(index + 1) + '/out'; + } + function createPipeline(build, emitError) { const reporter = createReporter(); @@ -82,7 +94,9 @@ const tasks = compilations.map(function (tsconfigFile) { sourceRoot: '../src' })) .pipe(tsFilter.restore) - .pipe(build ? nlsDev.createAdditionalLanguageFiles(languages, i18n, out) : es.through()) + .pipe(build ? nlsDev.createAdditionalLanguageFiles(languages, i18nPath, out) : es.through()) + .pipe(build ? nlsDev.bundleMetaDataFiles(headerId, headerOut) : es.through()) + .pipe(build ? nlsDev.bundleLanguageFiles() : es.through()) .pipe(reporter.end(emitError)); return es.duplex(input, output); diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index eecc080ad1d..f766cfaca0f 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -198,7 +198,7 @@ const hygiene = exports.hygiene = (some, options) => { tsfmt.processString(file.path, file.contents.toString('utf8'), { verify: true, tsfmt: true, - verbose: true + // verbose: true }).then(result => { if (result.error) { console.error(result.message); diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 9ac087e38d4..8ebb0555a58 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -92,10 +92,7 @@ const BUNDLED_FILE_HEADER = [ ' *--------------------------------------------------------*/' ].join('\n'); -var languages = ['chs', 'cht', 'jpn', 'kor', 'deu', 'fra', 'esn', 'rus', 'ita']; -if (process.env.VSCODE_QUALITY !== 'stable') { - languages = languages.concat(['ptb', 'hun', 'trk']); // Add languages requested by the community to non-stable builds -} +const languages = i18n.defaultLanguages.concat(process.env.VSCODE_QUALITY !== 'stable' ? i18n.extraLanguages: []); gulp.task('clean-optimized-vscode', util.rimraf('out-vscode')); gulp.task('optimize-vscode', ['clean-optimized-vscode', 'compile-build', 'compile-extensions-build'], common.optimizeTask({ @@ -105,7 +102,7 @@ gulp.task('optimize-vscode', ['clean-optimized-vscode', 'compile-build', 'compil loaderConfig: common.loaderConfig(nodeModules), header: BUNDLED_FILE_HEADER, out: 'out-vscode', - languages: languages + languages: languages, })); @@ -382,25 +379,21 @@ gulp.task('vscode-linux-x64-min', ['minify-vscode', 'clean-vscode-linux-x64'], p gulp.task('vscode-linux-arm-min', ['minify-vscode', 'clean-vscode-linux-arm'], packageTask('linux', 'arm', { minified: true })); // Transifex Localizations -const vscodeLanguages = [ - 'zh-hans', - 'zh-hant', - 'ja', - 'ko', - 'de', - 'fr', - 'es', - 'ru', - 'it', - 'pt-br', - 'hu', - 'tr' -]; -const setupDefaultLanguages = [ - 'zh-hans', - 'zh-hant', - 'ko' -]; + +const innoSetupConfig = { + 'zh-cn': { codePage: 'CP936', defaultInfo: { name: 'Simplified Chinese', id: '$0804', } }, + 'zh-tw': { codePage: 'CP950', defaultInfo: { name: 'Traditional Chinese', id: '$0404' } }, + 'ko': { codePage: 'CP949', defaultInfo: { name: 'Korean', id: '$0412' } }, + 'ja': { codePage: 'CP932' }, + 'de': { codePage: 'CP1252' }, + 'fr': { codePage: 'CP1252' }, + 'es': { codePage: 'CP1252' }, + 'ru': { codePage: 'CP1251' }, + 'it': { codePage: 'CP1252' }, + 'pt-br': { codePage: 'CP1252' }, + 'hu': { codePage: 'CP1250' }, + 'tr': { codePage: 'CP1254' } +}; const apiHostname = process.env.TRANSIFEX_API_URL; const apiName = process.env.TRANSIFEX_API_NAME; @@ -408,27 +401,46 @@ const apiToken = process.env.TRANSIFEX_API_TOKEN; gulp.task('vscode-translations-push', ['optimize-vscode'], function () { const pathToMetadata = './out-vscode/nls.metadata.json'; - const pathToExtensions = './extensions/**/*.nls.json'; + const pathToExtensions = './extensions/*'; const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}'; return es.merge( - gulp.src(pathToMetadata).pipe(i18n.prepareXlfFiles()), - gulp.src(pathToSetup).pipe(i18n.prepareXlfFiles()), - gulp.src(pathToExtensions).pipe(i18n.prepareXlfFiles('vscode-extensions')) + gulp.src(pathToMetadata).pipe(i18n.createXlfFilesForCoreBundle()), + gulp.src(pathToSetup).pipe(i18n.createXlfFilesForIsl()), + gulp.src(pathToExtensions).pipe(i18n.createXlfFilesForExtensions()) ).pipe(i18n.pushXlfFiles(apiHostname, apiName, apiToken)); }); -gulp.task('vscode-translations-pull', function () { +gulp.task('vscode-translations-push-test', function () { + const pathToMetadata = './out-vscode/nls.metadata.json'; + const pathToExtensions = './extensions/*'; + const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}'; + return es.merge( - i18n.pullXlfFiles('vscode-editor', apiHostname, apiName, apiToken, vscodeLanguages), - i18n.pullXlfFiles('vscode-workbench', apiHostname, apiName, apiToken, vscodeLanguages), - i18n.pullXlfFiles('vscode-extensions', apiHostname, apiName, apiToken, vscodeLanguages), - i18n.pullXlfFiles('vscode-setup', apiHostname, apiName, apiToken, setupDefaultLanguages) - ).pipe(vfs.dest('../vscode-localization')); + gulp.src(pathToMetadata).pipe(i18n.createXlfFilesForCoreBundle()), + gulp.src(pathToSetup).pipe(i18n.createXlfFilesForIsl()), + gulp.src(pathToExtensions).pipe(i18n.createXlfFilesForExtensions()) + ).pipe(vfs.dest('../vscode-transifex-input')); +}); + +gulp.task('vscode-translations-pull', function () { + [...i18n.defaultLanguages, ...i18n.extraLanguages].forEach(language => { + i18n.pullBuildXlfFiles(apiHostname, apiName, apiToken, language).pipe(vfs.dest(`../vscode-localization/${language.id}/build`)); + + let includeDefault = !!innoSetupConfig[language.id].defaultInfo; + i18n.pullSetupXlfFiles(apiHostname, apiName, apiToken, language, includeDefault).pipe(vfs.dest(`../vscode-localization/${language.id}/setup`)); + }); }); gulp.task('vscode-translations-import', function () { - return gulp.src('../vscode-localization/**/*.xlf').pipe(i18n.prepareJsonFiles()).pipe(vfs.dest('./i18n')); + [...i18n.defaultLanguages, ...i18n.extraLanguages].forEach(language => { + gulp.src(`../vscode-localization/${language.id}/build/*/*.xlf`) + .pipe(i18n.prepareI18nFiles(language)) + .pipe(vfs.dest(`./i18n/${language.folderName}`)); + gulp.src(`../vscode-localization/${language.id}/setup/*/*.xlf`) + .pipe(i18n.prepareIslFiles(language, innoSetupConfig[language.id])) + .pipe(vfs.dest(`./build/win32/i18n`)); + }); }); // Sourcemaps diff --git a/build/lib/i18n.js b/build/lib/i18n.js index 1358c7dfdda..907010f0841 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -12,6 +12,7 @@ var Is = require("is"); var xml2js = require("xml2js"); var glob = require("glob"); var https = require("https"); +var gulp = require("gulp"); var util = require('gulp-util'); var iconv = require('iconv-lite'); var NUMBER_OF_CONCURRENT_DOWNLOADS = 1; @@ -22,6 +23,24 @@ function log(message) { } util.log.apply(util, [util.colors.green('[i18n]'), message].concat(rest)); } +exports.defaultLanguages = [ + { id: 'zh-tw', folderName: 'cht', transifexId: 'zh-hant' }, + { id: 'zh-cn', folderName: 'chs', transifexId: 'zh-hans' }, + { id: 'ja', folderName: 'jpn' }, + { id: 'ko', folderName: 'kor' }, + { id: 'de', folderName: 'deu' }, + { id: 'fr', folderName: 'fra' }, + { id: 'es', folderName: 'esn' }, + { id: 'ru', folderName: 'rus' }, + { id: 'it', folderName: 'ita' } +]; +// languages requested by the community to non-stable builds +exports.extraLanguages = [ + { id: 'pt-br', folderName: 'ptb' }, + { id: 'hu', folderName: 'hun' }, + { id: 'tr', folderName: 'trk' } +]; +exports.pseudoLanguage = { id: 'pseudo', folderName: 'pseudo', transifexId: 'pseudo' }; var LocalizeInfo; (function (LocalizeInfo) { function is(value) { @@ -117,27 +136,31 @@ var XLF = /** @class */ (function () { return this.buffer.join('\r\n'); }; XLF.prototype.addFile = function (original, keys, messages) { + if (keys.length !== messages.length) { + throw new Error("Unmatching keys(" + keys.length + ") and messages(" + messages.length + ")."); + } this.files[original] = []; - var existingKeys = []; - for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) { - var key = keys_1[_i]; - // Ignore duplicate keys because Transifex does not populate those with translated values. - if (existingKeys.indexOf(key) !== -1) { + var existingKeys = new Set(); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var realKey = void 0; + var comment = void 0; + if (Is.string(key)) { + realKey = key; + comment = undefined; + } + else if (LocalizeInfo.is(key)) { + realKey = key.key; + if (key.comment && key.comment.length > 0) { + comment = key.comment.map(function (comment) { return encodeEntities(comment); }).join('\r\n'); + } + } + if (!realKey || existingKeys.has(realKey)) { continue; } - existingKeys.push(key); - var message = encodeEntities(messages[keys.indexOf(key)]); - var comment = undefined; - // Check if the message contains description (if so, it becomes an object type in JSON) - if (Is.string(key)) { - this.files[original].push({ id: key, message: message, comment: comment }); - } - else { - if (key['comment'] && key['comment'].length > 0) { - comment = key['comment'].map(function (comment) { return encodeEntities(comment); }).join('\r\n'); - } - this.files[original].push({ id: key['key'], message: message, comment: comment }); - } + existingKeys.add(realKey); + var message = encodeEntities(messages[i]); + this.files[original].push({ id: realKey, message: message, comment: comment }); } }; XLF.prototype.addStringItem = function (item) { @@ -169,20 +192,20 @@ var XLF = /** @class */ (function () { var files = []; parser.parseString(xlfString, function (err, result) { if (err) { - reject("Failed to parse XLIFF string. " + err); + reject(new Error("XLF parsing error: Failed to parse XLIFF string. " + err)); } var fileNodes = result['xliff']['file']; if (!fileNodes) { - reject('XLIFF file does not contain "xliff" or "file" node(s) required for parsing.'); + reject(new Error("XLF parsing error: XLIFF file does not contain \"xliff\" or \"file\" node(s) required for parsing.")); } fileNodes.forEach(function (file) { var originalFilePath = file.$.original; if (!originalFilePath) { - reject('XLIFF file node does not contain original attribute to determine the original location of the resource file.'); + reject(new Error("XLF parsing error: XLIFF file node does not contain original attribute to determine the original location of the resource file.")); } - var language = file.$['target-language'].toLowerCase(); + var language = file.$['target-language']; if (!language) { - reject('XLIFF file node does not contain target-language attribute to determine translated language.'); + reject(new Error("XLF parsing error: XLIFF file node does not contain target-language attribute to determine translated language.")); } var messages = {}; var transUnits = file.body[0]['trans-unit']; @@ -196,10 +219,10 @@ var XLF = /** @class */ (function () { messages[key] = decodeEntities(val); } else { - reject('XLIFF file does not contain full localization data. ID or target translation for one of the trans-unit nodes is not present.'); + reject(new Error("XLF parsing error: XLIFF file does not contain full localization data. ID or target translation for one of the trans-unit nodes is not present.")); } }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: language }); + files.push({ messages: messages, originalFilePath: originalFilePath, language: language.toLowerCase() }); }); resolve(files); }); @@ -238,67 +261,9 @@ var Limiter = /** @class */ (function () { return Limiter; }()); exports.Limiter = Limiter; -var iso639_3_to_2 = { - 'chs': 'zh-cn', - 'cht': 'zh-tw', - 'csy': 'cs-cz', - 'deu': 'de', - 'enu': 'en', - 'esn': 'es', - 'fra': 'fr', - 'hun': 'hu', - 'ita': 'it', - 'jpn': 'ja', - 'kor': 'ko', - 'nld': 'nl', - 'plk': 'pl', - 'ptb': 'pt-br', - 'ptg': 'pt', - 'rus': 'ru', - 'sve': 'sv-se', - 'trk': 'tr' -}; -/** - * Used to map Transifex to VS Code language code representation. - */ -var iso639_2_to_3 = { - 'zh-hans': 'chs', - 'zh-hant': 'cht', - 'cs-cz': 'csy', - 'de': 'deu', - 'en': 'enu', - 'es': 'esn', - 'fr': 'fra', - 'hu': 'hun', - 'it': 'ita', - 'ja': 'jpn', - 'ko': 'kor', - 'nl': 'nld', - 'pl': 'plk', - 'pt-br': 'ptb', - 'pt': 'ptg', - 'ru': 'rus', - 'sv-se': 'sve', - 'tr': 'trk' -}; -function sortLanguages(directoryNames) { - return directoryNames.map(function (dirName) { - var lower = dirName.toLowerCase(); - return { - name: lower, - iso639_2: iso639_3_to_2[lower] - }; - }).sort(function (a, b) { - if (!a.iso639_2 && !b.iso639_2) { - return 0; - } - if (!a.iso639_2) { - return -1; - } - if (!b.iso639_2) { - return 1; - } - return a.iso639_2 < b.iso639_2 ? -1 : (a.iso639_2 > b.iso639_2 ? 1 : 0); +function sortLanguages(languages) { + return languages.sort(function (a, b) { + return a.id < b.id ? -1 : (a.id > b.id ? 1 : 0); }); } function stripComments(content) { @@ -386,7 +351,7 @@ function processCoreBundleFormat(fileHeader, languages, json, emitter) { defaultMessages[module] = messageMap; keys.map(function (key, i) { total++; - if (Is.string(key)) { + if (typeof key === 'string') { messageMap[key] = messages[i]; } else { @@ -395,23 +360,15 @@ function processCoreBundleFormat(fileHeader, languages, json, emitter) { }); }); var languageDirectory = path.join(__dirname, '..', '..', 'i18n'); - var languageDirs; - if (languages) { - languageDirs = sortLanguages(languages); - } - else { - languageDirs = sortLanguages(fs.readdirSync(languageDirectory).filter(function (item) { return fs.statSync(path.join(languageDirectory, item)).isDirectory(); })); - } - languageDirs.forEach(function (language) { - if (!language.iso639_2) { - return; - } + var sortedLanguages = sortLanguages(languages); + sortedLanguages.forEach(function (language) { if (process.env['VSCODE_BUILD_VERBOSE']) { - log("Generating nls bundles for: " + language.iso639_2); + log("Generating nls bundles for: " + language.id); } - statistics[language.iso639_2] = 0; + statistics[language.id] = 0; var localizedModules = Object.create(null); - var cwd = path.join(languageDirectory, language.name, 'src'); + var languageFolderName = language.folderName || language.id; + var cwd = path.join(languageDirectory, languageFolderName, 'src'); modules.forEach(function (module) { var order = keysSection[module]; var i18nFile = path.join(cwd, module) + '.i18n.json'; @@ -425,12 +382,12 @@ function processCoreBundleFormat(fileHeader, languages, json, emitter) { log("No localized messages found for module " + module + ". Using default messages."); } messages = defaultMessages[module]; - statistics[language.iso639_2] = statistics[language.iso639_2] + Object.keys(messages).length; + statistics[language.id] = statistics[language.id] + Object.keys(messages).length; } var localizedMessages = []; order.forEach(function (keyInfo) { var key = null; - if (Is.string(keyInfo)) { + if (typeof keyInfo === 'string') { key = keyInfo; } else { @@ -442,7 +399,7 @@ function processCoreBundleFormat(fileHeader, languages, json, emitter) { log("No localized message found for key " + key + " in module " + module + ". Using default message."); } message = defaultMessages[module][key]; - statistics[language.iso639_2] = statistics[language.iso639_2] + 1; + statistics[language.id] = statistics[language.id] + 1; } localizedMessages.push(message); }); @@ -452,7 +409,7 @@ function processCoreBundleFormat(fileHeader, languages, json, emitter) { var modules = bundleSection[bundle]; var contents = [ fileHeader, - "define(\"" + bundle + ".nls." + language.iso639_2 + "\", {" + "define(\"" + bundle + ".nls." + language.id + "\", {" ]; modules.forEach(function (module, index) { contents.push("\t\"" + module + "\": ["); @@ -467,24 +424,17 @@ function processCoreBundleFormat(fileHeader, languages, json, emitter) { contents.push(index < modules.length - 1 ? '\t],' : '\t]'); }); contents.push('});'); - emitter.emit('data', new File({ path: bundle + '.nls.' + language.iso639_2 + '.js', contents: new Buffer(contents.join('\n'), 'utf-8') })); + emitter.queue(new File({ path: bundle + '.nls.' + language.id + '.js', contents: new Buffer(contents.join('\n'), 'utf-8') })); }); }); Object.keys(statistics).forEach(function (key) { var value = statistics[key]; log(key + " has " + value + " untranslated strings."); }); - languageDirs.forEach(function (dir) { - var language = dir.name; - var iso639_2 = iso639_3_to_2[language]; - if (!iso639_2) { - log("\tCouldn't find iso639 2 mapping for language " + language + ". Using default language instead."); - } - else { - var stats = statistics[iso639_2]; - if (Is.undef(stats)) { - log("\tNo translations found for language " + language + ". Using default language instead."); - } + sortedLanguages.forEach(function (language) { + var stats = statistics[language.id]; + if (Is.undef(stats)) { + log("\tNo translations found for language " + language.id + ". Using default language instead."); } }); } @@ -498,39 +448,16 @@ function processNlsFiles(opts) { } else { this.emit('error', "Failed to read component file: " + file.relative); + return; } if (BundledFormat.is(json)) { processCoreBundleFormat(opts.fileHeader, opts.languages, json, this); } } - this.emit('data', file); + this.queue(file); }); } exports.processNlsFiles = processNlsFiles; -function prepareXlfFiles(projectName, extensionName) { - return event_stream_1.through(function (file) { - if (!file.isBuffer()) { - throw new Error("Failed to read component file: " + file.relative); - } - var extension = path.extname(file.path); - if (extension === '.json') { - var json = JSON.parse(file.contents.toString('utf8')); - if (BundledFormat.is(json)) { - importBundleJson(file, json, this); - } - else if (PackageJsonFormat.is(json) || ModuleJsonFormat.is(json)) { - importModuleOrPackageJson(file, json, projectName, this, extensionName); - } - else { - throw new Error("JSON format cannot be deduced for " + file.relative + "."); - } - } - else if (extension === '.isl') { - importIsl(file, this); - } - }); -} -exports.prepareXlfFiles = prepareXlfFiles; var editorProject = 'vscode-editor', workbenchProject = 'vscode-workbench', extensionsProject = 'vscode-extensions', setupProject = 'vscode-setup'; function getResource(sourceFile) { var resource; @@ -563,113 +490,186 @@ function getResource(sourceFile) { throw new Error("Could not identify the XLF bundle for " + sourceFile); } exports.getResource = getResource; -function importBundleJson(file, json, stream) { - var bundleXlfs = Object.create(null); - for (var source in json.keys) { - var projectResource = getResource(source); - var resource = projectResource.name; - var project = projectResource.project; - var keys = json.keys[source]; - var messages = json.messages[source]; - if (keys.length !== messages.length) { - throw new Error("There is a mismatch between keys and messages in " + file.relative); - } - var xlf = bundleXlfs[resource] ? bundleXlfs[resource] : bundleXlfs[resource] = new XLF(project); - xlf.addFile('src/' + source, keys, messages); - } - for (var resource in bundleXlfs) { - var newFilePath = bundleXlfs[resource].project + "/" + resource.replace(/\//g, '_') + ".xlf"; - var xlfFile = new File({ path: newFilePath, contents: new Buffer(bundleXlfs[resource].toString(), 'utf-8') }); - stream.emit('data', xlfFile); - } -} -// Keeps existing XLF instances and a state of how many files were already processed for faster file emission -var extensions = Object.create(null); -function importModuleOrPackageJson(file, json, projectName, stream, extensionName) { - if (ModuleJsonFormat.is(json) && json['keys'].length !== json['messages'].length) { - throw new Error("There is a mismatch between keys and messages in " + file.relative); - } - // Prepare the source path for attribute in XLF & extract messages from JSON - var formattedSourcePath = file.relative.replace(/\\/g, '/'); - var messages = Object.keys(json).map(function (key) { return json[key].toString(); }); - // Stores the amount of localization files to be transformed to XLF before the emission - var localizationFilesCount, originalFilePath; - // If preparing XLF for external extension, then use different glob pattern and source path - if (extensionName) { - localizationFilesCount = glob.sync('**/*.nls.json').length; - originalFilePath = "" + formattedSourcePath.substr(0, formattedSourcePath.length - '.nls.json'.length); - } - else { - // Used for vscode/extensions folder - extensionName = formattedSourcePath.split('/')[0]; - localizationFilesCount = glob.sync("./extensions/" + extensionName + "/**/*.nls.json").length; - originalFilePath = "extensions/" + formattedSourcePath.substr(0, formattedSourcePath.length - '.nls.json'.length); - } - var extension = extensions[extensionName] ? - extensions[extensionName] : extensions[extensionName] = { xlf: new XLF(projectName), processed: 0 }; - // .nls.json can come with empty array of keys and messages, check for it - if (ModuleJsonFormat.is(json) && json.keys.length !== 0) { - extension.xlf.addFile(originalFilePath, json.keys, json.messages); - } - else if (PackageJsonFormat.is(json) && Object.keys(json).length !== 0) { - extension.xlf.addFile(originalFilePath, Object.keys(json), messages); - } - // Check if XLF is populated with file nodes to emit it - if (++extensions[extensionName].processed === localizationFilesCount) { - var newFilePath = path.join(projectName, extensionName + '.xlf'); - var xlfFile = new File({ path: newFilePath, contents: new Buffer(extension.xlf.toString(), 'utf-8') }); - stream.emit('data', xlfFile); - } -} -function importIsl(file, stream) { - var projectName, resourceFile; - if (path.basename(file.path) === 'Default.isl') { - projectName = setupProject; - resourceFile = 'setup_default.xlf'; - } - else { - projectName = workbenchProject; - resourceFile = 'setup_messages.xlf'; - } - var xlf = new XLF(projectName), keys = [], messages = []; - var model = new TextModel(file.contents.toString()); - var inMessageSection = false; - model.lines.forEach(function (line) { - if (line.length === 0) { - return; - } - var firstChar = line.charAt(0); - switch (firstChar) { - case ';': - // Comment line; +function createXlfFilesForCoreBundle() { + return event_stream_1.through(function (file) { + var basename = path.basename(file.path); + if (basename === 'nls.metadata.json') { + if (file.isBuffer()) { + var xlfs = Object.create(null); + var json = JSON.parse(file.contents.toString('utf8')); + for (var coreModule in json.keys) { + var projectResource = getResource(coreModule); + var resource = projectResource.name; + var project = projectResource.project; + var keys = json.keys[coreModule]; + var messages = json.messages[coreModule]; + if (keys.length !== messages.length) { + this.emit('error', "There is a mismatch between keys and messages in " + file.relative + " for module " + coreModule); + return; + } + else { + var xlf = xlfs[resource]; + if (!xlf) { + xlf = new XLF(project); + xlfs[resource] = xlf; + } + xlf.addFile("src/" + coreModule, keys, messages); + } + } + for (var resource in xlfs) { + var xlf = xlfs[resource]; + var filePath = xlf.project + "/" + resource.replace(/\//g, '_') + ".xlf"; + var xlfFile = new File({ + path: filePath, + contents: new Buffer(xlf.toString(), 'utf8') + }); + this.queue(xlfFile); + } + } + else { + this.emit('error', new Error("File " + file.relative + " is not using a buffer content")); return; - case '[': - inMessageSection = '[Messages]' === line || '[CustomMessages]' === line; - return; - } - if (!inMessageSection) { - return; - } - var sections = line.split('='); - if (sections.length !== 2) { - throw new Error("Badly formatted message found: " + line); - } - else { - var key = sections[0]; - var value = sections[1]; - if (key.length > 0 && value.length > 0) { - keys.push(key); - messages.push(value); } } + else { + this.emit('error', new Error("File " + file.relative + " is not a core meta data file.")); + return; + } }); - var originalPath = file.path.substring(file.cwd.length + 1, file.path.split('.')[0].length).replace(/\\/g, '/'); - xlf.addFile(originalPath, keys, messages); - // Emit only upon all ISL files combined into single XLF instance - var newFilePath = path.join(projectName, resourceFile); - var xlfFile = new File({ path: newFilePath, contents: new Buffer(xlf.toString(), 'utf-8') }); - stream.emit('data', xlfFile); } +exports.createXlfFilesForCoreBundle = createXlfFilesForCoreBundle; +function createXlfFilesForExtensions() { + var counter = 0; + var folderStreamEnded = false; + var folderStreamEndEmitted = false; + return event_stream_1.through(function (extensionFolder) { + var folderStream = this; + var stat = fs.statSync(extensionFolder.path); + if (!stat.isDirectory()) { + return; + } + var extensionName = path.basename(extensionFolder.path); + if (extensionName === 'node_modules') { + return; + } + counter++; + var _xlf; + function getXlf() { + if (!_xlf) { + _xlf = new XLF(extensionsProject); + } + return _xlf; + } + gulp.src(["./extensions/" + extensionName + "/package.nls.json", "./extensions/" + extensionName + "/**/nls.metadata.json"]).pipe(event_stream_1.through(function (file) { + if (file.isBuffer()) { + var buffer = file.contents; + var basename = path.basename(file.path); + if (basename === 'package.nls.json') { + var json_1 = JSON.parse(buffer.toString('utf8')); + var keys = Object.keys(json_1); + var messages = keys.map(function (key) { + var value = json_1[key]; + if (Is.string(value)) { + return value; + } + else if (value) { + return value.message; + } + else { + return "Unknown message for key: " + key; + } + }); + getXlf().addFile("extensions/" + extensionName + "/package", keys, messages); + } + else if (basename === 'nls.metadata.json') { + var json = JSON.parse(buffer.toString('utf8')); + var relPath = path.relative("./extensions/" + extensionName, path.dirname(file.path)); + for (var file_1 in json) { + var fileContent = json[file_1]; + getXlf().addFile("extensions/" + extensionName + "/" + relPath + "/" + file_1, fileContent.keys, fileContent.messages); + } + } + else { + this.emit('error', new Error(file.path + " is not a valid extension nls file")); + return; + } + } + }, function () { + if (_xlf) { + var xlfFile = new File({ + path: path.join(extensionsProject, extensionName + '.xlf'), + contents: new Buffer(_xlf.toString(), 'utf8') + }); + folderStream.queue(xlfFile); + } + this.queue(null); + counter--; + if (counter === 0 && folderStreamEnded && !folderStreamEndEmitted) { + folderStreamEndEmitted = true; + folderStream.queue(null); + } + })); + }, function () { + folderStreamEnded = true; + if (counter === 0) { + folderStreamEndEmitted = true; + this.queue(null); + } + }); +} +exports.createXlfFilesForExtensions = createXlfFilesForExtensions; +function createXlfFilesForIsl() { + return event_stream_1.through(function (file) { + var projectName, resourceFile; + if (path.basename(file.path) === 'Default.isl') { + projectName = setupProject; + resourceFile = 'setup_default.xlf'; + } + else { + projectName = workbenchProject; + resourceFile = 'setup_messages.xlf'; + } + var xlf = new XLF(projectName), keys = [], messages = []; + var model = new TextModel(file.contents.toString()); + var inMessageSection = false; + model.lines.forEach(function (line) { + if (line.length === 0) { + return; + } + var firstChar = line.charAt(0); + switch (firstChar) { + case ';': + // Comment line; + return; + case '[': + inMessageSection = '[Messages]' === line || '[CustomMessages]' === line; + return; + } + if (!inMessageSection) { + return; + } + var sections = line.split('='); + if (sections.length !== 2) { + throw new Error("Badly formatted message found: " + line); + } + else { + var key = sections[0]; + var value = sections[1]; + if (key.length > 0 && value.length > 0) { + keys.push(key); + messages.push(value); + } + } + }); + var originalPath = file.path.substring(file.cwd.length + 1, file.path.split('.')[0].length).replace(/\\/g, '/'); + xlf.addFile(originalPath, keys, messages); + // Emit only upon all ISL files combined into single XLF instance + var newFilePath = path.join(projectName, resourceFile); + var xlfFile = new File({ path: newFilePath, contents: new Buffer(xlf.toString(), 'utf-8') }); + this.queue(xlfFile); + }); +} +exports.createXlfFilesForIsl = createXlfFilesForIsl; function pushXlfFiles(apiHostname, username, password) { var tryGetPromises = []; var updateCreatePromises = []; @@ -695,7 +695,7 @@ function pushXlfFiles(apiHostname, username, password) { // End the pipe only after all the communication with Transifex API happened Promise.all(tryGetPromises).then(function () { Promise.all(updateCreatePromises).then(function () { - _this.emit('end'); + _this.queue(null); }).catch(function (reason) { throw new Error(reason); }); }).catch(function (reason) { throw new Error(reason); }); }); @@ -800,40 +800,37 @@ function updateResource(project, slug, xlfFile, apiHostname, credentials) { request.end(); }); } -function obtainProjectResources(projectName) { - var resources = []; - if (projectName === editorProject) { - var json = fs.readFileSync('./build/lib/i18n.resources.json', 'utf8'); - resources = JSON.parse(json).editor; - } - else if (projectName === workbenchProject) { - var json = fs.readFileSync('./build/lib/i18n.resources.json', 'utf8'); - resources = JSON.parse(json).workbench; - } - else if (projectName === extensionsProject) { - var extensionsToLocalize = glob.sync('./extensions/**/*.nls.json').map(function (extension) { return extension.split('/')[2]; }); - var resourcesToPull_1 = []; - extensionsToLocalize.forEach(function (extension) { - if (resourcesToPull_1.indexOf(extension) === -1) { - resourcesToPull_1.push(extension); - resources.push({ name: extension, project: projectName }); - } +// cache resources +var _buildResources; +function pullBuildXlfFiles(apiHostname, username, password, language) { + if (!_buildResources) { + _buildResources = []; + // editor and workbench + var json = JSON.parse(fs.readFileSync('./build/lib/i18n.resources.json', 'utf8')); + _buildResources.push.apply(_buildResources, json.editor); + _buildResources.push.apply(_buildResources, json.workbench); + // extensions + var extensionsToLocalize_1 = Object.create(null); + glob.sync('./extensions/**/*.nls.json').forEach(function (extension) { return extensionsToLocalize_1[extension.split('/')[2]] = true; }); + glob.sync('./extensions/*/node_modules/vscode-nls').forEach(function (extension) { return extensionsToLocalize_1[extension.split('/')[2]] = true; }); + Object.keys(extensionsToLocalize_1).forEach(function (extension) { + _buildResources.push({ name: extension, project: 'vscode-extensions' }); }); } - else if (projectName === setupProject) { - resources.push({ name: 'setup_default', project: setupProject }); - } - return resources; + return pullXlfFiles(apiHostname, username, password, language, _buildResources); } -function pullXlfFiles(projectName, apiHostname, username, password, languages, resources) { - if (!resources) { - resources = obtainProjectResources(projectName); - } - if (!resources) { - throw new Error('Transifex projects and resources must be defined to be able to pull translations from Transifex.'); +exports.pullBuildXlfFiles = pullBuildXlfFiles; +function pullSetupXlfFiles(apiHostname, username, password, language, includeDefault) { + var setupResources = [{ name: 'setup_messages', project: 'vscode-workbench' }]; + if (includeDefault) { + setupResources.push({ name: 'setup_default', project: 'vscode-setup' }); } + return pullXlfFiles(apiHostname, username, password, language, setupResources); +} +exports.pullSetupXlfFiles = pullSetupXlfFiles; +function pullXlfFiles(apiHostname, username, password, language, resources) { var credentials = username + ":" + password; - var expectedTranslationsCount = languages.length * resources.length; + var expectedTranslationsCount = resources.length; var translationsRetrieved = 0, called = false; return event_stream_1.readable(function (count, callback) { // Mark end of stream when all resources were retrieved @@ -843,29 +840,27 @@ function pullXlfFiles(projectName, apiHostname, username, password, languages, r if (!called) { called = true; var stream_1 = this; - // Retrieve XLF files from main projects - languages.map(function (language) { - resources.map(function (resource) { - retrieveResource(language, resource, apiHostname, credentials).then(function (file) { + resources.map(function (resource) { + retrieveResource(language, resource, apiHostname, credentials).then(function (file) { + if (file) { stream_1.emit('data', file); - translationsRetrieved++; - }).catch(function (error) { throw new Error(error); }); - }); + } + translationsRetrieved++; + }).catch(function (error) { throw new Error(error); }); }); } callback(); }); } -exports.pullXlfFiles = pullXlfFiles; var limiter = new Limiter(NUMBER_OF_CONCURRENT_DOWNLOADS); function retrieveResource(language, resource, apiHostname, credentials) { return limiter.queue(function () { return new Promise(function (resolve, reject) { var slug = resource.name.replace(/\//g, '_'); var project = resource.project; - var iso639 = language.toLowerCase(); + var transifexLanguageId = language.transifexId || language.id; var options = { hostname: apiHostname, - path: "/api/2/project/" + project + "/resource/" + slug + "/translation/" + iso639 + "?file&mode=onlyreviewed", + path: "/api/2/project/" + project + "/resource/" + slug + "/translation/" + transifexLanguageId + "?file&mode=onlyreviewed", auth: credentials, port: 443, method: 'GET' @@ -875,20 +870,24 @@ function retrieveResource(language, resource, apiHostname, credentials) { res.on('data', function (chunk) { return xlfBuffer.push(chunk); }); res.on('end', function () { if (res.statusCode === 200) { - console.log('success: ' + options.path); - resolve(new File({ contents: Buffer.concat(xlfBuffer), path: project + "/" + iso639_2_to_3[language] + "/" + slug + ".xlf" })); + resolve(new File({ contents: Buffer.concat(xlfBuffer), path: project + "/" + slug + ".xlf" })); + } + else if (res.statusCode === 404) { + console.log(slug + " in " + project + " returned no data."); + resolve(null); + } + else { + reject(slug + " in " + project + " returned no data. Response code: " + res.statusCode + "."); } - reject(slug + " in " + project + " returned no data. Response code: " + res.statusCode + "."); }); }); request.on('error', function (err) { reject("Failed to query resource " + slug + " with the following error: " + err + ". " + options.path); }); request.end(); - console.log('started: ' + options.path); }); }); } -function prepareJsonFiles() { +function prepareI18nFiles() { var parsePromises = []; return event_stream_1.through(function (xlf) { var stream = this; @@ -896,69 +895,117 @@ function prepareJsonFiles() { parsePromises.push(parsePromise); parsePromise.then(function (resolvedFiles) { resolvedFiles.forEach(function (file) { - var messages = file.messages, translatedFile; - // ISL file path always starts with 'build/' - if (/^build\//.test(file.originalFilePath)) { - var defaultLanguages = { 'zh-hans': true, 'zh-hant': true, 'ko': true }; - if (path.basename(file.originalFilePath) === 'Default' && !defaultLanguages[file.language]) { - return; - } - translatedFile = createIslFile('..', file.originalFilePath, messages, iso639_2_to_3[file.language]); - } - else { - translatedFile = createI18nFile(iso639_2_to_3[file.language], file.originalFilePath, messages); - } - stream.emit('data', translatedFile); + var translatedFile = createI18nFile(file.originalFilePath, file.messages); + stream.queue(translatedFile); }); - }, function (rejectReason) { - throw new Error("XLF parsing error: " + rejectReason); }); }, function () { var _this = this; Promise.all(parsePromises) - .then(function () { _this.emit('end'); }) + .then(function () { _this.queue(null); }) .catch(function (reason) { throw new Error(reason); }); }); } -exports.prepareJsonFiles = prepareJsonFiles; -function createI18nFile(base, originalFilePath, messages) { - var content = [ - '/*---------------------------------------------------------------------------------------------', - ' * Copyright (c) Microsoft Corporation. All rights reserved.', - ' * Licensed under the MIT License. See License.txt in the project root for license information.', - ' *--------------------------------------------------------------------------------------------*/', - '// Do not edit this file. It is machine generated.' - ].join('\n') + '\n' + JSON.stringify(messages, null, '\t').replace(/\r\n/g, '\n'); +exports.prepareI18nFiles = prepareI18nFiles; +function createI18nFile(originalFilePath, messages) { + var result = Object.create(null); + result[''] = [ + '--------------------------------------------------------------------------------------------', + 'Copyright (c) Microsoft Corporation. All rights reserved.', + 'Licensed under the MIT License. See License.txt in the project root for license information.', + '--------------------------------------------------------------------------------------------', + 'Do not edit this file. It is machine generated.' + ]; + for (var _i = 0, _a = Object.keys(messages); _i < _a.length; _i++) { + var key = _a[_i]; + result[key] = messages[key]; + } + var content = JSON.stringify(result, null, '\t').replace(/\r\n/g, '\n'); return new File({ - path: path.join(base, originalFilePath + '.i18n.json'), + path: path.join(originalFilePath + '.i18n.json'), contents: new Buffer(content, 'utf8') }); } -var languageNames = { - 'chs': 'Simplified Chinese', - 'cht': 'Traditional Chinese', - 'kor': 'Korean' -}; -var languageIds = { - 'chs': '$0804', - 'cht': '$0404', - 'kor': '$0412' -}; -var encodings = { - 'chs': 'CP936', - 'cht': 'CP950', - 'jpn': 'CP932', - 'kor': 'CP949', - 'deu': 'CP1252', - 'fra': 'CP1252', - 'esn': 'CP1252', - 'rus': 'CP1251', - 'ita': 'CP1252', - 'ptb': 'CP1252', - 'hun': 'CP1250', - 'trk': 'CP1254' -}; -function createIslFile(base, originalFilePath, messages, language) { +var i18nPackVersion = "1.0.0"; +function pullI18nPackFiles(apiHostname, username, password, language) { + return pullBuildXlfFiles(apiHostname, username, password, language).pipe(prepareI18nPackFiles()); +} +exports.pullI18nPackFiles = pullI18nPackFiles; +function prepareI18nPackFiles() { + var parsePromises = []; + var mainPack = { version: i18nPackVersion, contents: {} }; + var extensionsPacks = {}; + return event_stream_1.through(function (xlf) { + var stream = this; + var parsePromise = XLF.parse(xlf.contents.toString()); + parsePromises.push(parsePromise); + parsePromise.then(function (resolvedFiles) { + resolvedFiles.forEach(function (file) { + var path = file.originalFilePath; + var firstSlash = path.indexOf('/'); + var firstSegment = path.substr(0, firstSlash); + if (firstSegment === 'src') { + mainPack.contents[path.substr(firstSlash + 1)] = file.messages; + } + else if (firstSegment === 'extensions') { + var secondSlash = path.indexOf('/', firstSlash + 1); + var secondSegment = path.substring(firstSlash + 1, secondSlash); + if (secondSegment) { + var extPack = extensionsPacks[secondSegment]; + if (!extPack) { + extPack = extensionsPacks[secondSegment] = { version: i18nPackVersion, contents: {} }; + } + extPack.contents[path.substr(secondSlash + 1)] = file.messages; + } + else { + console.log('Unknown second segment ' + path); + } + } + else { + console.log('Unknown first segment ' + path); + } + }); + }); + }, function () { + var _this = this; + Promise.all(parsePromises) + .then(function () { + var translatedMainFile = createI18nFile('./main', mainPack); + _this.queue(translatedMainFile); + for (var extension in extensionsPacks) { + var translatedExtFile = createI18nFile("./extensions/" + extension, extensionsPacks[extension]); + _this.queue(translatedExtFile); + } + _this.queue(null); + }) + .catch(function (reason) { throw new Error(reason); }); + }); +} +exports.prepareI18nPackFiles = prepareI18nPackFiles; +function prepareIslFiles(language, innoSetupConfig) { + var parsePromises = []; + return event_stream_1.through(function (xlf) { + var stream = this; + var parsePromise = XLF.parse(xlf.contents.toString()); + parsePromises.push(parsePromise); + parsePromise.then(function (resolvedFiles) { + resolvedFiles.forEach(function (file) { + if (path.basename(file.originalFilePath) === 'Default' && !innoSetupConfig.defaultInfo) { + return; + } + var translatedFile = createIslFile(file.originalFilePath, file.messages, language, innoSetupConfig); + stream.queue(translatedFile); + }); + }); + }, function () { + var _this = this; + Promise.all(parsePromises) + .then(function () { _this.queue(null); }) + .catch(function (reason) { throw new Error(reason); }); + }); +} +exports.prepareIslFiles = prepareIslFiles; +function createIslFile(originalFilePath, messages, language, innoSetup) { var content = []; var originalContent; if (path.basename(originalFilePath) === 'Default') { @@ -972,7 +1019,7 @@ function createIslFile(base, originalFilePath, messages, language) { var firstChar = line.charAt(0); if (firstChar === '[' || firstChar === ';') { if (line === '; *** Inno Setup version 5.5.3+ English messages ***') { - content.push("; *** Inno Setup version 5.5.3+ " + languageNames[language] + " messages ***"); + content.push("; *** Inno Setup version 5.5.3+ " + innoSetup.defaultInfo.name + " messages ***"); } else { content.push(line); @@ -984,13 +1031,13 @@ function createIslFile(base, originalFilePath, messages, language) { var translated = line; if (key) { if (key === 'LanguageName') { - translated = key + "=" + languageNames[language]; + translated = key + "=" + innoSetup.defaultInfo.name; } else if (key === 'LanguageID') { - translated = key + "=" + languageIds[language]; + translated = key + "=" + innoSetup.defaultInfo.id; } else if (key === 'LanguageCodePage') { - translated = key + "=" + encodings[language].substr(2); + translated = key + "=" + innoSetup.codePage.substr(2); } else { var translatedMessage = messages[key]; @@ -1003,12 +1050,11 @@ function createIslFile(base, originalFilePath, messages, language) { } } }); - var tag = iso639_3_to_2[language]; var basename = path.basename(originalFilePath); - var filePath = path.join(base, path.dirname(originalFilePath), basename) + "." + tag + ".isl"; + var filePath = basename + "." + language.id + ".isl"; return new File({ path: filePath, - contents: iconv.encode(new Buffer(content.join('\r\n'), 'utf8'), encodings[language]) + contents: iconv.encode(new Buffer(content.join('\r\n'), 'utf8'), innoSetup.codePage) }); } function encodeEntities(value) { diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 93cf72c39c9..499ef117f7d 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -197,10 +197,6 @@ { "name": "vs/workbench/services/decorations", "project": "vscode-workbench" - }, - { - "name": "setup_messages", - "project": "vscode-workbench" } ] } \ No newline at end of file diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index 223b61ce911..aa249e1f2a3 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -6,13 +6,13 @@ import * as path from 'path'; import * as fs from 'fs'; -import { through, readable } from 'event-stream'; -import { ThroughStream } from 'through'; +import { through, readable, ThroughStream } from 'event-stream'; import File = require('vinyl'); import * as Is from 'is'; import * as xml2js from 'xml2js'; import * as glob from 'glob'; import * as https from 'https'; +import * as gulp from 'gulp'; var util = require('gulp-util'); var iconv = require('iconv-lite'); @@ -23,6 +23,41 @@ function log(message: any, ...rest: any[]): void { util.log(util.colors.green('[i18n]'), message, ...rest); } +export interface Language { + id: string; // laguage id, e.g. zh-tw, de + transifexId?: string; // language id used in transifex, e.g zh-hant, de (optional, if not set, the id is used) + folderName?: string; // language specific folder name, e.g. cht, deu (optional, if not set, the id is used) +} + +export interface InnoSetup { + codePage: string; //code page for encoding (http://www.jrsoftware.org/ishelp/index.php?topic=langoptionssection) + defaultInfo?: { + name: string; // inno setup language name + id: string; // locale identifier (https://msdn.microsoft.com/en-us/library/dd318693.aspx) + }; +} + +export const defaultLanguages: Language[] = [ + { id: 'zh-tw', folderName: 'cht', transifexId: 'zh-hant' }, + { id: 'zh-cn', folderName: 'chs', transifexId: 'zh-hans' }, + { id: 'ja', folderName: 'jpn' }, + { id: 'ko', folderName: 'kor' }, + { id: 'de', folderName: 'deu' }, + { id: 'fr', folderName: 'fra' }, + { id: 'es', folderName: 'esn' }, + { id: 'ru', folderName: 'rus' }, + { id: 'it', folderName: 'ita' } +]; + +// languages requested by the community to non-stable builds +export const extraLanguages: Language[] = [ + { id: 'pt-br', folderName: 'ptb' }, + { id: 'hu', folderName: 'hun' }, + { id: 'tr', folderName: 'trk' } +]; + +export const pseudoLanguage: Language = { id: 'pseudo', folderName: 'pseudo', transifexId: 'pseudo' }; + interface Map { [key: string]: V; } @@ -110,6 +145,20 @@ module ModuleJsonFormat { } } +interface BundledExtensionHeaderFormat { + id: string; + type: string; + hash: string; + outDir: string; +} + +interface BundledExtensionFormat { + [key: string]: { + messages: string[]; + keys: (string | LocalizeInfo)[]; + }; +} + export class Line { private buffer: string[] = []; @@ -165,30 +214,31 @@ export class XLF { return this.buffer.join('\r\n'); } - public addFile(original: string, keys: any[], messages: string[]) { + public addFile(original: string, keys: (string | LocalizeInfo)[], messages: string[]) { + if (keys.length !== messages.length) { + throw new Error(`Unmatching keys(${keys.length}) and messages(${messages.length}).`); + } this.files[original] = []; - let existingKeys = []; - - for (let key of keys) { - // Ignore duplicate keys because Transifex does not populate those with translated values. - if (existingKeys.indexOf(key) !== -1) { + let existingKeys = new Set(); + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + let realKey: string; + let comment: string; + if (Is.string(key)) { + realKey = key; + comment = undefined; + } else if (LocalizeInfo.is(key)) { + realKey = key.key; + if (key.comment && key.comment.length > 0) { + comment = key.comment.map(comment => encodeEntities(comment)).join('\r\n'); + } + } + if (!realKey || existingKeys.has(realKey)) { continue; } - existingKeys.push(key); - - let message: string = encodeEntities(messages[keys.indexOf(key)]); - let comment: string = undefined; - - // Check if the message contains description (if so, it becomes an object type in JSON) - if (Is.string(key)) { - this.files[original].push({ id: key, message: message, comment: comment }); - } else { - if (key['comment'] && key['comment'].length > 0) { - comment = key['comment'].map(comment => encodeEntities(comment)).join('\r\n'); - } - - this.files[original].push({ id: key['key'], message: message, comment: comment }); - } + existingKeys.add(realKey); + let message: string = encodeEntities(messages[i]); + this.files[original].push({ id: realKey, message: message, comment: comment }); } } @@ -230,22 +280,22 @@ export class XLF { parser.parseString(xlfString, function (err, result) { if (err) { - reject(`Failed to parse XLIFF string. ${err}`); + reject(new Error(`XLF parsing error: Failed to parse XLIFF string. ${err}`)); } const fileNodes: any[] = result['xliff']['file']; if (!fileNodes) { - reject('XLIFF file does not contain "xliff" or "file" node(s) required for parsing.'); + reject(new Error(`XLF parsing error: XLIFF file does not contain "xliff" or "file" node(s) required for parsing.`)); } fileNodes.forEach((file) => { const originalFilePath = file.$.original; if (!originalFilePath) { - reject('XLIFF file node does not contain original attribute to determine the original location of the resource file.'); + reject(new Error(`XLF parsing error: XLIFF file node does not contain original attribute to determine the original location of the resource file.`)); } - const language = file.$['target-language'].toLowerCase(); + const language = file.$['target-language']; if (!language) { - reject('XLIFF file node does not contain target-language attribute to determine translated language.'); + reject(new Error(`XLF parsing error: XLIFF file node does not contain target-language attribute to determine translated language.`)); } let messages: Map = {}; @@ -261,11 +311,11 @@ export class XLF { if (key && val) { messages[key] = decodeEntities(val); } else { - reject('XLIFF file does not contain full localization data. ID or target translation for one of the trans-unit nodes is not present.'); + reject(new Error(`XLF parsing error: XLIFF file does not contain full localization data. ID or target translation for one of the trans-unit nodes is not present.`)); } }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: language }); + files.push({ messages: messages, originalFilePath: originalFilePath, language: language.toLowerCase() }); }); resolve(files); @@ -295,7 +345,7 @@ export class Limiter { queue(factory: ITask>): Promise { return new Promise((c, e) => { - this.outstandingPromises.push({factory, c, e}); + this.outstandingPromises.push({ factory, c, e }); this.consume(); }); } @@ -317,74 +367,9 @@ export class Limiter { } } -const iso639_3_to_2: Map = { - 'chs': 'zh-cn', - 'cht': 'zh-tw', - 'csy': 'cs-cz', - 'deu': 'de', - 'enu': 'en', - 'esn': 'es', - 'fra': 'fr', - 'hun': 'hu', - 'ita': 'it', - 'jpn': 'ja', - 'kor': 'ko', - 'nld': 'nl', - 'plk': 'pl', - 'ptb': 'pt-br', - 'ptg': 'pt', - 'rus': 'ru', - 'sve': 'sv-se', - 'trk': 'tr' -}; - -/** - * Used to map Transifex to VS Code language code representation. - */ -const iso639_2_to_3: Map = { - 'zh-hans': 'chs', - 'zh-hant': 'cht', - 'cs-cz': 'csy', - 'de': 'deu', - 'en': 'enu', - 'es': 'esn', - 'fr': 'fra', - 'hu': 'hun', - 'it': 'ita', - 'ja': 'jpn', - 'ko': 'kor', - 'nl': 'nld', - 'pl': 'plk', - 'pt-br': 'ptb', - 'pt': 'ptg', - 'ru': 'rus', - 'sv-se': 'sve', - 'tr': 'trk' -}; - -interface IDirectoryInfo { - name: string; - iso639_2: string; -} - -function sortLanguages(directoryNames: string[]): IDirectoryInfo[] { - return directoryNames.map((dirName) => { - var lower = dirName.toLowerCase(); - return { - name: lower, - iso639_2: iso639_3_to_2[lower] - }; - }).sort((a: IDirectoryInfo, b: IDirectoryInfo): number => { - if (!a.iso639_2 && !b.iso639_2) { - return 0; - } - if (!a.iso639_2) { - return -1; - } - if (!b.iso639_2) { - return 1; - } - return a.iso639_2 < b.iso639_2 ? -1 : (a.iso639_2 > b.iso639_2 ? 1 : 0); +function sortLanguages(languages: Language[]): Language[] { + return languages.sort((a: Language, b: Language): number => { + return a.id < b.id ? -1 : (a.id > b.id ? 1 : 0); }); } @@ -453,7 +438,7 @@ function escapeCharacters(value: string): string { return result.join(''); } -function processCoreBundleFormat(fileHeader: string, languages: string[], json: BundledFormat, emitter: any) { +function processCoreBundleFormat(fileHeader: string, languages: Language[], json: BundledFormat, emitter: ThroughStream) { let keysSection = json.keys; let messageSection = json.messages; let bundleSection = json.bundles; @@ -474,7 +459,7 @@ function processCoreBundleFormat(fileHeader: string, languages: string[], json: defaultMessages[module] = messageMap; keys.map((key, i) => { total++; - if (Is.string(key)) { + if (typeof key === 'string') { messageMap[key] = messages[i]; } else { messageMap[key.key] = messages[i]; @@ -483,24 +468,16 @@ function processCoreBundleFormat(fileHeader: string, languages: string[], json: }); let languageDirectory = path.join(__dirname, '..', '..', 'i18n'); - let languageDirs; - if (languages) { - languageDirs = sortLanguages(languages); - } else { - languageDirs = sortLanguages(fs.readdirSync(languageDirectory).filter((item) => fs.statSync(path.join(languageDirectory, item)).isDirectory())); - } - languageDirs.forEach((language) => { - if (!language.iso639_2) { - return; - } - + let sortedLanguages = sortLanguages(languages); + sortedLanguages.forEach((language) => { if (process.env['VSCODE_BUILD_VERBOSE']) { - log(`Generating nls bundles for: ${language.iso639_2}`); + log(`Generating nls bundles for: ${language.id}`); } - statistics[language.iso639_2] = 0; + statistics[language.id] = 0; let localizedModules: Map = Object.create(null); - let cwd = path.join(languageDirectory, language.name, 'src'); + let languageFolderName = language.folderName || language.id; + let cwd = path.join(languageDirectory, languageFolderName, 'src'); modules.forEach((module) => { let order = keysSection[module]; let i18nFile = path.join(cwd, module) + '.i18n.json'; @@ -513,12 +490,12 @@ function processCoreBundleFormat(fileHeader: string, languages: string[], json: log(`No localized messages found for module ${module}. Using default messages.`); } messages = defaultMessages[module]; - statistics[language.iso639_2] = statistics[language.iso639_2] + Object.keys(messages).length; + statistics[language.id] = statistics[language.id] + Object.keys(messages).length; } let localizedMessages: string[] = []; order.forEach((keyInfo) => { let key: string = null; - if (Is.string(keyInfo)) { + if (typeof keyInfo === 'string') { key = keyInfo; } else { key = keyInfo.key; @@ -529,7 +506,7 @@ function processCoreBundleFormat(fileHeader: string, languages: string[], json: log(`No localized message found for key ${key} in module ${module}. Using default message.`); } message = defaultMessages[module][key]; - statistics[language.iso639_2] = statistics[language.iso639_2] + 1; + statistics[language.id] = statistics[language.id] + 1; } localizedMessages.push(message); }); @@ -539,7 +516,7 @@ function processCoreBundleFormat(fileHeader: string, languages: string[], json: let modules = bundleSection[bundle]; let contents: string[] = [ fileHeader, - `define("${bundle}.nls.${language.iso639_2}", {` + `define("${bundle}.nls.${language.id}", {` ]; modules.forEach((module, index) => { contents.push(`\t"${module}": [`); @@ -554,29 +531,23 @@ function processCoreBundleFormat(fileHeader: string, languages: string[], json: contents.push(index < modules.length - 1 ? '\t],' : '\t]'); }); contents.push('});'); - emitter.emit('data', new File({ path: bundle + '.nls.' + language.iso639_2 + '.js', contents: new Buffer(contents.join('\n'), 'utf-8') })); + emitter.queue(new File({ path: bundle + '.nls.' + language.id + '.js', contents: new Buffer(contents.join('\n'), 'utf-8') })); }); }); Object.keys(statistics).forEach(key => { let value = statistics[key]; log(`${key} has ${value} untranslated strings.`); }); - languageDirs.forEach(dir => { - const language = dir.name; - let iso639_2 = iso639_3_to_2[language]; - if (!iso639_2) { - log(`\tCouldn't find iso639 2 mapping for language ${language}. Using default language instead.`); - } else { - let stats = statistics[iso639_2]; - if (Is.undef(stats)) { - log(`\tNo translations found for language ${language}. Using default language instead.`); - } + sortedLanguages.forEach(language => { + let stats = statistics[language.id]; + if (Is.undef(stats)) { + log(`\tNo translations found for language ${language.id}. Using default language instead.`); } }); } -export function processNlsFiles(opts: { fileHeader: string; languages: string[] }): ThroughStream { - return through(function (file: File) { +export function processNlsFiles(opts: { fileHeader: string; languages: Language[] }): ThroughStream { + return through(function (this: ThroughStream, file: File) { let fileName = path.basename(file.path); if (fileName === 'nls.metadata.json') { let json = null; @@ -584,40 +555,16 @@ export function processNlsFiles(opts: { fileHeader: string; languages: string[] json = JSON.parse((file.contents).toString('utf8')); } else { this.emit('error', `Failed to read component file: ${file.relative}`); + return; } if (BundledFormat.is(json)) { processCoreBundleFormat(opts.fileHeader, opts.languages, json, this); } } - this.emit('data', file); + this.queue(file); }); } -export function prepareXlfFiles(projectName?: string, extensionName?: string): ThroughStream { - return through( - function (file: File) { - if (!file.isBuffer()) { - throw new Error(`Failed to read component file: ${file.relative}`); - } - - const extension = path.extname(file.path); - if (extension === '.json') { - const json = JSON.parse((file.contents).toString('utf8')); - - if (BundledFormat.is(json)) { - importBundleJson(file, json, this); - } else if (PackageJsonFormat.is(json) || ModuleJsonFormat.is(json)) { - importModuleOrPackageJson(file, json, projectName, this, extensionName); - } else { - throw new Error(`JSON format cannot be deduced for ${file.relative}.`); - } - } else if (extension === '.isl') { - importIsl(file, this); - } - } - ); -} - const editorProject: string = 'vscode-editor', workbenchProject: string = 'vscode-workbench', extensionsProject: string = 'vscode-extensions', @@ -650,134 +597,190 @@ export function getResource(sourceFile: string): Resource { } -function importBundleJson(file: File, json: BundledFormat, stream: ThroughStream): void { - let bundleXlfs: Map = Object.create(null); +export function createXlfFilesForCoreBundle(): ThroughStream { + return through(function (this: ThroughStream, file: File) { + const basename = path.basename(file.path); + if (basename === 'nls.metadata.json') { + if (file.isBuffer()) { + const xlfs: Map = Object.create(null); + const json: BundledFormat = JSON.parse((file.contents as Buffer).toString('utf8')); + for (let coreModule in json.keys) { + const projectResource = getResource(coreModule); + const resource = projectResource.name; + const project = projectResource.project; - for (let source in json.keys) { - const projectResource = getResource(source); - const resource = projectResource.name; - const project = projectResource.project; - - const keys = json.keys[source]; - const messages = json.messages[source]; - if (keys.length !== messages.length) { - throw new Error(`There is a mismatch between keys and messages in ${file.relative}`); - } - - let xlf = bundleXlfs[resource] ? bundleXlfs[resource] : bundleXlfs[resource] = new XLF(project); - xlf.addFile('src/' + source, keys, messages); - } - - for (let resource in bundleXlfs) { - const newFilePath = `${bundleXlfs[resource].project}/${resource.replace(/\//g, '_')}.xlf`; - const xlfFile = new File({ path: newFilePath, contents: new Buffer(bundleXlfs[resource].toString(), 'utf-8') }); - stream.emit('data', xlfFile); - } -} - -// Keeps existing XLF instances and a state of how many files were already processed for faster file emission -var extensions: Map<{ xlf: XLF, processed: number }> = Object.create(null); -function importModuleOrPackageJson(file: File, json: ModuleJsonFormat | PackageJsonFormat, projectName: string, stream: ThroughStream, extensionName?: string): void { - if (ModuleJsonFormat.is(json) && json['keys'].length !== json['messages'].length) { - throw new Error(`There is a mismatch between keys and messages in ${file.relative}`); - } - - // Prepare the source path for attribute in XLF & extract messages from JSON - const formattedSourcePath = file.relative.replace(/\\/g, '/'); - const messages = Object.keys(json).map((key) => json[key].toString()); - - // Stores the amount of localization files to be transformed to XLF before the emission - let localizationFilesCount, - originalFilePath; - // If preparing XLF for external extension, then use different glob pattern and source path - if (extensionName) { - localizationFilesCount = glob.sync('**/*.nls.json').length; - originalFilePath = `${formattedSourcePath.substr(0, formattedSourcePath.length - '.nls.json'.length)}`; - } else { - // Used for vscode/extensions folder - extensionName = formattedSourcePath.split('/')[0]; - localizationFilesCount = glob.sync(`./extensions/${extensionName}/**/*.nls.json`).length; - originalFilePath = `extensions/${formattedSourcePath.substr(0, formattedSourcePath.length - '.nls.json'.length)}`; - } - - let extension = extensions[extensionName] ? - extensions[extensionName] : extensions[extensionName] = { xlf: new XLF(projectName), processed: 0 }; - - // .nls.json can come with empty array of keys and messages, check for it - if (ModuleJsonFormat.is(json) && json.keys.length !== 0) { - extension.xlf.addFile(originalFilePath, json.keys, json.messages); - } else if (PackageJsonFormat.is(json) && Object.keys(json).length !== 0) { - extension.xlf.addFile(originalFilePath, Object.keys(json), messages); - } - - // Check if XLF is populated with file nodes to emit it - if (++extensions[extensionName].processed === localizationFilesCount) { - const newFilePath = path.join(projectName, extensionName + '.xlf'); - const xlfFile = new File({ path: newFilePath, contents: new Buffer(extension.xlf.toString(), 'utf-8') }); - stream.emit('data', xlfFile); - } -} - -function importIsl(file: File, stream: ThroughStream) { - let projectName: string, - resourceFile: string; - if (path.basename(file.path) === 'Default.isl') { - projectName = setupProject; - resourceFile = 'setup_default.xlf'; - } else { - projectName = workbenchProject; - resourceFile = 'setup_messages.xlf'; - } - - let xlf = new XLF(projectName), - keys: string[] = [], - messages: string[] = []; - - let model = new TextModel(file.contents.toString()); - let inMessageSection = false; - model.lines.forEach(line => { - if (line.length === 0) { - return; - } - let firstChar = line.charAt(0); - switch (firstChar) { - case ';': - // Comment line; + const keys = json.keys[coreModule]; + const messages = json.messages[coreModule]; + if (keys.length !== messages.length) { + this.emit('error', `There is a mismatch between keys and messages in ${file.relative} for module ${coreModule}`); + return; + } else { + let xlf = xlfs[resource]; + if (!xlf) { + xlf = new XLF(project); + xlfs[resource] = xlf; + } + xlf.addFile(`src/${coreModule}`, keys, messages); + } + } + for (let resource in xlfs) { + const xlf = xlfs[resource]; + const filePath = `${xlf.project}/${resource.replace(/\//g, '_')}.xlf`; + const xlfFile = new File({ + path: filePath, + contents: new Buffer(xlf.toString(), 'utf8') + }); + this.queue(xlfFile); + } + } else { + this.emit('error', new Error(`File ${file.relative} is not using a buffer content`)); return; - case '[': - inMessageSection = '[Messages]' === line || '[CustomMessages]' === line; - return; - } - if (!inMessageSection) { - return; - } - let sections: string[] = line.split('='); - if (sections.length !== 2) { - throw new Error(`Badly formatted message found: ${line}`); - } else { - let key = sections[0]; - let value = sections[1]; - if (key.length > 0 && value.length > 0) { - keys.push(key); - messages.push(value); } + } else { + this.emit('error', new Error(`File ${file.relative} is not a core meta data file.`)); + return; } }); +} - const originalPath = file.path.substring(file.cwd.length + 1, file.path.split('.')[0].length).replace(/\\/g, '/'); - xlf.addFile(originalPath, keys, messages); +export function createXlfFilesForExtensions(): ThroughStream { + let counter: number = 0; + let folderStreamEnded: boolean = false; + let folderStreamEndEmitted: boolean = false; + return through(function (this: ThroughStream, extensionFolder: File) { + const folderStream = this; + const stat = fs.statSync(extensionFolder.path); + if (!stat.isDirectory()) { + return; + } + let extensionName = path.basename(extensionFolder.path); + if (extensionName === 'node_modules') { + return; + } + counter++; + let _xlf: XLF; + function getXlf() { + if (!_xlf) { + _xlf = new XLF(extensionsProject); + } + return _xlf; + } + gulp.src([`./extensions/${extensionName}/package.nls.json`, `./extensions/${extensionName}/**/nls.metadata.json`]).pipe(through(function (file: File) { + if (file.isBuffer()) { + const buffer: Buffer = file.contents as Buffer; + const basename = path.basename(file.path); + if (basename === 'package.nls.json') { + const json: PackageJsonFormat = JSON.parse(buffer.toString('utf8')); + const keys = Object.keys(json); + const messages = keys.map((key) => { + const value = json[key]; + if (Is.string(value)) { + return value; + } else if (value) { + return value.message; + } else { + return `Unknown message for key: ${key}`; + } + }); + getXlf().addFile(`extensions/${extensionName}/package`, keys, messages); + } else if (basename === 'nls.metadata.json') { + const json: BundledExtensionFormat = JSON.parse(buffer.toString('utf8')); + const relPath = path.relative(`./extensions/${extensionName}`, path.dirname(file.path)); + for (let file in json) { + const fileContent = json[file]; + getXlf().addFile(`extensions/${extensionName}/${relPath}/${file}`, fileContent.keys, fileContent.messages); + } + } else { + this.emit('error', new Error(`${file.path} is not a valid extension nls file`)); + return; + } + } + }, function () { + if (_xlf) { + let xlfFile = new File({ + path: path.join(extensionsProject, extensionName + '.xlf'), + contents: new Buffer(_xlf.toString(), 'utf8') + }); + folderStream.queue(xlfFile); + } + this.queue(null); + counter--; + if (counter === 0 && folderStreamEnded && !folderStreamEndEmitted) { + folderStreamEndEmitted = true; + folderStream.queue(null); + } + })); + }, function () { + folderStreamEnded = true; + if (counter === 0) { + folderStreamEndEmitted = true; + this.queue(null); + } + }); +} - // Emit only upon all ISL files combined into single XLF instance - const newFilePath = path.join(projectName, resourceFile); - const xlfFile = new File({ path: newFilePath, contents: new Buffer(xlf.toString(), 'utf-8') }); - stream.emit('data', xlfFile); +export function createXlfFilesForIsl(): ThroughStream { + return through(function (this: ThroughStream, file: File) { + let projectName: string, + resourceFile: string; + if (path.basename(file.path) === 'Default.isl') { + projectName = setupProject; + resourceFile = 'setup_default.xlf'; + } else { + projectName = workbenchProject; + resourceFile = 'setup_messages.xlf'; + } + + let xlf = new XLF(projectName), + keys: string[] = [], + messages: string[] = []; + + let model = new TextModel(file.contents.toString()); + let inMessageSection = false; + model.lines.forEach(line => { + if (line.length === 0) { + return; + } + let firstChar = line.charAt(0); + switch (firstChar) { + case ';': + // Comment line; + return; + case '[': + inMessageSection = '[Messages]' === line || '[CustomMessages]' === line; + return; + } + if (!inMessageSection) { + return; + } + let sections: string[] = line.split('='); + if (sections.length !== 2) { + throw new Error(`Badly formatted message found: ${line}`); + } else { + let key = sections[0]; + let value = sections[1]; + if (key.length > 0 && value.length > 0) { + keys.push(key); + messages.push(value); + } + } + }); + + const originalPath = file.path.substring(file.cwd.length + 1, file.path.split('.')[0].length).replace(/\\/g, '/'); + xlf.addFile(originalPath, keys, messages); + + // Emit only upon all ISL files combined into single XLF instance + const newFilePath = path.join(projectName, resourceFile); + const xlfFile = new File({ path: newFilePath, contents: new Buffer(xlf.toString(), 'utf-8') }); + this.queue(xlfFile); + }); } export function pushXlfFiles(apiHostname: string, username: string, password: string): ThroughStream { let tryGetPromises = []; let updateCreatePromises = []; - return through(function (file: File) { + return through(function (this: ThroughStream, file: File) { const project = path.dirname(file.relative); const fileName = path.basename(file.path); const slug = fileName.substr(0, fileName.length - '.xlf'.length); @@ -799,7 +802,7 @@ export function pushXlfFiles(apiHostname: string, username: string, password: st // End the pipe only after all the communication with Transifex API happened Promise.all(tryGetPromises).then(() => { Promise.all(updateCreatePromises).then(() => { - this.emit('end'); + this.queue(null); }).catch((reason) => { throw new Error(reason); }); }).catch((reason) => { throw new Error(reason); }); }); @@ -910,42 +913,40 @@ function updateResource(project: string, slug: string, xlfFile: File, apiHostnam }); } -function obtainProjectResources(projectName: string): Resource[] { - let resources: Resource[] = []; +// cache resources +let _buildResources: Resource[]; - if (projectName === editorProject) { - const json = fs.readFileSync('./build/lib/i18n.resources.json', 'utf8'); - resources = JSON.parse(json).editor; - } else if (projectName === workbenchProject) { - const json = fs.readFileSync('./build/lib/i18n.resources.json', 'utf8'); - resources = JSON.parse(json).workbench; - } else if (projectName === extensionsProject) { - let extensionsToLocalize: string[] = glob.sync('./extensions/**/*.nls.json').map(extension => extension.split('/')[2]); - let resourcesToPull: string[] = []; +export function pullBuildXlfFiles(apiHostname: string, username: string, password: string, language: Language): NodeJS.ReadableStream { + if (!_buildResources) { + _buildResources = []; + // editor and workbench + const json = JSON.parse(fs.readFileSync('./build/lib/i18n.resources.json', 'utf8')); + _buildResources.push(...json.editor); + _buildResources.push(...json.workbench); - extensionsToLocalize.forEach(extension => { - if (resourcesToPull.indexOf(extension) === -1) { // remove duplicate elements returned by glob - resourcesToPull.push(extension); - resources.push({ name: extension, project: projectName }); - } + // 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); + + Object.keys(extensionsToLocalize).forEach(extension => { + _buildResources.push({ name: extension, project: 'vscode-extensions' }); }); - } else if (projectName === setupProject) { - resources.push({ name: 'setup_default', project: setupProject }); } - - return resources; + return pullXlfFiles(apiHostname, username, password, language, _buildResources); } -export function pullXlfFiles(projectName: string, apiHostname: string, username: string, password: string, languages: string[], resources?: Resource[]): NodeJS.ReadableStream { - if (!resources) { - resources = obtainProjectResources(projectName); - } - if (!resources) { - throw new Error('Transifex projects and resources must be defined to be able to pull translations from Transifex.'); +export function pullSetupXlfFiles(apiHostname: string, username: string, password: string, language: Language, includeDefault: boolean): NodeJS.ReadableStream { + let setupResources = [{ name: 'setup_messages', project: 'vscode-workbench' }]; + if (includeDefault) { + setupResources.push({ name: 'setup_default', project: 'vscode-setup' }); } + return pullXlfFiles(apiHostname, username, password, language, setupResources); +} +function pullXlfFiles(apiHostname: string, username: string, password: string, language: Language, resources: Resource[]): NodeJS.ReadableStream { const credentials = `${username}:${password}`; - let expectedTranslationsCount = languages.length * resources.length; + let expectedTranslationsCount = resources.length; let translationsRetrieved = 0, called = false; return readable(function (count, callback) { @@ -957,15 +958,13 @@ export function pullXlfFiles(projectName: string, apiHostname: string, username: if (!called) { called = true; const stream = this; - - // Retrieve XLF files from main projects - languages.map(function (language) { - resources.map(function (resource) { - retrieveResource(language, resource, apiHostname, credentials).then((file: File) => { + resources.map(function (resource) { + retrieveResource(language, resource, apiHostname, credentials).then((file: File) => { + if (file) { stream.emit('data', file); - translationsRetrieved++; - }).catch(error => { throw new Error(error); }); - }); + } + translationsRetrieved++; + }).catch(error => { throw new Error(error); }); }); } @@ -974,14 +973,14 @@ export function pullXlfFiles(projectName: string, apiHostname: string, username: } const limiter = new Limiter(NUMBER_OF_CONCURRENT_DOWNLOADS); -function retrieveResource(language: string, resource: Resource, apiHostname, credentials): Promise { +function retrieveResource(language: Language, resource: Resource, apiHostname, credentials): Promise { return limiter.queue(() => new Promise((resolve, reject) => { const slug = resource.name.replace(/\//g, '_'); const project = resource.project; - const iso639 = language.toLowerCase(); + const transifexLanguageId = language.transifexId || language.id; const options = { hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/translation/${iso639}?file&mode=onlyreviewed`, + path: `/api/2/project/${project}/resource/${slug}/translation/${transifexLanguageId}?file&mode=onlyreviewed`, auth: credentials, port: 443, method: 'GET' @@ -992,102 +991,152 @@ function retrieveResource(language: string, resource: Resource, apiHostname, cre res.on('data', (chunk: Buffer) => xlfBuffer.push(chunk)); res.on('end', () => { if (res.statusCode === 200) { - console.log('success: ' + options.path); - resolve(new File({ contents: Buffer.concat(xlfBuffer), path: `${project}/${iso639_2_to_3[language]}/${slug}.xlf` })); + resolve(new File({ contents: Buffer.concat(xlfBuffer), path: `${project}/${slug}.xlf` })); + } else if (res.statusCode === 404) { + console.log(`${slug} in ${project} returned no data.`); + resolve(null); + } else { + reject(`${slug} in ${project} returned no data. Response code: ${res.statusCode}.`); } - reject(`${slug} in ${project} returned no data. Response code: ${res.statusCode}.`); }); }); request.on('error', (err) => { reject(`Failed to query resource ${slug} with the following error: ${err}. ${options.path}`); }); request.end(); - console.log('started: ' + options.path); })); } -export function prepareJsonFiles(): ThroughStream { +export function prepareI18nFiles(): ThroughStream { let parsePromises: Promise[] = []; - return through(function (xlf: File) { + return through(function (this: ThroughStream, xlf: File) { let stream = this; let parsePromise = XLF.parse(xlf.contents.toString()); parsePromises.push(parsePromise); parsePromise.then( - function (resolvedFiles) { + resolvedFiles => { resolvedFiles.forEach(file => { - let messages = file.messages, translatedFile; - - // ISL file path always starts with 'build/' - if (/^build\//.test(file.originalFilePath)) { - const defaultLanguages = { 'zh-hans': true, 'zh-hant': true, 'ko': true }; - if (path.basename(file.originalFilePath) === 'Default' && !defaultLanguages[file.language]) { - return; - } - - translatedFile = createIslFile('..', file.originalFilePath, messages, iso639_2_to_3[file.language]); - } else { - translatedFile = createI18nFile(iso639_2_to_3[file.language], file.originalFilePath, messages); - } - - stream.emit('data', translatedFile); + let translatedFile = createI18nFile(file.originalFilePath, file.messages); + stream.queue(translatedFile); }); - }, - function (rejectReason) { - throw new Error(`XLF parsing error: ${rejectReason}`); } ); }, function () { Promise.all(parsePromises) - .then(() => { this.emit('end'); }) + .then(() => { this.queue(null); }) .catch(reason => { throw new Error(reason); }); }); } -function createI18nFile(base: string, originalFilePath: string, messages: Map): File { - let content = [ - '/*---------------------------------------------------------------------------------------------', - ' * Copyright (c) Microsoft Corporation. All rights reserved.', - ' * Licensed under the MIT License. See License.txt in the project root for license information.', - ' *--------------------------------------------------------------------------------------------*/', - '// Do not edit this file. It is machine generated.' - ].join('\n') + '\n' + JSON.stringify(messages, null, '\t').replace(/\r\n/g, '\n'); +function createI18nFile(originalFilePath: string, messages: any): File { + let result = Object.create(null); + result[''] = [ + '--------------------------------------------------------------------------------------------', + 'Copyright (c) Microsoft Corporation. All rights reserved.', + 'Licensed under the MIT License. See License.txt in the project root for license information.', + '--------------------------------------------------------------------------------------------', + 'Do not edit this file. It is machine generated.' + ]; + for (let key of Object.keys(messages)) { + result[key] = messages[key]; + } + let content = JSON.stringify(result, null, '\t').replace(/\r\n/g, '\n'); return new File({ - path: path.join(base, originalFilePath + '.i18n.json'), + path: path.join(originalFilePath + '.i18n.json'), contents: new Buffer(content, 'utf8') }); } +interface I18nPack { + version: string; + contents: { + [path: string]: Map; + }; +} -const languageNames: Map = { - 'chs': 'Simplified Chinese', - 'cht': 'Traditional Chinese', - 'kor': 'Korean' -}; +const i18nPackVersion = "1.0.0"; -const languageIds: Map = { - 'chs': '$0804', - 'cht': '$0404', - 'kor': '$0412' -}; +export function pullI18nPackFiles(apiHostname: string, username: string, password: string, language: Language): NodeJS.ReadableStream { + return pullBuildXlfFiles(apiHostname, username, password, language).pipe(prepareI18nPackFiles()); +} -const encodings: Map = { - 'chs': 'CP936', - 'cht': 'CP950', - 'jpn': 'CP932', - 'kor': 'CP949', - 'deu': 'CP1252', - 'fra': 'CP1252', - 'esn': 'CP1252', - 'rus': 'CP1251', - 'ita': 'CP1252', - 'ptb': 'CP1252', - 'hun': 'CP1250', - 'trk': 'CP1254' -}; +export function prepareI18nPackFiles() { + let parsePromises: Promise[] = []; + let mainPack: I18nPack = { version: i18nPackVersion, contents: {} }; + let extensionsPacks: Map = {}; + return through(function (this: ThroughStream, xlf: File) { + let stream = this; + let parsePromise = XLF.parse(xlf.contents.toString()); + parsePromises.push(parsePromise); + parsePromise.then( + resolvedFiles => { + resolvedFiles.forEach(file => { + const path = file.originalFilePath; + const firstSlash = path.indexOf('/'); + const firstSegment = path.substr(0, firstSlash); + if (firstSegment === 'src') { + mainPack.contents[path.substr(firstSlash + 1)] = file.messages; + } else if (firstSegment === 'extensions') { + const secondSlash = path.indexOf('/', firstSlash + 1); + const secondSegment = path.substring(firstSlash + 1, secondSlash); + if (secondSegment) { + let extPack = extensionsPacks[secondSegment]; + if (!extPack) { + extPack = extensionsPacks[secondSegment] = { version: i18nPackVersion, contents: {} }; + } + extPack.contents[path.substr(secondSlash + 1)] = file.messages; + } else { + console.log('Unknown second segment ' + path); + } + } else { + console.log('Unknown first segment ' + path); + } + }); + } + ); + }, function () { + Promise.all(parsePromises) + .then(() => { + const translatedMainFile = createI18nFile('./main', mainPack); + this.queue(translatedMainFile); + for (let extension in extensionsPacks) { + const translatedExtFile = createI18nFile(`./extensions/${extension}`, extensionsPacks[extension]); + this.queue(translatedExtFile); + } + this.queue(null); + }) + .catch(reason => { throw new Error(reason); }); + }); +} -function createIslFile(base: string, originalFilePath: string, messages: Map, language: string): File { +export function prepareIslFiles(language: Language, innoSetupConfig: InnoSetup): ThroughStream { + let parsePromises: Promise[] = []; + + return through(function (this: ThroughStream, xlf: File) { + let stream = this; + let parsePromise = XLF.parse(xlf.contents.toString()); + parsePromises.push(parsePromise); + parsePromise.then( + resolvedFiles => { + resolvedFiles.forEach(file => { + if (path.basename(file.originalFilePath) === 'Default' && !innoSetupConfig.defaultInfo) { + return; + } + let translatedFile = createIslFile(file.originalFilePath, file.messages, language, innoSetupConfig); + stream.queue(translatedFile); + }); + } + ); + }, function () { + Promise.all(parsePromises) + .then(() => { this.queue(null); }) + .catch(reason => { throw new Error(reason); }); + }); +} + +function createIslFile(originalFilePath: string, messages: Map, language: Language, innoSetup: InnoSetup): File { let content: string[] = []; let originalContent: TextModel; if (path.basename(originalFilePath) === 'Default') { @@ -1095,13 +1144,12 @@ function createIslFile(base: string, originalFilePath: string, messages: Map { if (line.length > 0) { let firstChar = line.charAt(0); if (firstChar === '[' || firstChar === ';') { if (line === '; *** Inno Setup version 5.5.3+ English messages ***') { - content.push(`; *** Inno Setup version 5.5.3+ ${languageNames[language]} messages ***`); + content.push(`; *** Inno Setup version 5.5.3+ ${innoSetup.defaultInfo.name} messages ***`); } else { content.push(line); } @@ -1111,11 +1159,11 @@ function createIslFile(base: string, originalFilePath: string, messages: Map NodeJS.ReadWriteStream { const entryPoints = opts.entryPoints; @@ -239,7 +239,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr })) .pipe(gulp.dest(out)); }; -}; +} declare class FileWithCopyright extends VinylFile { public __hasOurCopyright: boolean; @@ -324,4 +324,4 @@ export function minifyTask(src: string, sourceMapBaseUrl: string): (cb: any) => cb(err); }); }; -}; +} diff --git a/build/lib/typings/event-stream.d.ts b/build/lib/typings/event-stream.d.ts index 7e5ccee5e17..d79ac9183d0 100644 --- a/build/lib/typings/event-stream.d.ts +++ b/build/lib/typings/event-stream.d.ts @@ -1,7 +1,14 @@ declare module "event-stream" { import { Stream } from 'stream'; - import { ThroughStream } from 'through'; + import { ThroughStream as _ThroughStream} from 'through'; import { MapStream } from 'map-stream'; + import * as File from 'vinyl'; + + export interface ThroughStream extends _ThroughStream { + queue(data: File | null); + push(data: File | null); + paused: boolean; + } function merge(streams: Stream[]): ThroughStream; function merge(...streams: Stream[]): ThroughStream; diff --git a/build/npm/update-localization-extension.js b/build/npm/update-localization-extension.js new file mode 100644 index 00000000000..ca8a4139d6d --- /dev/null +++ b/build/npm/update-localization-extension.js @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +let i18n = require("../lib/i18n"); + +let fs = require("fs"); +let path = require("path"); +let vfs = require("vinyl-fs"); +let rimraf = require('rimraf'); + +function update(idOrPath) { + if (!idOrPath) { + throw new Error('Argument must be the location of the localization extension.'); + return; + } + let locExtFolder = idOrPath; + if (/^\w{2}(-\w+)?$/.test(idOrPath)) { + locExtFolder = '../vscode-localization-' + idOrPath; + } + let locExtStat = fs.statSync(locExtFolder); + if (!locExtStat || !locExtStat.isDirectory) { + throw new Error('No directory found at ' + idOrPath); + } + let packageJSON = JSON.parse(fs.readFileSync(path.join(locExtFolder, 'package.json')).toString()); + let contributes = packageJSON['contributes']; + if (!contributes) { + throw new Error('The extension must define a "localizations" contribution in the "package.json"'); + } + let localizations = contributes['localizations']; + if (!localizations) { + throw new Error('The extension must define a "localizations" contribution of type array in the "package.json"'); + } + + localizations.forEach(function (localization) { + if (!localization.languageId || !localization.languageName || !localization.translations) { + throw new Error('Each localization contribution must define "languageId", "languageName" and "translations" properties.'); + } + let server = localization.server || 'www.transifex.com'; + let userName = localization.userName || 'api'; + let apiToken = process.env.TRANSIFEX_API_TOKEN; + let languageId = localization.transifexId || localization.languageId; + let translationDataFolder = path.join(locExtFolder, localization.translations); + + if (fs.existsSync(translationDataFolder) && fs.existsSync(path.join(translationDataFolder, 'main.i18n.json'))) { + console.log('Clearing \'' + translationDataFolder + '\'...'); + rimraf.sync(translationDataFolder); + } + + console.log('Downloading translations for \'' + languageId + '\' to \'' + translationDataFolder + '\'...'); + i18n.pullI18nPackFiles(server, userName, apiToken, { id: languageId }) + .pipe(vfs.dest(translationDataFolder)); + }); + + +} +if (path.basename(process.argv[1]) === 'update-localization-extension.js') { + update(process.argv[2]); +} diff --git a/build/win32/inno_updater.exe b/build/win32/inno_updater.exe index c83bcd48cac..2d5d1ab1d49 100644 Binary files a/build/win32/inno_updater.exe and b/build/win32/inno_updater.exe differ diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json index cbf3960da86..ed2819ba97f 100644 --- a/extensions/configuration-editing/package.json +++ b/extensions/configuration-editing/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "jsonc-parser": "^1.0.0", - "vscode-nls": "^2.0.1" + "vscode-nls": "^3.1.2" }, "contributes": { "jsonValidation": [ diff --git a/extensions/configuration-editing/src/extension.ts b/extensions/configuration-editing/src/extension.ts index a081f0ad448..ab31432ee85 100644 --- a/extensions/configuration-editing/src/extension.ts +++ b/extensions/configuration-editing/src/extension.ts @@ -2,16 +2,14 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ - 'use strict'; +import * as nls from 'vscode-nls'; +const localize = nls.loadMessageBundle(); import * as vscode from 'vscode'; import { getLocation, visit, parse } from 'jsonc-parser'; import * as path from 'path'; import { SettingsDocument } from './settingsDocumentHelper'; -import * as nls from 'vscode-nls'; - -const localize = nls.loadMessageBundle(); const decoration = vscode.window.createTextEditorDecorationType({ color: '#9e9e9e' diff --git a/extensions/configuration-editing/yarn.lock b/extensions/configuration-editing/yarn.lock index 6e178dd74ea..3aecfb034d5 100644 --- a/extensions/configuration-editing/yarn.lock +++ b/extensions/configuration-editing/yarn.lock @@ -10,6 +10,6 @@ jsonc-parser@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-1.0.0.tgz#ddcc864ae708e60a7a6dd36daea00172fa8d9272" -vscode-nls@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" diff --git a/extensions/css/client/src/cssMain.ts b/extensions/css/client/src/cssMain.ts index 6c64c46a54e..930deba4a6e 100644 --- a/extensions/css/client/src/cssMain.ts +++ b/extensions/css/client/src/cssMain.ts @@ -3,18 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ 'use strict'; - import * as path from 'path'; +import * as nls from 'vscode-nls'; +const localize = nls.loadMessageBundle(); + import { languages, window, commands, ExtensionContext, TextDocument, ColorInformation, ColorPresentation, Color, Range, Position, CompletionItem, CompletionItemKind, TextEdit, SnippetString } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient'; import { ConfigurationFeature } from 'vscode-languageclient/lib/configuration.proposed'; import { DocumentColorRequest, DocumentColorParams, ColorPresentationRequest, ColorPresentationParams } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; -import * as nls from 'vscode-nls'; -let localize = nls.loadMessageBundle(); - // this method is called when vs code is activated export function activate(context: ExtensionContext) { diff --git a/extensions/css/package.json b/extensions/css/package.json index e404748578a..5f4354623e6 100644 --- a/extensions/css/package.json +++ b/extensions/css/package.json @@ -714,7 +714,7 @@ }, "dependencies": { "vscode-languageclient": "^3.5.0", - "vscode-nls": "^2.0.2" + "vscode-nls": "^3.1.2" }, "devDependencies": { "@types/node": "7.0.43" diff --git a/extensions/css/yarn.lock b/extensions/css/yarn.lock index f50be178c48..e6c3983fb99 100644 --- a/extensions/css/yarn.lock +++ b/extensions/css/yarn.lock @@ -27,6 +27,6 @@ vscode-languageserver-types@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz#e48d79962f0b8e02de955e3f524908e2b19c0374" -vscode-nls@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index 38326f318eb..8e9c4b0236e 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -320,6 +320,6 @@ "vscode-emmet-helper": "^1.1.21", "vscode-languageserver-types": "^3.5.0", "image-size": "^0.5.2", - "vscode-nls": "2.0.2" + "vscode-nls": "3.1.2" } } \ No newline at end of file diff --git a/extensions/emmet/yarn.lock b/extensions/emmet/yarn.lock index c3294d4438d..bc19aef330b 100644 --- a/extensions/emmet/yarn.lock +++ b/extensions/emmet/yarn.lock @@ -2068,9 +2068,9 @@ vscode-languageserver-types@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz#e48d79962f0b8e02de955e3f524908e2b19c0374" -vscode-nls@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.0.tgz#a8a264c0d4bd3e1ed4746a9883235fec5b62968a" vscode@1.0.1: version "1.0.1" diff --git a/extensions/extension-editing/package.json b/extensions/extension-editing/package.json index 8f4b631803e..fe7e6bdb413 100644 --- a/extensions/extension-editing/package.json +++ b/extensions/extension-editing/package.json @@ -23,7 +23,7 @@ "jsonc-parser": "^1.0.0", "markdown-it": "^8.3.1", "parse5": "^3.0.2", - "vscode-nls": "^2.0.1" + "vscode-nls": "^3.1.2" }, "contributes": { "jsonValidation": [ diff --git a/extensions/extension-editing/src/extensionLinter.ts b/extensions/extension-editing/src/extensionLinter.ts index 63dab8afefb..0e486252598 100644 --- a/extensions/extension-editing/src/extensionLinter.ts +++ b/extensions/extension-editing/src/extensionLinter.ts @@ -6,8 +6,10 @@ import * as fs from 'fs'; import * as path from 'path'; -import { parseTree, findNodeAtLocation, Node as JsonNode } from 'jsonc-parser'; import * as nls from 'vscode-nls'; +const localize = nls.loadMessageBundle(); + +import { parseTree, findNodeAtLocation, Node as JsonNode } from 'jsonc-parser'; import * as MarkdownItType from 'markdown-it'; import { languages, workspace, Disposable, TextDocument, Uri, Diagnostic, Range, DiagnosticSeverity, Position } from 'vscode'; @@ -15,8 +17,6 @@ import { languages, workspace, Disposable, TextDocument, Uri, Diagnostic, Range, const product = require('../../../product.json'); const allowedBadgeProviders: string[] = (product.extensionAllowedBadgeProviders || []).map(s => s.toLowerCase()); -const localize = nls.loadMessageBundle(); - const httpsRequired = localize('httpsRequired', "Images must use the HTTPS protocol."); const svgsNotValid = localize('svgsNotValid', "SVGs are not a valid image source."); const embeddedSvgsNotValid = localize('embeddedSvgsNotValid', "Embedded SVGs are not a valid image source."); diff --git a/extensions/extension-editing/yarn.lock b/extensions/extension-editing/yarn.lock index ce500bb28a0..e0072b69ac8 100644 --- a/extensions/extension-editing/yarn.lock +++ b/extensions/extension-editing/yarn.lock @@ -58,6 +58,6 @@ uc.micro@^1.0.1, uc.micro@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" -vscode-nls@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" diff --git a/extensions/git/package.json b/extensions/git/package.json index 645361ff5ec..e1c8322553e 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -1001,7 +1001,7 @@ "file-type": "^7.2.0", "iconv-lite": "0.4.19", "vscode-extension-telemetry": "0.0.8", - "vscode-nls": "2.0.2", + "vscode-nls": "^3.1.2", "which": "^1.3.0" }, "devDependencies": { @@ -1012,4 +1012,4 @@ "@types/which": "^1.0.28", "mocha": "^3.2.0" } -} \ No newline at end of file +} diff --git a/extensions/git/src/main.ts b/extensions/git/src/main.ts index d82223f0099..c00b71b12af 100644 --- a/extensions/git/src/main.ts +++ b/extensions/git/src/main.ts @@ -6,7 +6,7 @@ 'use strict'; import * as nls from 'vscode-nls'; -const localize = nls.config(process.env.VSCODE_NLS_CONFIG)(); +const localize = nls.loadMessageBundle(); import { ExtensionContext, workspace, window, Disposable, commands, Uri, OutputChannel } from 'vscode'; import { findGit, Git, IGit } from './git'; import { Model } from './model'; diff --git a/extensions/git/yarn.lock b/extensions/git/yarn.lock index a9d4c679d30..807d677b30a 100644 --- a/extensions/git/yarn.lock +++ b/extensions/git/yarn.lock @@ -242,9 +242,9 @@ vscode-extension-telemetry@0.0.8: applicationinsights "0.18.0" winreg "1.2.3" -vscode-nls@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" which@^1.3.0: version "1.3.0" diff --git a/extensions/grunt/package.json b/extensions/grunt/package.json index b330d18326c..c63b52e02b4 100644 --- a/extensions/grunt/package.json +++ b/extensions/grunt/package.json @@ -15,7 +15,7 @@ "watch": "gulp watch-extension:grunt" }, "dependencies": { - "vscode-nls": "^2.0.2" + "vscode-nls": "^3.1.2" }, "devDependencies": { "@types/node": "7.0.43" diff --git a/extensions/grunt/src/main.ts b/extensions/grunt/src/main.ts index d08e845c1ba..3f425451a30 100644 --- a/extensions/grunt/src/main.ts +++ b/extensions/grunt/src/main.ts @@ -9,8 +9,7 @@ import * as fs from 'fs'; import * as cp from 'child_process'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; - -const localize = nls.config(process.env.VSCODE_NLS_CONFIG)(); +const localize = nls.loadMessageBundle(); type AutoDetect = 'on' | 'off'; @@ -68,7 +67,7 @@ interface GruntTaskDefinition extends vscode.TaskDefinition { class FolderDetector { - private fileWatcher: vscode.FileSystemWatcher; + private fileWatcher: vscode.FileSystemWatcher | undefined; private promise: Thenable | undefined; constructor(private _workspaceFolder: vscode.WorkspaceFolder) { diff --git a/extensions/grunt/yarn.lock b/extensions/grunt/yarn.lock index cde3e475ca8..e2fc7ae342e 100644 --- a/extensions/grunt/yarn.lock +++ b/extensions/grunt/yarn.lock @@ -6,6 +6,6 @@ version "7.0.43" resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c" -vscode-nls@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" diff --git a/extensions/gulp/package.json b/extensions/gulp/package.json index 00e098d9b20..525398dcf9a 100644 --- a/extensions/gulp/package.json +++ b/extensions/gulp/package.json @@ -15,7 +15,7 @@ "watch": "gulp watch-extension:gulp" }, "dependencies": { - "vscode-nls": "^2.0.2" + "vscode-nls": "^3.1.2" }, "devDependencies": { "@types/node": "7.0.43" diff --git a/extensions/gulp/src/main.ts b/extensions/gulp/src/main.ts index 51a64054021..def484dc13f 100644 --- a/extensions/gulp/src/main.ts +++ b/extensions/gulp/src/main.ts @@ -8,9 +8,9 @@ import * as path from 'path'; import * as fs from 'fs'; import * as cp from 'child_process'; import * as vscode from 'vscode'; -import * as nls from 'vscode-nls'; -const localize = nls.config(process.env.VSCODE_NLS_CONFIG)(); +import * as nls from 'vscode-nls'; +const localize = nls.loadMessageBundle(); type AutoDetect = 'on' | 'off'; diff --git a/extensions/gulp/yarn.lock b/extensions/gulp/yarn.lock index cde3e475ca8..e2fc7ae342e 100644 --- a/extensions/gulp/yarn.lock +++ b/extensions/gulp/yarn.lock @@ -6,6 +6,6 @@ version "7.0.43" resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c" -vscode-nls@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" diff --git a/extensions/html/client/src/htmlMain.ts b/extensions/html/client/src/htmlMain.ts index b4b84b3ee01..a3bc91466ea 100644 --- a/extensions/html/client/src/htmlMain.ts +++ b/extensions/html/client/src/htmlMain.ts @@ -5,6 +5,8 @@ 'use strict'; import * as path from 'path'; +import * as nls from 'vscode-nls'; +const localize = nls.loadMessageBundle(); import { languages, ExtensionContext, IndentAction, Position, TextDocument, Color, ColorInformation, ColorPresentation, Range, CompletionItem, CompletionItemKind, SnippetString } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, TextDocumentPositionParams } from 'vscode-languageclient'; @@ -14,9 +16,6 @@ import TelemetryReporter from 'vscode-extension-telemetry'; import { DocumentColorRequest, DocumentColorParams, ColorPresentationRequest, ColorPresentationParams } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; -import * as nls from 'vscode-nls'; -let localize = nls.loadMessageBundle(); - namespace TagCloseRequest { export const type: RequestType = new RequestType('html/tag'); } diff --git a/extensions/html/package.json b/extensions/html/package.json index 13e5d82ca51..c9662fab156 100644 --- a/extensions/html/package.json +++ b/extensions/html/package.json @@ -226,7 +226,7 @@ "dependencies": { "vscode-extension-telemetry": "0.0.8", "vscode-languageclient": "^3.5.0", - "vscode-nls": "2.0.2" + "vscode-nls": "^3.1.2" }, "devDependencies": { "@types/node": "7.0.43" diff --git a/extensions/html/server/package.json b/extensions/html/server/package.json index 65cd75b02e9..37ab867085e 100644 --- a/extensions/html/server/package.json +++ b/extensions/html/server/package.json @@ -11,7 +11,7 @@ "vscode-css-languageservice": "^3.0.3", "vscode-html-languageservice": "^2.0.14", "vscode-languageserver": "^3.5.0", - "vscode-nls": "^2.0.2", + "vscode-nls": "^3.1.2", "vscode-uri": "^1.0.1" }, "devDependencies": { diff --git a/extensions/html/server/src/htmlServerMain.ts b/extensions/html/server/src/htmlServerMain.ts index 85383529fd4..cf03f00d561 100644 --- a/extensions/html/server/src/htmlServerMain.ts +++ b/extensions/html/server/src/htmlServerMain.ts @@ -18,10 +18,6 @@ import { getDocumentContext } from './utils/documentContext'; import uri from 'vscode-uri'; import { formatError, runSafe } from './utils/errors'; -import * as nls from 'vscode-nls'; - -nls.config(process.env['VSCODE_NLS_CONFIG']); - namespace TagCloseRequest { export const type: RequestType = new RequestType('html/tag'); } diff --git a/extensions/html/server/yarn.lock b/extensions/html/server/yarn.lock index d676d5f4456..f12116b9872 100644 --- a/extensions/html/server/yarn.lock +++ b/extensions/html/server/yarn.lock @@ -51,6 +51,10 @@ vscode-nls@^2.0.1, vscode-nls@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" + vscode-uri@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.1.tgz#11a86befeac3c4aa3ec08623651a3c81a6d0bbc8" diff --git a/extensions/html/yarn.lock b/extensions/html/yarn.lock index 4ebd6092170..fac01e86dad 100644 --- a/extensions/html/yarn.lock +++ b/extensions/html/yarn.lock @@ -38,9 +38,9 @@ vscode-languageserver-types@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz#e48d79962f0b8e02de955e3f524908e2b19c0374" -vscode-nls@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" winreg@1.2.3: version "1.2.3" diff --git a/extensions/jake/package.json b/extensions/jake/package.json index 58ba0168e4a..374be5cea88 100644 --- a/extensions/jake/package.json +++ b/extensions/jake/package.json @@ -15,7 +15,7 @@ "watch": "gulp watch-extension:jake" }, "dependencies": { - "vscode-nls": "^2.0.2" + "vscode-nls": "^3.1.2" }, "devDependencies": { "@types/node": "7.0.43" diff --git a/extensions/jake/src/main.ts b/extensions/jake/src/main.ts index 0a2032c970c..514cfbacd41 100644 --- a/extensions/jake/src/main.ts +++ b/extensions/jake/src/main.ts @@ -9,8 +9,7 @@ import * as fs from 'fs'; import * as cp from 'child_process'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; - -const localize = nls.config(process.env.VSCODE_NLS_CONFIG)(); +const localize = nls.loadMessageBundle(); type AutoDetect = 'on' | 'off'; @@ -68,7 +67,7 @@ interface JakeTaskDefinition extends vscode.TaskDefinition { class FolderDetector { - private fileWatcher: vscode.FileSystemWatcher; + private fileWatcher: vscode.FileSystemWatcher | undefined; private promise: Thenable | undefined; constructor(private _workspaceFolder: vscode.WorkspaceFolder) { diff --git a/extensions/jake/yarn.lock b/extensions/jake/yarn.lock index cde3e475ca8..e2fc7ae342e 100644 --- a/extensions/jake/yarn.lock +++ b/extensions/jake/yarn.lock @@ -6,6 +6,6 @@ version "7.0.43" resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c" -vscode-nls@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" diff --git a/extensions/javascript/package.json b/extensions/javascript/package.json index 8a6e0ed6708..b3377418c01 100644 --- a/extensions/javascript/package.json +++ b/extensions/javascript/package.json @@ -13,7 +13,7 @@ "dependencies": { "jsonc-parser": "^1.0.0", "request-light": "^0.2.2", - "vscode-nls": "^2.0.2" + "vscode-nls": "^3.1.2" }, "scripts": { "compile": "gulp compile-extension:javascript", diff --git a/extensions/javascript/src/javascriptMain.ts b/extensions/javascript/src/javascriptMain.ts index ed2552b87f0..319c5bae577 100644 --- a/extensions/javascript/src/javascriptMain.ts +++ b/extensions/javascript/src/javascriptMain.ts @@ -8,13 +8,9 @@ import { addJSONProviders } from './features/jsonContributions'; import * as httpRequest from 'request-light'; -import { ExtensionContext, env, workspace } from 'vscode'; - -import * as nls from 'vscode-nls'; +import { ExtensionContext, workspace } from 'vscode'; export function activate(context: ExtensionContext): any { - nls.config({ locale: env.language }); - configureHttpRequest(); workspace.onDidChangeConfiguration(() => configureHttpRequest()); diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json index 29765c0ba34..45dc54b7115 100644 --- a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/8b44958a27860957872cc6f628d843a71686af63", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/51323af933792ffbb9a088fd500536122be38b59", "name": "JavaScript (with React support)", "scopeName": "source.js", "fileTypes": [ @@ -292,7 +292,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.js", - "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js entity.name.function.js" @@ -354,7 +354,7 @@ "patterns": [ { "name": "meta.object-binding-pattern-variable.js", - "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.js" @@ -753,7 +753,7 @@ }, { "name": "meta.definition.property.js entity.name.function.js", - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))" }, { "name": "meta.definition.property.js variable.object.property.js", @@ -1884,7 +1884,7 @@ }, "after-operator-block-as-object-literal": { "name": "meta.objectliteral.js", - "begin": "(?<=[=(,\\[?+!]|await|return|yield|throw|in|of|typeof|&&|\\|\\||\\*)\\s*(\\{)", + "begin": "(?<=[=(,\\[?+!]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)", "beginCaptures": { "1": { "name": "punctuation.definition.block.js" @@ -2057,13 +2057,13 @@ ] }, "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\)))*\\>)*>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\)))*\\>)*>\\s*)?\\()", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "name": "meta.function-call.js", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\)))*\\>)*>\\s*)?\\()", + "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "include": "#literal" @@ -3295,7 +3295,7 @@ "patterns": [ { "name": "string.regexp.js", - "begin": "(?<=[=(:,\\[?+!]|return|case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "begin": "(?<=[=(:,\\[?+!]|^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", "beginCaptures": { "1": { "name": "punctuation.definition.string.begin.js" @@ -4041,7 +4041,7 @@ ] }, "jsx-tag-without-attributes-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", + "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", "patterns": [ { @@ -4089,7 +4089,7 @@ ] }, "jsx-tag-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", "end": "(/>)|(?:())", "endCaptures": { "0": { diff --git a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json index 30557f4a531..85ebfe2446f 100644 --- a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/8b44958a27860957872cc6f628d843a71686af63", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/51323af933792ffbb9a088fd500536122be38b59", "name": "JavaScript (with React support)", "scopeName": "source.js.jsx", "fileTypes": [ @@ -292,7 +292,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.js.jsx", - "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js.jsx entity.name.function.js.jsx" @@ -354,7 +354,7 @@ "patterns": [ { "name": "meta.object-binding-pattern-variable.js.jsx", - "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.js.jsx" @@ -753,7 +753,7 @@ }, { "name": "meta.definition.property.js.jsx entity.name.function.js.jsx", - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))" }, { "name": "meta.definition.property.js.jsx variable.object.property.js.jsx", @@ -1884,7 +1884,7 @@ }, "after-operator-block-as-object-literal": { "name": "meta.objectliteral.js.jsx", - "begin": "(?<=[=(,\\[?+!]|await|return|yield|throw|in|of|typeof|&&|\\|\\||\\*)\\s*(\\{)", + "begin": "(?<=[=(,\\[?+!]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)", "beginCaptures": { "1": { "name": "punctuation.definition.block.js.jsx" @@ -2057,13 +2057,13 @@ ] }, "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\)))*\\>)*>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\)))*\\>)*>\\s*)?\\()", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "name": "meta.function-call.js.jsx", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\)))*\\>)*>\\s*)?\\()", + "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "include": "#literal" @@ -3295,7 +3295,7 @@ "patterns": [ { "name": "string.regexp.js.jsx", - "begin": "(?<=[=(:,\\[?+!]|return|case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "begin": "(?<=[=(:,\\[?+!]|^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", "beginCaptures": { "1": { "name": "punctuation.definition.string.begin.js.jsx" @@ -4041,7 +4041,7 @@ ] }, "jsx-tag-without-attributes-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", + "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", "patterns": [ { @@ -4089,7 +4089,7 @@ ] }, "jsx-tag-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", "end": "(/>)|(?:())", "endCaptures": { "0": { diff --git a/extensions/javascript/yarn.lock b/extensions/javascript/yarn.lock index c74f9ca2c9f..72d121783eb 100644 --- a/extensions/javascript/yarn.lock +++ b/extensions/javascript/yarn.lock @@ -71,3 +71,7 @@ request-light@^0.2.2: vscode-nls@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" + +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" diff --git a/extensions/json/client/src/jsonMain.ts b/extensions/json/client/src/jsonMain.ts index 654db136a3f..e6fe6e4253b 100644 --- a/extensions/json/client/src/jsonMain.ts +++ b/extensions/json/client/src/jsonMain.ts @@ -5,6 +5,8 @@ 'use strict'; import * as path from 'path'; +import * as nls from 'vscode-nls'; +const localize = nls.loadMessageBundle(); import { workspace, languages, ExtensionContext, extensions, Uri, TextDocument, ColorInformation, Color, ColorPresentation, LanguageConfiguration } from 'vscode'; import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification } from 'vscode-languageclient'; @@ -12,10 +14,7 @@ import TelemetryReporter from 'vscode-extension-telemetry'; import { ConfigurationFeature } from 'vscode-languageclient/lib/configuration.proposed'; import { DocumentColorRequest, DocumentColorParams, ColorPresentationParams, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; - -import * as nls from 'vscode-nls'; import { hash } from './utils/hash'; -let localize = nls.loadMessageBundle(); namespace VSCodeContentRequest { export const type: RequestType = new RequestType('vscode/content'); diff --git a/extensions/json/package.json b/extensions/json/package.json index 31f13d8017b..e5ae54bde5b 100644 --- a/extensions/json/package.json +++ b/extensions/json/package.json @@ -164,7 +164,7 @@ "dependencies": { "vscode-extension-telemetry": "0.0.8", "vscode-languageclient": "^3.5.0", - "vscode-nls": "2.0.2" + "vscode-nls": "^3.1.2" }, "devDependencies": { "@types/node": "7.0.43" diff --git a/extensions/json/server/package.json b/extensions/json/server/package.json index 2dc13ac6bef..562689ecf52 100644 --- a/extensions/json/server/package.json +++ b/extensions/json/server/package.json @@ -12,7 +12,7 @@ "request-light": "^0.2.2", "vscode-json-languageservice": "^3.0.4", "vscode-languageserver": "^3.5.0", - "vscode-nls": "^2.0.2", + "vscode-nls": "^3.1.2", "vscode-uri": "^1.0.1" }, "devDependencies": { diff --git a/extensions/json/server/src/jsonServerMain.ts b/extensions/json/server/src/jsonServerMain.ts index 182dfc60ddf..3137b954d36 100644 --- a/extensions/json/server/src/jsonServerMain.ts +++ b/extensions/json/server/src/jsonServerMain.ts @@ -21,9 +21,6 @@ import { formatError, runSafe } from './utils/errors'; import { JSONDocument, JSONSchema, LanguageSettings, getLanguageService, DocumentLanguageSettings } from 'vscode-json-languageservice'; import { getLanguageModelCache } from './languageModelCache'; -import * as nls from 'vscode-nls'; -nls.config(process.env['VSCODE_NLS_CONFIG']); - interface ISchemaAssociations { [pattern: string]: string[]; } diff --git a/extensions/json/server/yarn.lock b/extensions/json/server/yarn.lock index c526bf67451..8c005a3357a 100644 --- a/extensions/json/server/yarn.lock +++ b/extensions/json/server/yarn.lock @@ -99,6 +99,10 @@ vscode-nls@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" + vscode-uri@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.1.tgz#11a86befeac3c4aa3ec08623651a3c81a6d0bbc8" diff --git a/extensions/json/yarn.lock b/extensions/json/yarn.lock index 4ebd6092170..fac01e86dad 100644 --- a/extensions/json/yarn.lock +++ b/extensions/json/yarn.lock @@ -38,9 +38,9 @@ vscode-languageserver-types@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz#e48d79962f0b8e02de955e3f524908e2b19c0374" -vscode-nls@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" winreg@1.2.3: version "1.2.3" diff --git a/extensions/markdown/package.json b/extensions/markdown/package.json index db8a18ec737..6d86a3d88fb 100644 --- a/extensions/markdown/package.json +++ b/extensions/markdown/package.json @@ -314,7 +314,7 @@ "markdown-it": "^8.4.0", "markdown-it-named-headers": "0.0.4", "vscode-extension-telemetry": "^0.0.8", - "vscode-nls": "^2.0.2" + "vscode-nls": "^3.1.2" }, "devDependencies": { "@types/highlight.js": "9.1.10", diff --git a/extensions/markdown/src/commands.ts b/extensions/markdown/src/commands.ts index b0b029f1b24..583c0f85292 100644 --- a/extensions/markdown/src/commands.ts +++ b/extensions/markdown/src/commands.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vscode-nls'; -const localize = nls.config(process.env.VSCODE_NLS_CONFIG)(); +const localize = nls.loadMessageBundle(); import * as vscode from 'vscode'; import * as path from 'path'; diff --git a/extensions/markdown/syntaxes/markdown.tmLanguage b/extensions/markdown/syntaxes/markdown.tmLanguage index 26a48c15d3e..bb0e0c36761 100644 --- a/extensions/markdown/syntaxes/markdown.tmLanguage +++ b/extensions/markdown/syntaxes/markdown.tmLanguage @@ -3318,7 +3318,7 @@ begin (?x) - (\*|_)(?=\S) # Open + \b(\*|_)(?=\S) # Open (?= ( <[^>]*+> # HTML tags @@ -3368,7 +3368,7 @@ end - (?<=\S)(\1)((?!\1)|(?=\1\1)) + (?<=\S)(\1)((?!\1)|(?=\1\1))\b name markup.italic.markdown patterns diff --git a/extensions/markdown/syntaxes/markdown.tmLanguage.base b/extensions/markdown/syntaxes/markdown.tmLanguage.base index ca8b920a22f..442b45acce8 100644 --- a/extensions/markdown/syntaxes/markdown.tmLanguage.base +++ b/extensions/markdown/syntaxes/markdown.tmLanguage.base @@ -808,7 +808,7 @@ begin (?x) - (\*|_)(?=\S) # Open + \b(\*|_)(?=\S) # Open (?= ( <[^>]*+> # HTML tags @@ -858,7 +858,7 @@ end - (?<=\S)(\1)((?!\1)|(?=\1\1)) + (?<=\S)(\1)((?!\1)|(?=\1\1))\b name markup.italic.markdown patterns diff --git a/extensions/markdown/test/colorize-results/test_md.json b/extensions/markdown/test/colorize-results/test_md.json index 01b3aac1707..a3dd8829dfe 100644 --- a/extensions/markdown/test/colorize-results/test_md.json +++ b/extensions/markdown/test/colorize-results/test_md.json @@ -1584,51 +1584,7 @@ } }, { - "c": "in", - "t": "text.html.markdown meta.paragraph.markdown", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "_", - "t": "text.html.markdown meta.paragraph.markdown markup.italic.markdown punctuation.definition.italic.markdown", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "words", - "t": "text.html.markdown meta.paragraph.markdown markup.italic.markdown", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "_", - "t": "text.html.markdown meta.paragraph.markdown markup.italic.markdown punctuation.definition.italic.markdown", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "are ignored.", + "c": "in_words_are ignored.", "t": "text.html.markdown meta.paragraph.markdown", "r": { "dark_plus": "default: #D4D4D4", diff --git a/extensions/markdown/yarn.lock b/extensions/markdown/yarn.lock index 4baed92f526..5e1e4c7a48b 100644 --- a/extensions/markdown/yarn.lock +++ b/extensions/markdown/yarn.lock @@ -162,9 +162,9 @@ vscode-extension-telemetry@^0.0.8: applicationinsights "0.18.0" winreg "1.2.3" -vscode-nls@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" winreg@1.2.3: version "1.2.3" diff --git a/extensions/merge-conflict/package.json b/extensions/merge-conflict/package.json index 1a0f35f9b34..d7a0031df97 100644 --- a/extensions/merge-conflict/package.json +++ b/extensions/merge-conflict/package.json @@ -100,7 +100,7 @@ }, "dependencies": { "vscode-extension-telemetry": "0.0.8", - "vscode-nls": "^2.0.2" + "vscode-nls": "^3.1.2" }, "devDependencies": { "@types/node": "8.0.33" diff --git a/extensions/merge-conflict/src/extension.ts b/extensions/merge-conflict/src/extension.ts index 3168d67ab42..33c996955db 100644 --- a/extensions/merge-conflict/src/extension.ts +++ b/extensions/merge-conflict/src/extension.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vscode-nls'; -nls.config(process.env.VSCODE_NLS_CONFIG)(); import * as vscode from 'vscode'; import MergeConflictServices from './services'; diff --git a/extensions/merge-conflict/yarn.lock b/extensions/merge-conflict/yarn.lock index feea62445f1..bd0aecc3553 100644 --- a/extensions/merge-conflict/yarn.lock +++ b/extensions/merge-conflict/yarn.lock @@ -17,9 +17,9 @@ vscode-extension-telemetry@0.0.8: applicationinsights "0.18.0" winreg "1.2.3" -vscode-nls@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" winreg@1.2.3: version "1.2.3" diff --git a/extensions/npm/package.json b/extensions/npm/package.json index 5810b4ee483..dba83356e28 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -15,7 +15,7 @@ "watch": "gulp watch-extension:npm" }, "dependencies": { - "vscode-nls": "^2.0.2" + "vscode-nls": "^3.1.2" }, "devDependencies": { "@types/node": "7.0.43" diff --git a/extensions/npm/src/main.ts b/extensions/npm/src/main.ts index e18287872db..17d2c47b1c9 100644 --- a/extensions/npm/src/main.ts +++ b/extensions/npm/src/main.ts @@ -9,7 +9,7 @@ import * as path from 'path'; import * as fs from 'fs'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; -let localize = nls.loadMessageBundle(); +const localize = nls.loadMessageBundle(); type AutoDetect = 'on' | 'off'; let taskProvider: vscode.Disposable | undefined; diff --git a/extensions/npm/yarn.lock b/extensions/npm/yarn.lock index cde3e475ca8..e2fc7ae342e 100644 --- a/extensions/npm/yarn.lock +++ b/extensions/npm/yarn.lock @@ -6,6 +6,6 @@ version "7.0.43" resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c" -vscode-nls@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" diff --git a/extensions/php/package.json b/extensions/php/package.json index fb5758ff8bf..bfe9fcaa5c5 100644 --- a/extensions/php/package.json +++ b/extensions/php/package.json @@ -10,7 +10,7 @@ ], "main": "./out/phpMain", "dependencies": { - "vscode-nls": "^1.0.4" + "vscode-nls": "^3.1.2" }, "contributes": { "languages": [ diff --git a/extensions/php/src/phpMain.ts b/extensions/php/src/phpMain.ts index 64eda6c7809..060f7587c18 100644 --- a/extensions/php/src/phpMain.ts +++ b/extensions/php/src/phpMain.ts @@ -5,8 +5,6 @@ 'use strict'; import * as vscode from 'vscode'; -import * as nls from 'vscode-nls'; -nls.config({ locale: vscode.env.language }); import PHPCompletionItemProvider from './features/completionItemProvider'; import PHPHoverProvider from './features/hoverProvider'; diff --git a/extensions/php/yarn.lock b/extensions/php/yarn.lock index fdd1d36b518..e2fc7ae342e 100644 --- a/extensions/php/yarn.lock +++ b/extensions/php/yarn.lock @@ -6,6 +6,6 @@ version "7.0.43" resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c" -vscode-nls@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-1.0.7.tgz#298c01fce87802c644c0a15ef526a33c62c0d58e" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" diff --git a/extensions/typescript/package.json b/extensions/typescript/package.json index 6e182cef3d1..27656dec922 100644 --- a/extensions/typescript/package.json +++ b/extensions/typescript/package.json @@ -14,7 +14,7 @@ "dependencies": { "semver": "4.3.6", "vscode-extension-telemetry": "^0.0.8", - "vscode-nls": "^2.0.2" + "vscode-nls": "^3.1.2" }, "devDependencies": { "@types/node": "8.0.33", diff --git a/extensions/typescript/src/extension.ts b/extensions/typescript/src/extension.ts index 5116fa9af72..73604a21c3f 100644 --- a/extensions/typescript/src/extension.ts +++ b/extensions/typescript/src/extension.ts @@ -5,12 +5,6 @@ import * as vscode from 'vscode'; -// This must be the first statement otherwise modules might got loaded with -// the wrong locale. -import * as nls from 'vscode-nls'; -nls.config({ locale: vscode.env.language }); -nls.loadMessageBundle(); - import { CommandManager } from './utils/commandManager'; import TypeScriptServiceClientHost from './typeScriptServiceClientHost'; import * as commands from './commands'; diff --git a/extensions/typescript/src/features/refactorProvider.ts b/extensions/typescript/src/features/refactorProvider.ts index 088d8879059..c6310dcf0d9 100644 --- a/extensions/typescript/src/features/refactorProvider.ts +++ b/extensions/typescript/src/features/refactorProvider.ts @@ -96,6 +96,9 @@ class SelectRefactorCommand implements Command { } export default class TypeScriptRefactorProvider implements vscode.CodeActionProvider { + private static readonly extractFunctionKind = vscode.CodeActionKind.RefactorExtract.append('function'); + private static readonly extractConstantKind = vscode.CodeActionKind.RefactorExtract.append('constant'); + constructor( private readonly client: ITypeScriptServiceClient, formattingOptionsManager: FormattingOptionsManager, @@ -171,7 +174,9 @@ export default class TypeScriptRefactorProvider implements vscode.CodeActionProv private static getKind(refactor: Proto.RefactorActionInfo) { if (refactor.name.startsWith('function_')) { - return vscode.CodeActionKind.RefactorExtract.append('function'); + return TypeScriptRefactorProvider.extractFunctionKind; + } else if (refactor.name.startsWith('constant_')) { + return TypeScriptRefactorProvider.extractConstantKind; } return vscode.CodeActionKind.Refactor; } diff --git a/extensions/typescript/src/utils/previewer.ts b/extensions/typescript/src/utils/previewer.ts index 22e39cf9079..647ae3bf91b 100644 --- a/extensions/typescript/src/utils/previewer.ts +++ b/extensions/typescript/src/utils/previewer.ts @@ -27,7 +27,7 @@ function getTagBodyText(tag: Proto.JSDocTagInfo): string | undefined { function getTagDocumentation(tag: Proto.JSDocTagInfo): string | undefined { switch (tag.name) { case 'param': - const body = (tag.text || '').split(/^(\w+)\s*/); + const body = (tag.text || '').split(/^([\w\.]+)\s*/); if (body && body.length === 3) { const param = body[1]; const doc = body[2]; diff --git a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json b/extensions/typescript/syntaxes/TypeScript.tmLanguage.json index cc81558cfc2..b76d98425eb 100644 --- a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json +++ b/extensions/typescript/syntaxes/TypeScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/8b44958a27860957872cc6f628d843a71686af63", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/51323af933792ffbb9a088fd500536122be38b59", "name": "TypeScript", "scopeName": "source.ts", "fileTypes": [ @@ -286,7 +286,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.ts", - "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.ts entity.name.function.ts" @@ -348,7 +348,7 @@ "patterns": [ { "name": "meta.object-binding-pattern-variable.ts", - "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.ts" @@ -747,7 +747,7 @@ }, { "name": "meta.definition.property.ts entity.name.function.ts", - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))" }, { "name": "meta.definition.property.ts variable.object.property.ts", @@ -1878,7 +1878,7 @@ }, "after-operator-block-as-object-literal": { "name": "meta.objectliteral.ts", - "begin": "(?<=[=(,\\[?+!]|await|return|yield|throw|in|of|typeof|&&|\\|\\||\\*)\\s*(\\{)", + "begin": "(?<=[=(,\\[?+!]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)", "beginCaptures": { "1": { "name": "punctuation.definition.block.ts" @@ -2051,13 +2051,13 @@ ] }, "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\)))*\\>)*>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\)))*\\>)*>\\s*)?\\()", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "name": "meta.function-call.ts", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\)))*\\>)*>\\s*)?\\()", + "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "include": "#literal" @@ -2163,7 +2163,7 @@ "patterns": [ { "name": "cast.expr.ts", - "begin": "(?:(?<=return|throw|yield|await|default|[=(,:>*?\\&\\|\\^]|[^_$[:alnum:]](?:\\+\\+|\\-\\-)|[^\\+]\\+|[^\\-]\\-))\\s*(<)(?!*?\\&\\|\\^]|[^_$[:alnum:]](?:\\+\\+|\\-\\-)|[^\\+]\\+|[^\\-]\\-))\\s*(<)(?!|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "begin": "(?<=[=(:,\\[?+!]|^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", "beginCaptures": { "1": { "name": "punctuation.definition.string.begin.ts" diff --git a/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json b/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json index 5da35c8fe7f..c8bb27a8610 100644 --- a/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json +++ b/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/8b44958a27860957872cc6f628d843a71686af63", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/51323af933792ffbb9a088fd500536122be38b59", "name": "TypeScriptReact", "scopeName": "source.tsx", "fileTypes": [ @@ -289,7 +289,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.tsx", - "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.tsx entity.name.function.tsx" @@ -351,7 +351,7 @@ "patterns": [ { "name": "meta.object-binding-pattern-variable.tsx", - "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.tsx" @@ -750,7 +750,7 @@ }, { "name": "meta.definition.property.tsx entity.name.function.tsx", - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=(\\?\\s*)?\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))" }, { "name": "meta.definition.property.tsx variable.object.property.tsx", @@ -1881,7 +1881,7 @@ }, "after-operator-block-as-object-literal": { "name": "meta.objectliteral.tsx", - "begin": "(?<=[=(,\\[?+!]|await|return|yield|throw|in|of|typeof|&&|\\|\\||\\*)\\s*(\\{)", + "begin": "(?<=[=(,\\[?+!]|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^yield|[^\\._$[:alnum:]]yield|^throw|[^\\._$[:alnum:]]throw|^in|[^\\._$[:alnum:]]in|^of|[^\\._$[:alnum:]]of|^typeof|[^\\._$[:alnum:]]typeof|&&|\\|\\||\\*)\\s*(\\{)", "beginCaptures": { "1": { "name": "punctuation.definition.block.tsx" @@ -2054,13 +2054,13 @@ ] }, "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\)))*\\>)*>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\)))*\\>)*>\\s*)?\\()", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "name": "meta.function-call.tsx", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\)))*\\>)*>\\s*)?\\()", + "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", "patterns": [ { "include": "#literal" @@ -3292,7 +3292,7 @@ "patterns": [ { "name": "string.regexp.tsx", - "begin": "(?<=[=(:,\\[?+!]|return|case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "begin": "(?<=[=(:,\\[?+!]|^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", "beginCaptures": { "1": { "name": "punctuation.definition.string.begin.tsx" @@ -4038,7 +4038,7 @@ ] }, "jsx-tag-without-attributes-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", + "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", "patterns": [ { @@ -4086,7 +4086,7 @@ ] }, "jsx-tag-in-expression": { - "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", "end": "(/>)|(?:())", "endCaptures": { "0": { diff --git a/extensions/typescript/yarn.lock b/extensions/typescript/yarn.lock index eb4fd8e25fd..5f6bdee5635 100644 --- a/extensions/typescript/yarn.lock +++ b/extensions/typescript/yarn.lock @@ -25,9 +25,9 @@ vscode-extension-telemetry@^0.0.8: applicationinsights "0.18.0" winreg "1.2.3" -vscode-nls@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da" +vscode-nls@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.1.2.tgz#c1b63f4338ac49c852267633dd99717916424a74" winreg@1.2.3: version "1.2.3" diff --git a/i18n/chs/extensions/typescript/out/features/quickFixProvider.i18n.json b/i18n/chs/extensions/typescript/out/features/quickFixProvider.i18n.json new file mode 100644 index 00000000000..dabfe74346b --- /dev/null +++ b/i18n/chs/extensions/typescript/out/features/quickFixProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fixAllInFileLabel": "{0} (修复文件中所有问题)" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json index b2f32f3d15b..7633e13d1a4 100644 --- a/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -40,9 +40,9 @@ "wordWrapColumn": "在 \"editor.wordWrap\" 为 \"wordWrapColumn\" 或 \"bounded\" 时控制编辑器列的换行。", "wrappingIndent": "控制折行的缩进。可以是“none”、“same”或“indent”。", "mouseWheelScrollSensitivity": "要对鼠标滚轮滚动事件的 \"deltaX\" 和 \"deltaY\" 使用的乘数 ", - "multiCursorModifier.ctrlCmd": "映射到“Control”(Windows 和 Linux)或“Command”(OSX)。", - "multiCursorModifier.alt": "映射到“Alt”(Windows 和 Linux)或“Option”(OSX)。", - "multiCursorModifier": "用鼠标添加多个光标时使用的修改键。\"ctrlCmd\" 会映射为 \"Ctrl\" (Windows 和 Linux) 或 \"Command\" (OSX)。“转到定义”和“打开链接”功能所需的动作将会相应调整,不与多光标修改键冲突。", + "multiCursorModifier.ctrlCmd": "映射为 \"Ctrl\" (Windows 和 Linux) 或 \"Command\" (macOS)", + "multiCursorModifier.alt": "映射为 \"Alt\" (Windows 和 Linux) 或 \"Option\" (macOS)", + "multiCursorModifier": "在通过鼠标添加多个光标时使用的修改键。\"ctrlCmd\" 会映射为 \"Ctrl\" (Windows 和 Linux) 或 \"Command\" (macOS)。“转到定义”和“打开链接”功能所需的鼠标动作将会相应调整,不与多光标修改键冲突。", "quickSuggestions.strings": "在字符串内启用快速建议。", "quickSuggestions.comments": "在注释内启用快速建议。", "quickSuggestions.other": "在字符串和注释外启用快速建议。", diff --git a/i18n/chs/src/vs/platform/environment/node/argv.i18n.json b/i18n/chs/src/vs/platform/environment/node/argv.i18n.json index 30d7fd225a2..2f9194ac09c 100644 --- a/i18n/chs/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/chs/src/vs/platform/environment/node/argv.i18n.json @@ -31,6 +31,7 @@ "inspect-brk-extensions": "允许在扩展主机在启动后暂停时进行扩展的调试与分析。检查开发人员工具可获取连接 URI。", "disableGPU": "禁用 GPU 硬件加速。", "uploadLogs": "将当前会话的日志上传到安全端点。", + "issue": "报告问题。", "usage": "使用情况", "options": "选项", "paths": "路径", diff --git a/i18n/chs/src/vs/platform/list/browser/listService.i18n.json b/i18n/chs/src/vs/platform/list/browser/listService.i18n.json new file mode 100644 index 00000000000..6abcaadf646 --- /dev/null +++ b/i18n/chs/src/vs/platform/list/browser/listService.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "workbenchConfigurationTitle": "工作台", + "multiSelectModifier.ctrlCmd": "映射为 \"Ctrl\" (Windows 和 Linux) 或 \"Command\" (macOS)", + "multiSelectModifier.alt": "映射为 \"Alt\" (Windows 和 Linux) 或 \"Option\" (macOS)", + "multiSelectModifier": "在通过鼠标添加条目到多选项中时使用的修改键 (例如在支持此项操作的树或列表中)。\"ctrlCmd\" 会映射为 \"Ctrl\" (Windows 和 Linux) 或 \"Command\" (macOS)。“打开到侧边”功能所需的鼠标动作 (若可用) 将会相应调整,不与多选修改键冲突。" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json b/i18n/chs/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json new file mode 100644 index 00000000000..103d823dcdd --- /dev/null +++ b/i18n/chs/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "localizations 必须为数组", + "requirestring": "属性“{0}”是必要属性,其类型必须是 \"string\"", + "optstring": "属性“{0}”可以省略,否则其类型必须是 \"string\"", + "vscode.extension.contributes.localizations": "向编辑器提供本地化内容", + "vscode.extension.contributes.localizations.languageId": "显示字符串翻译的目标语言 ID。", + "vscode.extension.contributes.localizations.languageName": "显示字符串翻译的目标语言名称。", + "vscode.extension.contributes.localizations.translations": "文件夹的相对路径,其中包含了提供语言的所有翻译文件。" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index d2749a69222..139236ab4a9 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -16,7 +16,7 @@ "file": "文件", "close": "关闭", "closeOthers": "关闭其他", - "closeRight": "关闭到右侧", + "closeRight": "关闭右侧", "closeAllUnmodified": "关闭未更改", "closeAll": "全部关闭", "keepOpen": "保持打开状态", diff --git a/i18n/chs/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/chs/src/vs/workbench/electron-browser/actions.i18n.json index f941d8a0956..102013aa46a 100644 --- a/i18n/chs/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/chs/src/vs/workbench/electron-browser/actions.i18n.json @@ -29,6 +29,7 @@ "openRecent": "打开最近的文件…", "quickOpenRecent": "快速打开最近的文件…", "closeMessages": "关闭通知消息", + "openIssueReporter": "打开问题报告程序", "reportIssueInEnglish": "使用英文报告问题", "reportPerformanceIssue": "报告性能问题", "keybindingsReference": "键盘快捷方式参考", diff --git a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index fd6211c4e06..83ae4f6295a 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -19,8 +19,8 @@ "vscode.extension.contributes.debuggers.configurationAttributes": "用于验证 \"launch.json\" 的 JSON 架构配置。", "vscode.extension.contributes.debuggers.windows": "Windows 特定的设置。", "vscode.extension.contributes.debuggers.windows.runtime": "用于 Windows 的运行时。", - "vscode.extension.contributes.debuggers.osx": "OS X 特定的设置。", - "vscode.extension.contributes.debuggers.osx.runtime": "用于 OSX 的运行时。", + "vscode.extension.contributes.debuggers.osx": "macOS 特定的设置。", + "vscode.extension.contributes.debuggers.osx.runtime": "用于 macOS 的运行时。", "vscode.extension.contributes.debuggers.linux": "Linux 特定的设置。", "vscode.extension.contributes.debuggers.linux.runtime": "用于 Linux 的运行时。", "vscode.extension.contributes.breakpoints": "添加断点。", diff --git a/i18n/chs/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json index b75ed7a9817..e22eff45b62 100644 --- a/i18n/chs/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json @@ -14,7 +14,6 @@ "findInFiles": "在文件中查找", "openAnythingHandlerDescription": "转到文件", "openSymbolDescriptionNormal": "转到工作区中的符号", - "searchOutputChannelTitle": "搜索", "searchConfigurationTitle": "搜索", "exclude": "配置 glob 模式以在搜索中排除文件和文件夹。从 files.exclude 设置中继承所有 glob 模式。", "exclude.boolean": "匹配文件路径所依据的 glob 模式。设置为 true 或 false 可启用或禁用该模式。", diff --git a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index 199139684a9..40bc57dc321 100644 --- a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -13,6 +13,7 @@ "terminal.integrated.shellArgs.osx": "在 OS X 终端上时要使用的命令行参数。", "terminal.integrated.shell.windows": "终端在 Windows 使用的 shell 路径。使用随 Windows 一起提供的 shell (cmd、PowerShell 或 Bash on Ubuntu) 时。", "terminal.integrated.shellArgs.windows": "在 Windows 终端上时使用的命令行参数。", + "terminal.integrated.macOptionIsMeta": "在终端中,使用 Option 键作为 Meta 键。(macOS)", "terminal.integrated.rightClickCopyPaste": "设置后,在终端内右键单击时,这将阻止显示上下文菜单,相反,它将在有选项时进行复制,并且在没有选项时进行粘贴。", "terminal.integrated.copyOnSelection": "设置后,终端中选中的文字将被复制到剪贴板。", "terminal.integrated.fontFamily": "控制终端的字体系列,这在编辑器中是默认的。fontFamily 的值。", diff --git a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 6db35403434..916f76ed987 100644 --- a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -12,7 +12,7 @@ "workbench.action.terminal.selectAll": "全选", "workbench.action.terminal.deleteWordLeft": "删除左侧的字符", "workbench.action.terminal.deleteWordRight": "删除右侧的字符", - "workbench.action.terminal.enterLineNavigationMode": "进入按行导航模式", + "workbench.action.terminal.enterLineNavigationMode": "进入屏幕阅读器导航模式", "workbench.action.terminal.new": "新建集成终端", "workbench.action.terminal.new.short": "新的终端", "workbench.action.terminal.newWorkspacePlaceholder": "选择当前工作目录新建终端", diff --git a/i18n/cht/extensions/git/package.i18n.json b/i18n/cht/extensions/git/package.i18n.json index 46908731864..5f9e86aed6c 100644 --- a/i18n/cht/extensions/git/package.i18n.json +++ b/i18n/cht/extensions/git/package.i18n.json @@ -60,6 +60,7 @@ "config.enableLongCommitWarning": "是否發出長認可訊息的警告", "config.confirmSync": "請先確認再同步處理 GIT 存放庫", "config.countBadge": "控制 git 徽章計數器。[全部] 會計算所有變更。[已追蹤] 只會計算追蹤的變更。[關閉] 會將其關閉。", + "config.checkoutType": "控制在執行 [簽出至...] 時,會列出哪些類型的分支。[全部] 會顯示所有參考,[本機] 只會顯示本機分支,[標籤] 只會顯示標籤,以及 [遠端] 只會顯示遠端分支。", "config.ignoreLegacyWarning": "略過舊的 Git 警告", "config.ignoreMissingGitWarning": "忽略遺漏 Git 時的警告", "config.ignoreLimitWarning": "當儲存庫中有過多變更時,略過警告。", diff --git a/i18n/cht/extensions/typescript/out/features/quickFixProvider.i18n.json b/i18n/cht/extensions/typescript/out/features/quickFixProvider.i18n.json new file mode 100644 index 00000000000..b2cbb689282 --- /dev/null +++ b/i18n/cht/extensions/typescript/out/features/quickFixProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fixAllInFileLabel": "{0} (檔案中修復全部)" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json index 1cd1bd85b24..48d79ffbdd2 100644 --- a/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -40,9 +40,9 @@ "wordWrapColumn": "當 `editor.wordWrap` 為 [wordWrapColumn] 或 [bounded] 時,控制編輯器中的資料行換行。", "wrappingIndent": "控制換行的縮排。可以是 [無]、[相同] 或 [縮排]。", "mouseWheelScrollSensitivity": "滑鼠滾輪捲動事件的 'deltaX' 與 'deltaY' 所使用的乘數", - "multiCursorModifier.ctrlCmd": "對應Windows和Linux的'Control'與對應OSX的'Command'", - "multiCursorModifier.alt": "對應Windows和Linux的'Alt'與對應OSX的'Option'", - "multiCursorModifier": "用於新增多個滑鼠游標的修改程式。`ctrlCmd` 會對應到 Windows 及 Linux 上的 `Control` 以及 OSX 上的 `Command`。[移至定義] 及 [開啟連結] 滑鼠手勢將會適應以避免和 multicursor 修改程式衝突。", + "multiCursorModifier.ctrlCmd": "對應 Windows 和 Linux 的 `Control` 與對應 macOS 的 `Command`", + "multiCursorModifier.alt": "對應 Windows 和 Linux 的 `Alt` 與對應 macOS 的 `Option`", + "multiCursorModifier": "用於新增多個滑鼠游標的修改。 `ctrlCmd` 會對應到 Windows 和 Linux 上的 `Control` 以及 macOS 上的 `Command`。 [移至定義] 及 [開啟連結] 滑鼠手勢將會適應以避免和 multicursor 修改衝突。", "quickSuggestions.strings": "允許在字串內顯示即時建議。", "quickSuggestions.comments": "允許在註解中顯示即時建議。", "quickSuggestions.other": "允許在字串與註解以外之處顯示即時建議。", diff --git a/i18n/cht/src/vs/editor/contrib/gotoError/gotoError.i18n.json b/i18n/cht/src/vs/editor/contrib/gotoError/gotoError.i18n.json index c569d86bd1a..fcb4645d048 100644 --- a/i18n/cht/src/vs/editor/contrib/gotoError/gotoError.i18n.json +++ b/i18n/cht/src/vs/editor/contrib/gotoError/gotoError.i18n.json @@ -5,6 +5,8 @@ // Do not edit this file. It is machine generated. { "title.wo_source": "({0}/{1})", + "markerAction.next.label": "移至下一個問題 (錯誤, 警告, 資訊)", + "markerAction.previous.label": "移至上一個問題 (錯誤, 警告, 資訊)", "editorMarkerNavigationError": "編輯器標記導覽小工具錯誤的色彩。", "editorMarkerNavigationWarning": "編輯器標記導覽小工具警告的色彩。", "editorMarkerNavigationInfo": "編輯器標記導覽小工具資訊的色彩", diff --git a/i18n/cht/src/vs/platform/environment/node/argv.i18n.json b/i18n/cht/src/vs/platform/environment/node/argv.i18n.json index 4e6ecb355e3..0026dc0d184 100644 --- a/i18n/cht/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/cht/src/vs/platform/environment/node/argv.i18n.json @@ -31,6 +31,7 @@ "inspect-brk-extensions": "允許對擴展主機在啟動後暫停擴充功能進行除錯和分析。檢查開發工具中的連接 uri。", "disableGPU": "停用 GPU 硬體加速。", "uploadLogs": "上傳目前的工作階段紀錄至安全的端點。", + "issue": "回報1個問題", "usage": "使用方式", "options": "選項", "paths": "路徑", diff --git a/i18n/cht/src/vs/platform/list/browser/listService.i18n.json b/i18n/cht/src/vs/platform/list/browser/listService.i18n.json new file mode 100644 index 00000000000..14d649f76d2 --- /dev/null +++ b/i18n/cht/src/vs/platform/list/browser/listService.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "workbenchConfigurationTitle": "工作台", + "multiSelectModifier.ctrlCmd": "對應Windows和Linux的'Control'與對應 macOS 的'Command'。", + "multiSelectModifier.alt": "對應Windows和Linux的'Alt'與對應macOS的'Option'。", + "multiSelectModifier": "用於新增項目至滑鼠多選的修改 (例如在樹狀及列表支援下)。 `ctrlCmd` 會對應到 Windows 和 Linux 上的 `Control` 以及 macOS 上的 `Command`。 [在側邊開啟] 滑鼠手勢若支援,將會適應以避免和 multiselect 修改衝突。" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json b/i18n/cht/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json new file mode 100644 index 00000000000..1127905705c --- /dev/null +++ b/i18n/cht/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "在地化資料必須為陣列", + "requirestring": "屬性 '{0}' 為強制項目且必須屬於 `string` 類型", + "optstring": "屬性 `{0}` 可以省略或必須屬於 `string` 類型", + "vscode.extension.contributes.localizations": "提供在地化服務給編輯者", + "vscode.extension.contributes.localizations.languageId": "顯示已翻譯字串的語言 Id", + "vscode.extension.contributes.localizations.languageName": "顯示已翻譯字串的語言名稱", + "vscode.extension.contributes.localizations.translations": "檔案的相對路徑,其中該資料包含夾貢獻語言所有翻譯檔案。" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/api/node/extHostTreeViews.i18n.json b/i18n/cht/src/vs/workbench/api/node/extHostTreeViews.i18n.json index 2df7e9c33f5..1e554271b86 100644 --- a/i18n/cht/src/vs/workbench/api/node/extHostTreeViews.i18n.json +++ b/i18n/cht/src/vs/workbench/api/node/extHostTreeViews.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "treeView.notRegistered": "未註冊識別碼為 '{0}' 的樹狀檢視。" + "treeView.notRegistered": "未註冊識別碼為 '{0}' 的樹狀檢視。", + "treeView.duplicateElement": "識別碼為 {0} 的元件已被註冊" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/actions/toggleSidebarPosition.i18n.json b/i18n/cht/src/vs/workbench/browser/actions/toggleSidebarPosition.i18n.json index 16f408d9bec..ce860535636 100644 --- a/i18n/cht/src/vs/workbench/browser/actions/toggleSidebarPosition.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/actions/toggleSidebarPosition.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "toggleSidebarPosition": "切換提要欄位位置", "view": "檢視" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 9dbae940daf..3e12d7d30b8 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -20,6 +20,7 @@ "closeAllUnmodified": "關閉未變更的檔案", "closeAll": "全部關閉", "keepOpen": "保持開啟", + "toggleInlineView": "切換至內嵌檢視", "showOpenedEditors": "顯示開啟的編輯器", "keepEditor": "保留編輯器", "closeEditorsInGroup": "關閉群組中的所有編輯器", diff --git a/i18n/cht/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/cht/src/vs/workbench/electron-browser/actions.i18n.json index c6e5b092bd1..8b7032221cc 100644 --- a/i18n/cht/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/cht/src/vs/workbench/electron-browser/actions.i18n.json @@ -29,6 +29,7 @@ "openRecent": "開啟最近使用的檔案...", "quickOpenRecent": "快速開啟最近使用的檔案...", "closeMessages": "關閉通知訊息", + "openIssueReporter": "公開問題回報者", "reportIssueInEnglish": "回報問題", "reportPerformanceIssue": "回報效能問題", "keybindingsReference": "鍵盤快速鍵參考", diff --git a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 19f502a82ef..7bccdf99f80 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -19,8 +19,8 @@ "vscode.extension.contributes.debuggers.configurationAttributes": "JSON 結構描述組態,用於驗證 'launch.json'。", "vscode.extension.contributes.debuggers.windows": "Windows 特定設定。", "vscode.extension.contributes.debuggers.windows.runtime": "用於 Windows 的執行階段。", - "vscode.extension.contributes.debuggers.osx": "OS X 特定設定。", - "vscode.extension.contributes.debuggers.osx.runtime": "用於 OSX 的執行階段。", + "vscode.extension.contributes.debuggers.osx": "macOS 特定設定。", + "vscode.extension.contributes.debuggers.osx.runtime": "用於 macOS 的執行階段。", "vscode.extension.contributes.debuggers.linux": "Linux 特定設定。", "vscode.extension.contributes.debuggers.linux.runtime": "用於 Linux 的執行階段。", "vscode.extension.contributes.breakpoints": "提供中斷點。", diff --git a/i18n/cht/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/cht/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index ac9779dde41..f7439bf6054 100644 --- a/i18n/cht/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -13,6 +13,8 @@ "reallyRecommendedExtensionPack": "建議對此檔案類型使用 '{0}' 延伸模組套件。", "showRecommendations": "顯示建議", "install": "安裝", + "showLanguageExtensions": "市集有 '.{0}' 個文件的擴充功能可以提供協助", + "searchMarketplace": "搜尋市集", "workspaceRecommended": "此工作區具有擴充功能建議。", "installAll": "全部安裝", "ignoreExtensionRecommendations": "是否略過所有的延伸模組建議?", diff --git a/i18n/cht/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json b/i18n/cht/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json index 44a55467fbf..adf7f4b2563 100644 --- a/i18n/cht/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json @@ -4,6 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "installingVSIXExtension": "從 VSIX 安裝擴充功能...", + "installingMarketPlaceExtension": "從市集安裝擴充功能...", + "uninstallingExtension": "解除安裝擴充功能...", "enableDependeciesConfirmation": "啟用 '{0}' 也會啟用其相依性。仍要繼續嗎?", "enable": "是", "doNotEnable": "否", diff --git a/i18n/cht/src/vs/workbench/parts/feedback/electron-browser/feedback.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/feedback/electron-browser/feedback.contribution.i18n.json index 37b9d5384a5..6a2ef8c5498 100644 --- a/i18n/cht/src/vs/workbench/parts/feedback/electron-browser/feedback.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/feedback/electron-browser/feedback.contribution.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "workbenchConfigurationTitle": "工作台" + "workbenchConfigurationTitle": "工作台", + "feedbackVisibility": "控制工作台底部狀態列中的 Twitter 回饋 (笑臉) 的可見度。" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/feedback/electron-browser/feedback.i18n.json b/i18n/cht/src/vs/workbench/parts/feedback/electron-browser/feedback.i18n.json index 3ae75fe7ef4..50c2a802497 100644 --- a/i18n/cht/src/vs/workbench/parts/feedback/electron-browser/feedback.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/feedback/electron-browser/feedback.i18n.json @@ -16,6 +16,7 @@ "request a missing feature": "要求遺漏的功能", "tell us why?": "請告訴我們原因", "commentsHeader": "註解", + "showFeedback": "顯示狀態列中的回饋笑臉", "tweet": "推文", "character left": "剩餘字元", "characters left": "剩餘字元", diff --git a/i18n/cht/src/vs/workbench/parts/files/electron-browser/fileActions.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/files/electron-browser/fileActions.contribution.i18n.json index 8b0fa7e726f..fe4146d1ad2 100644 --- a/i18n/cht/src/vs/workbench/parts/files/electron-browser/fileActions.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/files/electron-browser/fileActions.contribution.i18n.json @@ -22,7 +22,9 @@ "copyPath": "複製路徑", "saveAll": "全部儲存", "compareWithSaved": "與已儲存的檔案比較", + "compareWithSelected": "與選取的比較", "compareSource": "選取用以比較", + "compareSelected": "比較已選取", "close": "關閉", "closeOthers": "關閉其他", "closeUnmodified": "關閉未變更的檔案", diff --git a/i18n/cht/src/vs/workbench/parts/files/electron-browser/fileActions.i18n.json b/i18n/cht/src/vs/workbench/parts/files/electron-browser/fileActions.i18n.json index e173bdcc79b..3cf9c4c6208 100644 --- a/i18n/cht/src/vs/workbench/parts/files/electron-browser/fileActions.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/files/electron-browser/fileActions.i18n.json @@ -23,11 +23,13 @@ "dirtyMessageFolderDelete": "您要刪除的資料夾中 {0} 個檔案有未儲存的變更。要繼續嗎?", "dirtyMessageFileDelete": "您要刪除的檔案有未儲存的變更。要繼續嗎?", "dirtyWarning": "如果您不儲存變更,這些變更將會遺失。", + "confirmMoveTrashMessageMultiple": "確定要刪除以下 {0} 個檔案嗎?", "confirmMoveTrashMessageFolder": "您確定要刪除 '{0}' 及其內容嗎?", "confirmMoveTrashMessageFile": "您確定要刪除 '{0}' 嗎?", "undoBin": "您可以從資源回收筒還原。", "undoTrash": "您可以從垃圾筒還原。", "doNotAskAgain": "不要再詢問我", + "confirmDeleteMessageMultiple": "確定要永久地刪除以下 {0} 個檔案嗎?", "confirmDeleteMessageFolder": "您確定要永久刪除 '{0}' 和其中的內容嗎?", "confirmDeleteMessageFile": "您確定要永久刪除 '{0}' 嗎?", "irreversible": "此動作無法回復!", diff --git a/i18n/cht/src/vs/workbench/parts/files/electron-browser/files.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/files/electron-browser/files.contribution.i18n.json index 28e38af66ab..1d9b4ba3736 100644 --- a/i18n/cht/src/vs/workbench/parts/files/electron-browser/files.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/files/electron-browser/files.contribution.i18n.json @@ -36,6 +36,7 @@ "editorConfigurationTitle": "編輯器", "formatOnSave": "在儲存時設定檔案格式。格式器必須處於可用狀態、檔案不得自動儲存,且編輯器不得關機。", "explorerConfigurationTitle": "檔案總管", + "openEditorsVisible": "[開放式編輯器] 窗格中顯示的編輯器數目。", "autoReveal": "控制總管是否在開啟檔案時自動加以顯示及選取。", "enableDragAndDrop": "控制總管是否應該允許透過拖放功能移動檔案和資料夾。", "confirmDragAndDrop": "控制總管是否須要求確認,以透過拖放來移動檔案和資料夾。", diff --git a/i18n/cht/src/vs/workbench/parts/markers/common/messages.i18n.json b/i18n/cht/src/vs/workbench/parts/markers/common/messages.i18n.json index c754d02f873..8f07ff5d3b3 100644 --- a/i18n/cht/src/vs/workbench/parts/markers/common/messages.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/markers/common/messages.i18n.json @@ -5,6 +5,8 @@ // Do not edit this file. It is machine generated. { "viewCategory": "檢視", + "problems.view.toggle.label": "切換至問題(錯誤, 警告, 資訊)", + "problems.view.focus.label": "聚焦於問題(錯誤, 警告, 資訊)", "problems.panel.configuration.title": "[問題] 檢視", "problems.panel.configuration.autoreveal": "控制 [問題] 檢視是否應自動在開啟檔案時加以顯示", "markers.panel.title.problems": "問題", diff --git a/i18n/cht/src/vs/workbench/parts/preferences/browser/keybindingsEditor.i18n.json b/i18n/cht/src/vs/workbench/parts/preferences/browser/keybindingsEditor.i18n.json index 0db1b09d33b..5c81c87f361 100644 --- a/i18n/cht/src/vs/workbench/parts/preferences/browser/keybindingsEditor.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/preferences/browser/keybindingsEditor.i18n.json @@ -17,6 +17,7 @@ "resetLabel": "重設按鍵繫結關係", "showConflictsLabel": "顯示衝突", "copyLabel": "複製", + "copyCommandLabel": "複製命令", "error": "編輯按鍵繫結關係時發生錯誤 '{0}'。請開啟 'keybindings.json' 檔案加以檢查。", "command": "Command", "keybinding": "按鍵繫結關係", diff --git a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json index 1b98a0d9db9..c35a778205c 100644 --- a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json @@ -11,6 +11,8 @@ "oneSettingFound": "1 項相符設定", "settingsFound": "{0} 項相符設定", "totalSettingsMessage": "共 {0} 項設定", + "nlpResult": "自然語言結果", + "filterResult": "篩選結果", "defaultSettings": "預設設定", "defaultFolderSettings": "預設資料夾設定", "defaultEditorReadonly": "在右方編輯器中編輯以覆寫預設。", diff --git a/i18n/cht/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json index 1244f50ad8c..fa44f03a99c 100644 --- a/i18n/cht/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json @@ -14,7 +14,6 @@ "findInFiles": "在檔案中尋找", "openAnythingHandlerDescription": "前往檔案", "openSymbolDescriptionNormal": "前往工作區中的符號", - "searchOutputChannelTitle": "搜尋", "searchConfigurationTitle": "搜尋", "exclude": "設定 Glob 模式,以排除不要搜尋的檔案及資料夾。請從 file.exclude 設定繼承所有的 Glob 模式。", "exclude.boolean": "要符合檔案路徑的 Glob 模式。設為 True 或 False 可啟用或停用模式。", diff --git a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index d824ac236e9..11d4003e254 100644 --- a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -13,6 +13,7 @@ "terminal.integrated.shellArgs.osx": "在 OS X 終端機要使用的命令列引數。", "terminal.integrated.shell.windows": "終端機在 Windows 上使用的殼層路徑。使用隨附於 Windows 的殼層 (cmd、PowerShell 或 Bash on Ubuntu) 時。", "terminal.integrated.shellArgs.windows": "在 Windows 終端機上時要使用的命令列引數。", + "terminal.integrated.macOptionIsMeta": "將選項鍵視為 macOS 終端機中的 meta 鍵。", "terminal.integrated.rightClickCopyPaste": "如有設定,這會防止在終端機內按滑鼠右鍵時顯示操作功能表,而是在有選取項目時複製、沒有選取項目時貼上。", "terminal.integrated.copyOnSelection": "當設定時,在終端機中選擇的文字將會被複製至剪貼簿", "terminal.integrated.fontFamily": "控制終端機的字型家族,預設為 editor.fontFamily 的值。", @@ -25,10 +26,12 @@ "terminal.integrated.setLocaleVariables": "控制是否在終端機啟動時設定地區設定變數,這在 OS X 上預設為 true,在其他平台則為 false。", "terminal.integrated.cwd": "終端機啟動位置的明確起始路徑,這會用作殼層處理序的目前工作目錄 (cwd)。當根目錄不是方便的 cwd 時,這在工作區設定中特別好用。", "terminal.integrated.confirmOnExit": "當有使用中的終端機工作階段時,是否要在結束時確認。", + "terminal.integrated.enableBell": "是否啟用終端機警告聲。", "terminal.integrated.commandsToSkipShell": "一組命令識別碼,其按鍵繫結關係將不會傳送到殼層,而會一律由 Code 處理。這讓通常由殼層取用的按鍵繫結關係,在使用上與未聚焦於終端機時行為相同,例如 Ctrl+P 可啟動 Quick Open。", "terminal.integrated.env.osx": "OS X 上的終端機要使用之具有將新增至 VS Code 流程之環境變數的物件", "terminal.integrated.env.linux": "Linux 上的終端機要使用之具有將新增至 VS Code 流程之環境變數的物件", "terminal.integrated.env.windows": "Windows 上的終端機要使用之具有將新增至 VS Code 流程之環境變數的物件", + "terminal.integrated.showExitAlert": "當結束代碼非 0,顯示警告訊息 '終端處理序已終止並回傳結束代碼'", "terminalCategory": "終端機", "viewCategory": "檢視" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 3338d6ea3da..2fcd49773a9 100644 --- a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -12,6 +12,7 @@ "workbench.action.terminal.selectAll": "全選", "workbench.action.terminal.deleteWordLeft": "刪除左方文字", "workbench.action.terminal.deleteWordRight": "刪除右方文字", + "workbench.action.terminal.enterLineNavigationMode": "進入螢幕閱讀器導航模式", "workbench.action.terminal.new": "建立新的整合式終端機", "workbench.action.terminal.new.short": "新增終端機", "workbench.action.terminal.newWorkspacePlaceholder": "為新的終端機選擇目前的工作目錄", diff --git a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 331a28ddaf2..fc6b0624a08 100644 --- a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -7,6 +7,7 @@ "terminal.integrated.chooseWindowsShellInfo": "您可以選取 [自訂] 按鈕變更預設的終端機殼層。", "customize": "自訂", "cancel": "取消", + "never again": "確定,不要再顯示", "terminal.integrated.chooseWindowsShell": "請選取所需的終端機殼層。您之後可以在設定中變更此選擇", "terminalService.terminalCloseConfirmationSingular": "仍有一個使用中的終端機工作階段。要予以終止嗎?", "terminalService.terminalCloseConfirmationPlural": "目前共有 {0} 個使用中的終端機工作階段。要予以終止嗎?" diff --git a/i18n/deu/extensions/git/package.i18n.json b/i18n/deu/extensions/git/package.i18n.json index eba5779a178..d9f684ed551 100644 --- a/i18n/deu/extensions/git/package.i18n.json +++ b/i18n/deu/extensions/git/package.i18n.json @@ -49,7 +49,7 @@ "command.showOutput": "Git-Ausgabe anzeigen", "command.ignore": "Datei zu .gitignore hinzufügen", "command.stashIncludeUntracked": "Stash (einschließlich nicht verfolgt)", - "command.stash": " Stash ausführen", + "command.stash": "Stash ausführen", "command.stashPop": "Pop für Stash ausführen...", "command.stashPopLatest": "Pop für letzten Stash ausführen", "config.enabled": "Gibt an, ob Git aktiviert ist.", diff --git a/i18n/deu/extensions/typescript/out/features/quickFixProvider.i18n.json b/i18n/deu/extensions/typescript/out/features/quickFixProvider.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/deu/extensions/typescript/out/features/quickFixProvider.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json index ed57dd20d06..4fbcab5f91e 100644 --- a/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -40,9 +40,6 @@ "wordWrapColumn": "Steuert die Umbruchspalte des Editors, wenn für \"editor.wordWrap\" die Option \"wordWrapColumn\" oder \"bounded\" festgelegt ist.", "wrappingIndent": "Steuert den Einzug der umbrochenen Zeilen. Der Wert kann \"none\", \"same\" oder \"indent\" sein.", "mouseWheelScrollSensitivity": "Ein Multiplikator, der für die Mausrad-Bildlaufereignisse \"deltaX\" und \"deltaY\" verwendet werden soll.", - "multiCursorModifier.ctrlCmd": "Ist unter Windows und Linux der Taste \"STRG\" und unter OSX der Befehlstaste zugeordnet.", - "multiCursorModifier.alt": "Ist unter Windows und Linux der Taste \"Alt\" und unter OSX der Wahltaste zugeordnet. ", - "multiCursorModifier": "Der Modifizierer, der zum Hinzufügen mehrerer Cursor mit der Maus verwendet wird. \"ctrlCmd\" wird unter Windows und Linux der Taste \"STRG\" und unter OSX der Befehlstaste zugeordnet. Die Mausbewegungen \"Gehe zu Definition\" und \"Link öffnen\" werden so angepasst, dass kein Konflikt mit dem Multi-Cursor-Modifizierer entsteht.", "quickSuggestions.strings": "Schnellvorschläge innerhalb von Zeichenfolgen aktivieren.", "quickSuggestions.comments": "Schnellvorschläge innerhalb von Kommentaren aktivieren.", "quickSuggestions.other": "Schnellvorschläge außerhalb von Zeichenfolgen und Kommentaren aktivieren.", diff --git a/i18n/deu/src/vs/platform/list/browser/listService.i18n.json b/i18n/deu/src/vs/platform/list/browser/listService.i18n.json new file mode 100644 index 00000000000..b9d7e353c74 --- /dev/null +++ b/i18n/deu/src/vs/platform/list/browser/listService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "workbenchConfigurationTitle": "Workbench" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json b/i18n/deu/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json new file mode 100644 index 00000000000..92a29050896 --- /dev/null +++ b/i18n/deu/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirestring": "Die Eigenschaft \"{0}\" ist erforderlich. Sie muss vom Typ \"string\" sein.", + "optstring": "Die Eigenschaft \"{0}\" kann ausgelassen werden oder muss vom Typ \"string\" sein." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 1c098b69622..6cfd4e91479 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -19,8 +19,6 @@ "vscode.extension.contributes.debuggers.configurationAttributes": "JSON-Schemakonfigurationen zum Überprüfen von \"launch.json\".", "vscode.extension.contributes.debuggers.windows": "Windows-spezifische Einstellungen.", "vscode.extension.contributes.debuggers.windows.runtime": "Die für Windows verwendete Laufzeit.", - "vscode.extension.contributes.debuggers.osx": "OS X-spezifische Einstellungen.", - "vscode.extension.contributes.debuggers.osx.runtime": "Die für OS X verwendete Laufzeit.", "vscode.extension.contributes.debuggers.linux": "Linux-spezifische Einstellungen.", "vscode.extension.contributes.debuggers.linux.runtime": "Die für Linux verwendete Laufzeit.", "vscode.extension.contributes.breakpoints": "Trägt Haltepunkte bei.", diff --git a/i18n/deu/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json index e32b687f050..0816ad37e8d 100644 --- a/i18n/deu/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json @@ -14,7 +14,6 @@ "findInFiles": "In Dateien suchen", "openAnythingHandlerDescription": "Zu Datei wechseln", "openSymbolDescriptionNormal": "Zu Symbol im Arbeitsbereich wechseln", - "searchOutputChannelTitle": "Suchen", "searchConfigurationTitle": "Suchen", "exclude": "Konfigurieren Sie Globmuster zum Ausschließen von Dateien und Ordnern in Suchvorgängen. Alle Globmuster werden von der files.exclude-Einstellung geerbt.", "exclude.boolean": "Das Globmuster, mit dem Dateipfade verglichen werden sollen. Legen Sie diesen Wert auf \"true\" oder \"false\" fest, um das Muster zu aktivieren bzw. zu deaktivieren.", diff --git a/i18n/esn/extensions/git/out/autofetch.i18n.json b/i18n/esn/extensions/git/out/autofetch.i18n.json index 98972c6f0a2..2e2bb63e461 100644 --- a/i18n/esn/extensions/git/out/autofetch.i18n.json +++ b/i18n/esn/extensions/git/out/autofetch.i18n.json @@ -6,5 +6,7 @@ { "yes": "Sí", "read more": "Leer más", - "no": "No" + "no": "No", + "not now": "Preguntarme luego", + "suggest auto fetch": "Te gustaría que Code ejecute `git fetch` periódicamente?" } \ No newline at end of file diff --git a/i18n/esn/extensions/git/out/commands.i18n.json b/i18n/esn/extensions/git/out/commands.i18n.json index 3be82274dd3..9a3ea98e470 100644 --- a/i18n/esn/extensions/git/out/commands.i18n.json +++ b/i18n/esn/extensions/git/out/commands.i18n.json @@ -41,6 +41,10 @@ "confirm discard all 2": "{0}\n\nEsta acción es IRREVERSIBLE. Su espacio de trabajo actual SE PERDERÁ PARA SIEMPRE.", "yes discard tracked": "Descartar un archivo con seguimiento", "yes discard tracked multiple": "Descartar {0} archivos con seguimiento", + "unsaved files single": "El siguiente archivo no está guardado: {0}.\n¿Desea guardarlo antes de confirmarlo? ", + "unsaved files": "Hay {0} archivos sin guardar.\n¿Desea guardarlos antes de confirmar?", + "save and commit": "Guardar todo y confirmar", + "commit": "Confirmar de todas formas", "no staged changes": "No hay elementos almacenados provisionalmente.\n\n¿Desea almacenar de forma provisional todos sus cambios y confirmarlos directamente?", "always": "Siempre", "no changes": "No hay cambios para confirmar.", @@ -69,6 +73,7 @@ "push with tags success": "Insertado con etiquetas correctamente.", "pick remote": "Seleccionar un elemento remoto para publicar la rama '{0}':", "sync is unpredictable": "Esta acción insertará y extraerá confirmaciones en '{0}'.", + "never again": "No volver a mostrar", "no remotes to publish": "El repositorio no tiene remotos configurados en los que publicar.", "no changes stash": "No existen cambios para el guardado provisional.", "provide stash message": "Opcionalmente, proporcionar un mensaje para el guardado provisional", diff --git a/i18n/esn/extensions/git/package.i18n.json b/i18n/esn/extensions/git/package.i18n.json index 9dab8cc59ce..71eed7035ea 100644 --- a/i18n/esn/extensions/git/package.i18n.json +++ b/i18n/esn/extensions/git/package.i18n.json @@ -54,11 +54,13 @@ "command.stashPopLatest": "Aplicar y quitar últimos cambios guardados provisionalmente...", "config.enabled": "Si GIT está habilitado", "config.path": "Ruta de acceso del ejecutable de GIT", + "config.autoRepositoryDetection": "Si se deben detectar automáticamente los repositories ", "config.autorefresh": "Indica si la actualización automática está habilitada", "config.autofetch": "Si la búsqueda automática está habilitada", "config.enableLongCommitWarning": "Si se debe advertir sobre los mensajes de confirmación largos", "config.confirmSync": "Confirmar antes de sincronizar repositorios GIT", "config.countBadge": "Controla el contador de insignia de Git. \"Todo\" cuenta todos los cambios. \"Seguimiento\" solamente cuenta los cambios realizados. \"Desactivado\" lo desconecta.", + "config.checkoutType": "Controla el tipo de ramas listadas cuando ejecuta \"Desproteger\". \"Todo\" muetra todas las referencias, \"local\" solamente las ramas locales y \"remoto\" las ramas remotas.", "config.ignoreLegacyWarning": "Ignora las advertencias hereradas de Git", "config.ignoreMissingGitWarning": "Ignora la advertencia cuando falta Git", "config.ignoreLimitWarning": "\nIgnora advertencias cuando se encuentran muchos cambios en un repositorio.", @@ -71,5 +73,6 @@ "colors.deleted": "Color para los recursos eliminados.", "colors.untracked": "Color para los recursos a los que no se les hace seguimiento.", "colors.ignored": "Color para los recursos ignorados.", - "colors.conflict": "Color para los recursos con conflictos." + "colors.conflict": "Color para los recursos con conflictos.", + "colors.submodule": "Color para los recursos de submódulos." } \ No newline at end of file diff --git a/i18n/esn/extensions/typescript/out/features/quickFixProvider.i18n.json b/i18n/esn/extensions/typescript/out/features/quickFixProvider.i18n.json new file mode 100644 index 00000000000..37a369cc83b --- /dev/null +++ b/i18n/esn/extensions/typescript/out/features/quickFixProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fixAllInFileLabel": "{0} (Corregir todo en el archivo)" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/esn/src/vs/editor/common/config/commonEditorConfig.i18n.json index 9e12f7523e1..dae6488ccb2 100644 --- a/i18n/esn/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/esn/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -40,9 +40,9 @@ "wordWrapColumn": "Controls the wrapping column of the editor when `editor.wordWrap` is 'wordWrapColumn' or 'bounded'.", "wrappingIndent": "Controla el sangrado de las líneas ajustadas. Puede ser uno los valores 'none', 'same' o 'indent'.", "mouseWheelScrollSensitivity": "Se utilizará un multiplicador en los eventos de desplazamiento de la rueda del mouse `deltaX` y `deltaY`", - "multiCursorModifier.ctrlCmd": "Se asigna a \"Control\" en Windows y Linux y a \"Comando\" en OSX.", - "multiCursorModifier.alt": "Se asigna a \"Alt\" en Windows y Linux y a \"Opción\" en OSX.", - "multiCursorModifier": "El modificador que se usará para agregar varios cursores con el mouse. \"ctrlCmd\" se asigna a \"Control\" en Windows y Linux y a \"Comando\" en OSX. Los gestos del mouse Ir a la definición y Abrir vínculo se adaptarán de modo que no entren en conflicto con el modificador multicursor.", + "multiCursorModifier.ctrlCmd": "Se asigna a \"Control\" en Windows y Linux y a \"Comando\" en macOS.", + "multiCursorModifier.alt": "Se asigna a \"Alt\" en Windows y Linux y a \"Opción\" en macOS.", + "multiCursorModifier": "El modificador que se usará para agregar varios cursores con el mouse. \"ctrlCmd\" se asigna a \"Control\" en Windows y Linux y a \"Comando\" en macOS. Los gestos del mouse \"Ir a la definición\" y \"Abrir vínculo\" se adaptarán de modo que no entren en conflicto con el modificador multicurso", "quickSuggestions.strings": "Habilita sugerencias rápidas en las cadenas.", "quickSuggestions.comments": "Habilita sugerencias rápidas en los comentarios.", "quickSuggestions.other": "Habilita sugerencias rápidas fuera de las cadenas y los comentarios.", diff --git a/i18n/esn/src/vs/platform/environment/node/argv.i18n.json b/i18n/esn/src/vs/platform/environment/node/argv.i18n.json index 65665985d3d..ab77c62ca8d 100644 --- a/i18n/esn/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/esn/src/vs/platform/environment/node/argv.i18n.json @@ -30,6 +30,7 @@ "inspect-extensions": "Permitir la depuración y el perfil de las extensiones. Revisar las herramientas de desarrollador para la conexión uri.", "inspect-brk-extensions": "Permitir la depuración y el perfil de las extensiones con el host de la extensión pausado después del inicio. Revisar las herramientas de desarrollador para la conexión uri.", "disableGPU": "Deshabilita la aceleración de hardware de GPU.", + "issue": "Notificar un problema. ", "usage": "Uso", "options": "opciones", "paths": "rutas de acceso", diff --git a/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index f654894f7d5..77d52783b53 100644 --- a/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -10,7 +10,10 @@ "override": "Anular", "cancel": "Cancelar", "errorInstallingDependencies": "Error instalando dependencias. {0}", + "notFoundCompatible": "No se pueden instalar '{0}'; no hay ninguna versión disponible compatible con VS Code '{1}'. ", "notFoundCompatibleDependency": "No se puede instalar porque no se encuentra la extensión dependiente '{0}' compatible con la versión actual '{1}' del VS Code.", + "quitCode": "No se puede instalar la extensión. Por favor, salga e inicie VS Code antes de reinstalarlo. ", + "exitCode": "No se puede instalar la extensión. Por favor, salga e inicie VS Code antes de reinstalarlo. ", "uninstallDependeciesConfirmation": "¿Quiere desinstalar solo '{0}' o también sus dependencias?", "uninstallOnly": "Solo", "uninstallAll": "Todo", diff --git a/i18n/esn/src/vs/platform/list/browser/listService.i18n.json b/i18n/esn/src/vs/platform/list/browser/listService.i18n.json new file mode 100644 index 00000000000..f2af41d4337 --- /dev/null +++ b/i18n/esn/src/vs/platform/list/browser/listService.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "workbenchConfigurationTitle": "Área de trabajo", + "multiSelectModifier.ctrlCmd": "Se asigna a \"Control\" en Windows y Linux y a \"Comando\" en macOS.", + "multiSelectModifier.alt": "Se asigna a \"Alt\" en Windows y Linux y a \"Opción\" en macOS." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json b/i18n/esn/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json new file mode 100644 index 00000000000..ab1f8a53027 --- /dev/null +++ b/i18n/esn/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "las localizaciones deben ser una matriz", + "requirestring": "la propiedad `{0}` es obligatoria y debe ser de tipo \"string\"", + "optstring": "la propiedad `{0}` se puede omitir o debe ser de tipo \"string\"", + "vscode.extension.contributes.localizations.languageName": "Nombre del idioma en el que se traducen las cadenas visualizadas." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.i18n.json b/i18n/esn/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.i18n.json index 8b6ad71cd4e..a0da8956de3 100644 --- a/i18n/esn/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.i18n.json +++ b/i18n/esn/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "saveParticipants": "Ejecutando Guardar Participantes..." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/api/node/extHostTreeViews.i18n.json b/i18n/esn/src/vs/workbench/api/node/extHostTreeViews.i18n.json index e897d06ac34..12c9dbb13d3 100644 --- a/i18n/esn/src/vs/workbench/api/node/extHostTreeViews.i18n.json +++ b/i18n/esn/src/vs/workbench/api/node/extHostTreeViews.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "treeView.notRegistered": "No se ha registrado ninga vista del árbol con id '{0}'." + "treeView.notRegistered": "No se ha registrado ninga vista del árbol con id '{0}'.", + "treeView.duplicateElement": "El elemento con id {0} está ya registrado" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/actions/workspaceCommands.i18n.json b/i18n/esn/src/vs/workbench/browser/actions/workspaceCommands.i18n.json index 832cb0abb68..e1642a76137 100644 --- a/i18n/esn/src/vs/workbench/browser/actions/workspaceCommands.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/actions/workspaceCommands.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "addFolderToWorkspace": "Agregar carpeta al área de trabajo...", + "add": "&&Añadir", "addFolderToWorkspaceTitle": "Agregar carpeta al área de trabajo", "workspaceFolderPickerPlaceholder": "Seleccionar la carpeta del área de trabajo" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 0e9cbb0a9e2..5d49307d15f 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -20,6 +20,7 @@ "closeAllUnmodified": "Cerrar los que no se han modificado", "closeAll": "Cerrar todo", "keepOpen": "Mantener abierto", + "toggleInlineView": "Cambiar vista en línea", "showOpenedEditors": "Mostrar editores abiertos", "keepEditor": "Mantener editor", "closeEditorsInGroup": "Cerrar todos los editores del grupo", diff --git a/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 93badc7f42a..0063a5e42f9 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -48,5 +48,8 @@ "moveEditorLeft": "Mover el editor a la izquierda", "moveEditorRight": "Mover el editor a la derecha", "moveEditorToPreviousGroup": "Mover editor al grupo anterior", - "moveEditorToNextGroup": "Mover editor al grupo siguiente" + "moveEditorToNextGroup": "Mover editor al grupo siguiente", + "moveEditorToFirstGroup": "Mover el Editor al Primer Grupo", + "moveEditorToSecondGroup": "Mover el Editor al Segundo Grupo", + "moveEditorToThirdGroup": "Mover el Editor al Tercer Grupo" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/editor/textDiffEditor.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/editor/textDiffEditor.i18n.json index 8fda6300549..ce242cd2e74 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/editor/textDiffEditor.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/editor/textDiffEditor.i18n.json @@ -10,5 +10,6 @@ "editableEditorWithInputAriaLabel": "{0}. Editor de comparación de archivos de texto.", "editableEditorAriaLabel": "Editor de comparación de archivos de texto.", "navigate.next.label": "Cambio siguiente", - "navigate.prev.label": "Cambio anterior" + "navigate.prev.label": "Cambio anterior", + "toggleIgnoreTrimWhitespace.label": "Ignorar espacios en blanco al principio y final" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json index 8b6ad71cd4e..e40ee5163a0 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "hideView": "Ocultar" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/esn/src/vs/workbench/electron-browser/actions.i18n.json index c875a388e03..27010729e22 100644 --- a/i18n/esn/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/esn/src/vs/workbench/electron-browser/actions.i18n.json @@ -29,6 +29,7 @@ "openRecent": "Abrir Reciente...", "quickOpenRecent": "Abrir Reciente Rapidamente...", "closeMessages": "Cerrar mensajes de notificación", + "openIssueReporter": "Abrir Reportador de Problemas", "reportIssueInEnglish": "Notificar problema", "reportPerformanceIssue": "Notificar problema de rendimiento", "keybindingsReference": "Referencia de métodos abreviados de teclado", diff --git a/i18n/esn/src/vs/workbench/electron-browser/window.i18n.json b/i18n/esn/src/vs/workbench/electron-browser/window.i18n.json index 5ceee829d26..bf0f301897f 100644 --- a/i18n/esn/src/vs/workbench/electron-browser/window.i18n.json +++ b/i18n/esn/src/vs/workbench/electron-browser/window.i18n.json @@ -9,5 +9,6 @@ "cut": "Cortar", "copy": "Copiar", "paste": "Pegar", - "selectAll": "Seleccionar todo" + "selectAll": "Seleccionar todo", + "runningAsRoot": "No se recomienda ejecutar {0} como usuario root." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 28c7690312b..59239289a53 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -19,8 +19,6 @@ "vscode.extension.contributes.debuggers.configurationAttributes": "Configuraciones de esquema JSON para validar \"launch.json\".", "vscode.extension.contributes.debuggers.windows": "Configuración específica de Windows.", "vscode.extension.contributes.debuggers.windows.runtime": "Entorno de ejecución que se usa para Windows.", - "vscode.extension.contributes.debuggers.osx": "Configuración específica de OS X.", - "vscode.extension.contributes.debuggers.osx.runtime": "Entorno de ejecución que se usa para OSX.", "vscode.extension.contributes.debuggers.linux": "Configuración específica de Linux.", "vscode.extension.contributes.debuggers.linux.runtime": "Entorno de ejecución que se usa para Linux.", "vscode.extension.contributes.breakpoints": "Aporta puntos de interrupción.", diff --git a/i18n/esn/src/vs/workbench/parts/files/electron-browser/saveErrorHandler.i18n.json b/i18n/esn/src/vs/workbench/parts/files/electron-browser/saveErrorHandler.i18n.json index 85b5734142e..b8d86411047 100644 --- a/i18n/esn/src/vs/workbench/parts/files/electron-browser/saveErrorHandler.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/electron-browser/saveErrorHandler.i18n.json @@ -5,9 +5,14 @@ // Do not edit this file. It is machine generated. { "userGuide": "Use las acciones de la barra de herramientas del editor situada a la derecha para **deshacer** los cambios o **sobrescribir** el contenido del disco con sus cambios", + "overwriteElevated": "Sobrescribir como Admin...", + "saveElevated": "Reintentar como Admin...", "overwrite": "Sobrescribir", "retry": "Reintentar", "discard": "Descartar", + "readonlySaveErrorAdmin": "No se pudo guardar '{0}': El archivo está protegido contra escritura. Seleccione 'Sobrescribir como Admin' para volverlo a intentar como administrador.", + "readonlySaveError": "No se pudo guardar '{0}': El archivo está protegido contra escritura. Seleccione 'Sobrescribir' para intentar quitar la protección.", + "permissionDeniedSaveError": "No se pudo guardar '{0}': Permisos insuficientes. Seleccione 'Reintentar como Admin' para volverlo a intentar como administrador.", "genericSaveError": "No se pudo guardar '{0}': {1}", "staleSaveError": "No se pudo guardar '{0}': El contenido del disco es más reciente. Haga clic en **Comparar** para comparar su versión con la que hay en el disco.", "compareChanges": "Comparar", diff --git a/i18n/esn/src/vs/workbench/parts/logs/electron-browser/logs.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/logs/electron-browser/logs.contribution.i18n.json index 68e35e56b16..29b8033be98 100644 --- a/i18n/esn/src/vs/workbench/parts/logs/electron-browser/logs.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/logs/electron-browser/logs.contribution.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "mainLog": "Log (Principal)", + "sharedLog": "Log (Compartido)", + "rendererLog": "Log (Ventana)", + "extensionsLog": "Log (Extensión del Host)", "developer": "Desarrollador" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/logs/electron-browser/logsActions.i18n.json b/i18n/esn/src/vs/workbench/parts/logs/electron-browser/logsActions.i18n.json index 80e723dfda2..850ca48cdd2 100644 --- a/i18n/esn/src/vs/workbench/parts/logs/electron-browser/logsActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/logs/electron-browser/logsActions.i18n.json @@ -11,6 +11,7 @@ "rendererProcess": "Ventana", "extensionHost": "Host de extensión", "selectProcess": "Seleccionar proceso", + "openLogFile": "Abrir archivo de log...", "setLogLevel": "Establecer nivel de registro", "trace": "Seguimiento", "debug": "Depurar", @@ -18,5 +19,6 @@ "warn": "Advertencia", "err": "Error", "critical": "Crítico", - "off": "Apagado" + "off": "Apagado", + "selectLogLevel": "Seleccionar nivel de log" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index c5061e853b0..45352bad122 100644 --- a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -8,5 +8,6 @@ "source control": "Control de código fuente", "toggleSCMViewlet": "Mostrar SCM", "view": "Ver", - "scmConfigurationTitle": "SCM" + "scmConfigurationTitle": "SCM", + "inputCounter": "Controla cuándo mostrar el contador de entradas." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index 7f679305c9e..812f048c02f 100644 --- a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -6,6 +6,8 @@ { "scm providers": "Proveedores de Control de Código fuente", "hideRepository": "Ocultar", + "commitMessageInfo": "{0} caracteres en la línea actual", + "commitMessageCountdown": "quedan {0} caracteres en la línea actual", "installAdditionalSCMProviders": "Instalar proveedores adicionales de SCM...", "no open repo": "No hay proveedores de control de código fuente activos.", "source control": "Control de código fuente", diff --git a/i18n/esn/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json index a0aba2b8419..3b7e2d3cd41 100644 --- a/i18n/esn/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json @@ -14,7 +14,6 @@ "findInFiles": "Buscar en archivos", "openAnythingHandlerDescription": "Ir al archivo", "openSymbolDescriptionNormal": "Ir al símbolo en el área de trabajo", - "searchOutputChannelTitle": "Buscar", "searchConfigurationTitle": "Buscar", "exclude": "Configure patrones globales para excluir archivos y carpetas de las búsquedas. Hereda todos los patrones globales de la configuración files.exclude.", "exclude.boolean": "El patrón global con el que se harán coincidir las rutas de acceso de los archivos. Establézcalo en true o false para habilitarlo o deshabilitarlo.", diff --git a/i18n/fra/extensions/typescript/out/features/quickFixProvider.i18n.json b/i18n/fra/extensions/typescript/out/features/quickFixProvider.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/fra/extensions/typescript/out/features/quickFixProvider.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json index 4beaeedee28..76111fb62b0 100644 --- a/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -40,9 +40,6 @@ "wordWrapColumn": "Contrôle la colonne de retour automatique à la ligne de l'éditeur quand 'editor.wordWrap' a la valeur 'wordWrapColumn' ou 'bounded'.", "wrappingIndent": "Contrôle le retrait des lignes renvoyées. La valeur peut être 'none', 'same' ou 'indent'.", "mouseWheelScrollSensitivity": "Multiplicateur à utiliser pour le 'deltaX' et le 'deltaY' des événements de défilement de la roulette de la souris", - "multiCursorModifier.ctrlCmd": "Mappe vers 'Contrôle' dans Windows et Linux, et vers 'Commande' dans OSX.", - "multiCursorModifier.alt": "Mappe vers 'Alt' dans Windows et Linux, et vers 'Option' dans OSX.", - "multiCursorModifier": "Modificateur à utiliser pour ajouter plusieurs curseurs avec la souris. 'ctrlCmd' mappe vers 'Contrôle' dans Windows et Linux, et vers 'Commande' dans OSX. Les mouvements de souris Accéder à la définition et Ouvrir le lien s'adaptent pour ne pas entrer en conflit avec le modificateur multicurseur.", "quickSuggestions.strings": "Activez les suggestions rapides dans les chaînes.", "quickSuggestions.comments": "Activez les suggestions rapides dans les commentaires.", "quickSuggestions.other": "Activez les suggestions rapides en dehors des chaînes et des commentaires.", diff --git a/i18n/fra/src/vs/platform/list/browser/listService.i18n.json b/i18n/fra/src/vs/platform/list/browser/listService.i18n.json new file mode 100644 index 00000000000..92f8f5bfde6 --- /dev/null +++ b/i18n/fra/src/vs/platform/list/browser/listService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "workbenchConfigurationTitle": "Banc d'essai" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json b/i18n/fra/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json new file mode 100644 index 00000000000..1c77d004aae --- /dev/null +++ b/i18n/fra/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirestring": "la propriété '{0}' est obligatoire et doit être de type 'string'", + "optstring": "La propriété '{0}' peut être omise ou doit être de type 'string'" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 5a3987eaa76..64badf8518f 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -19,8 +19,6 @@ "vscode.extension.contributes.debuggers.configurationAttributes": "Configurations de schéma JSON pour la validation de 'launch.json'.", "vscode.extension.contributes.debuggers.windows": "Paramètres spécifiques à Windows.", "vscode.extension.contributes.debuggers.windows.runtime": "Runtime utilisé pour Windows.", - "vscode.extension.contributes.debuggers.osx": "Paramètres spécifiques à OS X.", - "vscode.extension.contributes.debuggers.osx.runtime": "Runtime utilisé pour OS X.", "vscode.extension.contributes.debuggers.linux": "Paramètres spécifiques à Linux.", "vscode.extension.contributes.debuggers.linux.runtime": "Runtime utilisé pour Linux.", "vscode.extension.contributes.breakpoints": "Ajoute des points d'arrêt.", diff --git a/i18n/fra/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json index f5dbbc47515..69ce9d7f6cd 100644 --- a/i18n/fra/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json @@ -14,7 +14,6 @@ "findInFiles": "Chercher dans les fichiers", "openAnythingHandlerDescription": "Accéder au fichier", "openSymbolDescriptionNormal": "Atteindre le symbole dans l'espace de travail", - "searchOutputChannelTitle": "Rechercher", "searchConfigurationTitle": "Rechercher", "exclude": "Configurez les modèles Glob pour exclure les fichiers et les dossiers des recherches. Hérite de tous les modèles Glob à partir du paramètre files.exclude.", "exclude.boolean": "Modèle Glob auquel les chemins de fichiers doivent correspondre. Affectez la valeur true ou false pour activer ou désactiver le modèle.", diff --git a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index c4ad53ee08a..5b59359d46e 100644 --- a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -12,7 +12,6 @@ "workbench.action.terminal.selectAll": "Tout Sélectionner", "workbench.action.terminal.deleteWordLeft": "Supprimer le mot à gauche", "workbench.action.terminal.deleteWordRight": "Supprimer le mot à droite", - "workbench.action.terminal.enterLineNavigationMode": "Saisir la ligne de mode de navigation", "workbench.action.terminal.new": "Créer un terminal intégré", "workbench.action.terminal.new.short": "Nouveau terminal", "workbench.action.terminal.newWorkspacePlaceholder": "Sélectionner le répertoire de travail actuel pour le nouveau terminal", diff --git a/i18n/hun/extensions/git/package.i18n.json b/i18n/hun/extensions/git/package.i18n.json index 52f61e79d5d..87388db14f4 100644 --- a/i18n/hun/extensions/git/package.i18n.json +++ b/i18n/hun/extensions/git/package.i18n.json @@ -60,6 +60,7 @@ "config.enableLongCommitWarning": "Figyelmeztessen-e az alkalmazás hosszú beadási üzenet esetén", "config.confirmSync": "Megerősítés kérése git forráskódtárak szinkronizálása előtt", "config.countBadge": "Meghatározza a git jelvényen megjelenő számláló működését. Az `all` minden módosítást számol, a `tracked` csak a követkett változtatásokat. Az `off` kikapcsolja a jelvényt.", + "config.checkoutType": "Meghatározza, hogy milyen típusú ágak jelenjenek meg a `Checkout adott helyről... ` parancs futtatása esetén. Az `all` esetén az összes ref megjelenik, `local` esetén csak a helyi ágak, `tags` esetén csak a címkék, `remote` esetén pedig csak a távoli ágak.", "config.ignoreLegacyWarning": "Régi gittel kapcsolatos figyelmeztetés figyelmen kívül hagyása", "config.ignoreMissingGitWarning": "Figyelmeztetés figyelmen kívül hagyása, ha a Git hiányzik", "config.ignoreLimitWarning": "Túl sok módosítás esetén megjelenő figyelmeztetés figyelmen kívül hagyása", diff --git a/i18n/hun/extensions/typescript/out/features/quickFixProvider.i18n.json b/i18n/hun/extensions/typescript/out/features/quickFixProvider.i18n.json new file mode 100644 index 00000000000..6d6ae6eab7e --- /dev/null +++ b/i18n/hun/extensions/typescript/out/features/quickFixProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fixAllInFileLabel": "{0} (összes javítása a fájlban)" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/hun/src/vs/editor/common/config/commonEditorConfig.i18n.json index 7f137c6fbff..5a0b782e9aa 100644 --- a/i18n/hun/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/hun/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -40,9 +40,9 @@ "wordWrapColumn": "Meghatározza a sortöréshez használt oszlopszámot a szerkesztőablakban, ha az `editor.wordWrap` értéke 'wordWrapColumn' vagy 'bounded'.", "wrappingIndent": "Meghatározza a tördelt sorok behúzását. Értéke 'none', 'same' vagy 'indent' lehet.", "mouseWheelScrollSensitivity": "Az egér görgetési eseményeinél keletkező `deltaX` és `deltaY` paraméterek szorzója", - "multiCursorModifier.ctrlCmd": "Windows és Linux alatt a `Control`, OSX alatt a `Command` billentyűt jelenti.", - "multiCursorModifier.alt": "Windows és Linux alatt az `Alt`, OSX alatt az `Option` billentyűt jelenti.", - "multiCursorModifier": "Több kurzor hozzáadásához használt módosítóbillentyű. A `ctrlCmd` Windows és Linux alatt a `Control`, OSX alatt a `Command` billentyűt jelenti. A Definíció megkeresése és Hivatkozás megnyitása egérgesztusok automatikusan alkalmazkodnak úgy, hogy ne ütközzenek a többkurzorhoz tartozó módosítóval.", + "multiCursorModifier.ctrlCmd": "Windows és Linux alatt a `Control`, macOS alatt a `Command` billentyűt jelenti.", + "multiCursorModifier.alt": "Windows és Linux alatt az `Alt`, macOS alatt az `Option` billentyűt jelenti.", + "multiCursorModifier": "Több kurzor hozzáadásához használt módosítóbillentyű. A `ctrlCmd` Windows és Linux alatt a `Control`, macOS alatt a `Command` billentyűt jelenti. A Definíció megkeresése és Hivatkozás megnyitása egérgesztusok automatikusan úgy lesznek beállítva, hogy ne ütközzenek a többkurzorhoz tartozó módosítóval.", "quickSuggestions.strings": "Kiegészítési javaslatok engedélyezése karakterláncokban (stringekben)", "quickSuggestions.comments": "Kiegészítési javaslatok engedélyezése megjegyzésekben", "quickSuggestions.other": "Kiegészítési javaslatok engedélyezése karakterláncokon (stringeken) és megjegyzéseken kívül", diff --git a/i18n/hun/src/vs/platform/environment/node/argv.i18n.json b/i18n/hun/src/vs/platform/environment/node/argv.i18n.json index f2b86a65d34..06b5ed441c6 100644 --- a/i18n/hun/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/hun/src/vs/platform/environment/node/argv.i18n.json @@ -31,6 +31,7 @@ "inspect-brk-extensions": "Hibakeresés és profilozás engedélyezése a kiegészítőkben, úgy, hogy a kiegészítő gazdafolyamata szüneteltetve lesz az indítás után. Ellenőrizze a fejlesztői eszközöket a csatlakozási URI-hoz. ", "disableGPU": "Hardveres gyorsítás letiltása.", "uploadLogs": "Az aktuális munkamenet naplóinak feltöltése egy biztonságos végpontra.", + "issue": "Probléma jelentése", "usage": "Használat", "options": "beállítások", "paths": "elérési utak", diff --git a/i18n/hun/src/vs/platform/list/browser/listService.i18n.json b/i18n/hun/src/vs/platform/list/browser/listService.i18n.json new file mode 100644 index 00000000000..b784e240a18 --- /dev/null +++ b/i18n/hun/src/vs/platform/list/browser/listService.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "workbenchConfigurationTitle": "Munkaterület", + "multiSelectModifier.ctrlCmd": "Windows és Linux alatt a `Control`, macOS alatt a `Command` billentyűt jelenti.", + "multiSelectModifier.alt": "Windows és Linux alatt az `Alt`, macOS alatt az `Option` billentyűt jelenti.", + "multiSelectModifier": "Több elem kijelölése esetén újabb elem hozzáadásához használt módosítóbillentyű (például a fanézetekben és listáknál, ha támogatva van). A `ctrlCmd` Windows és Linux alatt a `Control`, macOS alatt a `Command` billentyűt jelenti. A 'Megnyitás oldalt\" egérgesztusok – ha támogatva vannak – automatikusan úgy lesznek beállítva, hogy ne ütközzenek a több elem kijelöléséhez tartozó módosítóbillentyűvel." +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json b/i18n/hun/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json new file mode 100644 index 00000000000..95d3d6d773a --- /dev/null +++ b/i18n/hun/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "a localizationst tömbként kell megadni", + "requirestring": "a(z) `{0}` tulajdonság kötelező és `string` típusúnak kell lennie", + "optstring": "a(z) `{0}` tulajdonság elhagyható vagy `string` típusúnak kell lennie", + "vscode.extension.contributes.localizations": "Lokalizációkat szolgáltat a szerkesztőhöz", + "vscode.extension.contributes.localizations.languageId": "Annak a nyelvnek az azonosítója, amelyre a megjelenített szövegek fordítva vannak.", + "vscode.extension.contributes.localizations.languageName": "Annak a nyelvnek a neve, amelyre a megjelenített szövegek fordítva vannak.", + "vscode.extension.contributes.localizations.translations": "A nyelvhez tartozó összes, fordítási fájlokat tartalmazó mappa relatív elérési útja." +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/hun/src/vs/workbench/electron-browser/actions.i18n.json index 2e7a5636a3d..f67fea70490 100644 --- a/i18n/hun/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/hun/src/vs/workbench/electron-browser/actions.i18n.json @@ -29,6 +29,7 @@ "openRecent": "Legutóbbi megnyitása...", "quickOpenRecent": "Legutóbbi gyors megnyitása...", "closeMessages": "Értesítések törlése", + "openIssueReporter": "Hibajelentő megnyitása", "reportIssueInEnglish": "Probléma jelentése", "reportPerformanceIssue": "Teljesítményproblémák jelentése", "keybindingsReference": "Billentyűparancs-referencia", diff --git a/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index a54b3a8b776..06dec99b6e3 100644 --- a/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -19,8 +19,8 @@ "vscode.extension.contributes.debuggers.configurationAttributes": "JSON-sémakonfigurációk a 'launch.json' validálásához.", "vscode.extension.contributes.debuggers.windows": "Windows-specifikus beállítások.", "vscode.extension.contributes.debuggers.windows.runtime": "A Windows által használt futtatókörnyezet.", - "vscode.extension.contributes.debuggers.osx": "OS X-specifikus beállítások.", - "vscode.extension.contributes.debuggers.osx.runtime": "Az OSX által használt futtatókörnyezet.", + "vscode.extension.contributes.debuggers.osx": "macOS-specifikus beállítások.", + "vscode.extension.contributes.debuggers.osx.runtime": "A macOS által használt futtatókörnyezet.", "vscode.extension.contributes.debuggers.linux": "Linux-specifikus beállítások.", "vscode.extension.contributes.debuggers.linux.runtime": "A Linux által használt futtatókörnyezet.", "vscode.extension.contributes.breakpoints": "Töréspontokat szolgáltat.", diff --git a/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index 27e3da174c1..0ad54ad8b33 100644 --- a/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -13,6 +13,8 @@ "reallyRecommendedExtensionPack": "Ehhez a fájltípushoz a(z) '{0}' kiegészítőcsomag ajánlott.", "showRecommendations": "Ajánlatok megjelenítése", "install": "Telepítés", + "showLanguageExtensions": "A piactéren található olyan kiegészítő, ami segíthet a(z) '.{0}' fájloknál", + "searchMarketplace": "Keresés a piactéren", "workspaceRecommended": "A munkaterülethez vannak javasolt kiegészítők", "installAll": "Összes telepítése", "ignoreExtensionRecommendations": "Figyelmen kívül akarja hagyni az összes javasolt kiegészítőt?", diff --git a/i18n/hun/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json b/i18n/hun/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json index 4769b5168e9..73fb02efab6 100644 --- a/i18n/hun/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json @@ -4,6 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "installingVSIXExtension": "Kiegészítő telepítése VSIX-ből...", + "installingMarketPlaceExtension": "Kiegészítő telepítése a piactérről...", + "uninstallingExtension": "Kiegészítő eltávolítása...", "enableDependeciesConfirmation": "A(z) '{0}' engedélyezésével annak függőségei is engedélyezve lesznek. Szeretné folytatni?", "enable": "Igen", "doNotEnable": "Nem", diff --git a/i18n/hun/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json index 9cd24f4c872..e928937e0a8 100644 --- a/i18n/hun/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json @@ -14,7 +14,6 @@ "findInFiles": "Keresés a fájlokban", "openAnythingHandlerDescription": "Fájl megkeresése", "openSymbolDescriptionNormal": "Szimbólum megkeresése a munkaterületen", - "searchOutputChannelTitle": "Keresés", "searchConfigurationTitle": "Keresés", "exclude": "Globális minták konfigurálása fájlok és mappák keresésből való kizárásához. Örökli az összes globális mintát a fliex.exclude beállításból.", "exclude.boolean": "A globális minta, amire illesztve lesznek a fájlok elérési útjai. A minta engedélyezéséhez vagy letiltásához állítsa igaz vagy hamis értékre.", diff --git a/i18n/ita/extensions/typescript/out/features/quickFixProvider.i18n.json b/i18n/ita/extensions/typescript/out/features/quickFixProvider.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/ita/extensions/typescript/out/features/quickFixProvider.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/ita/src/vs/base/node/ps.i18n.json b/i18n/ita/src/vs/base/node/ps.i18n.json index 8b6ad71cd4e..9b7eb442bac 100644 --- a/i18n/ita/src/vs/base/node/ps.i18n.json +++ b/i18n/ita/src/vs/base/node/ps.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "collecting": "Raccolta informazioni su CPU e memoria in corso. Potrebbe impiegare qualche secondo." +} \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/ita/src/vs/editor/common/config/commonEditorConfig.i18n.json index 71aff162568..d740e2e557d 100644 --- a/i18n/ita/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/ita/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -40,9 +40,6 @@ "wordWrapColumn": "Controlla la colonna di wrapping dell'editor quando il valore di `editor.wordWrap` è 'wordWrapColumn' o 'bounded'.", "wrappingIndent": "Controlla il rientro delle righe con ritorno a capo. Può essere uno dei valori seguenti: 'none', 'same' o 'indent'.", "mouseWheelScrollSensitivity": "Moltiplicatore da usare sui valori `deltaX` e `deltaY` degli eventi di scorrimento della rotellina del mouse", - "multiCursorModifier.ctrlCmd": "Rappresenta il tasto 'Control' (ctrl) su Windows e Linux e il tasto 'Comando' (cmd) su OSX.", - "multiCursorModifier.alt": "Rappresenta il tasto 'Alt' su Windows e Linux e il tasto 'Opzione' su OSX.", - "multiCursorModifier": "Il modificatore da utilizzare per aggiungere molteplici cursori con il mouse. 'ctrlCmd' rappresenta il tasto 'Control' su Windows e Linux e il tasto 'Comando' su OSX. I gesti del mouse Vai a definizione e Apri il Link si adatteranno in modo da non entrare in conflitto con il modificatore multi-cursore.", "quickSuggestions.strings": "Abilita i suggerimenti rapidi all'interno di stringhe.", "quickSuggestions.comments": "Abilita i suggerimenti rapidi all'interno di commenti.", "quickSuggestions.other": "Abilita i suggerimenti rapidi all'esterno di stringhe e commenti.", @@ -72,6 +69,7 @@ "cursorBlinking": "Controlla lo stile di animazione del cursore. I valori possibili sono: 'blink', 'smooth', 'phase', 'expand' e 'solid'", "mouseWheelZoom": "Ingrandisce il carattere dell'editor quando si usa la rotellina del mouse e si tiene premuto CTRL", "cursorStyle": "Controlla lo stile del cursore. I valori accettati sono 'block', 'block-outline', 'line', 'line-thin', 'underline' e 'underline-thin'", + "lineCursorWidth": "Controlla la larghezza del cursore quando editor.cursorSyle è impostato a 'line'", "fontLigatures": "Abilita i caratteri legatura", "hideCursorInOverviewRuler": "Controlla se il cursore deve essere nascosto nel righello delle annotazioni.", "renderWhitespace": "Consente di controllare in che modo l'editor deve eseguire il rendering dei caratteri di spazio vuoto. Le opzioni possibili sono: 'none', 'boundary' e 'all'. Con l'opzione 'boundary' non viene eseguito il rendering di singoli spazi tra le parole.", diff --git a/i18n/ita/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/ita/src/vs/editor/common/view/editorColorRegistry.i18n.json index 81909087f69..57a55fb4bfd 100644 --- a/i18n/ita/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/ita/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -6,6 +6,7 @@ { "lineHighlight": "Colore di sfondo per l'evidenziazione della riga alla posizione del cursore.", "lineHighlightBorderBox": "Colore di sfondo per il bordo intorno alla riga alla posizione del cursore.", + "rangeHighlight": "Colore di sfondo degli intervalli evidenziati, ad esempio dalle funzionalità Quick Open e Trova. il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", "caret": "Colore del cursore dell'editor.", "editorCursorBackground": "Colore di sfondo del cursore editor. Permette di personalizzare il colore di un carattere quando sovrapposto da un blocco cursore.", "editorWhitespaces": "Colore dei caratteri di spazio vuoto nell'editor.", diff --git a/i18n/ita/src/vs/editor/contrib/gotoError/gotoError.i18n.json b/i18n/ita/src/vs/editor/contrib/gotoError/gotoError.i18n.json index 505e8cba014..5fb4bad149e 100644 --- a/i18n/ita/src/vs/editor/contrib/gotoError/gotoError.i18n.json +++ b/i18n/ita/src/vs/editor/contrib/gotoError/gotoError.i18n.json @@ -5,6 +5,8 @@ // Do not edit this file. It is machine generated. { "title.wo_source": "({0}/{1})", + "markerAction.next.label": "Vai al problema successivo (Errore, Avviso, Informazioni)", + "markerAction.previous.label": "Vai al problema precedente (Errore, Avviso, Info)", "editorMarkerNavigationError": "Colore per gli errori del widget di spostamento tra marcatori dell'editor.", "editorMarkerNavigationWarning": "Colore per gli avvisi del widget di spostamento tra marcatori dell'editor.", "editorMarkerNavigationInfo": "Colore delle informazioni del widget di navigazione marcatori dell'editor.", diff --git a/i18n/ita/src/vs/editor/contrib/wordHighlighter/wordHighlighter.i18n.json b/i18n/ita/src/vs/editor/contrib/wordHighlighter/wordHighlighter.i18n.json index b355190a13b..b8a49a5af0b 100644 --- a/i18n/ita/src/vs/editor/contrib/wordHighlighter/wordHighlighter.i18n.json +++ b/i18n/ita/src/vs/editor/contrib/wordHighlighter/wordHighlighter.i18n.json @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "wordHighlight": "Colore di sfondo di un simbolo durante l'accesso in lettura, ad esempio durante la lettura di una variabile. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", + "wordHighlightStrong": "Colore di sfondo di un simbolo durante l'accesso in scrittura, per esempio durante la scrittura di una variabile. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", "overviewRulerWordHighlightForeground": "Colore del marcatore del righello delle annotazioni per le evidenziazioni dei simboli.", "overviewRulerWordHighlightStrongForeground": "Colore del marcatore del righello delle annotazioni per le evidenziazioni dei simboli di accesso in scrittura.", "wordHighlight.next.label": "Vai al prossimo simbolo evidenziato", diff --git a/i18n/ita/src/vs/platform/environment/node/argv.i18n.json b/i18n/ita/src/vs/platform/environment/node/argv.i18n.json index c1d35df0230..9dd58076c04 100644 --- a/i18n/ita/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/ita/src/vs/platform/environment/node/argv.i18n.json @@ -30,10 +30,13 @@ "inspect-extensions": "Consentire il debug e profiling delle estensioni. Controllare gli strumenti di sviluppo per l'uri di connessione.", "inspect-brk-extensions": "Consentire il debug e profiling delle estensioni con l'host di estensione in pausa dopo inizio. Controllare gli strumenti di sviluppo per l'uri di connessione.", "disableGPU": "Disabilita l'accelerazione hardware della GPU.", + "uploadLogs": "Caricamento dei log della sessione corrente verso un punto di comunicazione sicuro.", "usage": "Utilizzo", "options": "opzioni", "paths": "percorsi", "stdinWindows": "Per leggere l'output da un altro programma, aggiungere alla fine '-' (ad esempio 'echo Hello World | {0} -')", "stdinUnix": "Per leggere da stdin, aggiungere alla fine '-' (ad esempio 'ps aux | grep code | {0} -')", - "optionsUpperCase": "Opzioni" + "optionsUpperCase": "Opzioni", + "extensionsManagement": "Gestione delle estensioni", + "troubleshooting": "Risoluzione dei problemi" } \ No newline at end of file diff --git a/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index d13d2b8b626..973c52b94e0 100644 --- a/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -9,6 +9,7 @@ "installingOutdatedExtension": "Una versione più recente di questa estensione è già installata. Vuoi eseguire l'override di questa con la versione precedente?", "override": "Eseguire l'override", "cancel": "Annulla", + "errorInstallingDependencies": "Errore durante l'installazione delle dipendenze. {0}", "notFoundCompatible": "Impossibile installare '{0}'; non è presente alcuna versione compatibile con VS Code '{1}'.", "notFoundCompatibleDependency": "Impossibile installare perché non è stata trovata l'estensione dipendente '{0}' compatibile con la versione corrente '{1}' di VS Code.", "quitCode": "Impossibile installare l'estensione. Riavviare VS Code prima di procedere ad un nuovo setup.", diff --git a/i18n/ita/src/vs/platform/list/browser/listService.i18n.json b/i18n/ita/src/vs/platform/list/browser/listService.i18n.json new file mode 100644 index 00000000000..1866903b33e --- /dev/null +++ b/i18n/ita/src/vs/platform/list/browser/listService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "workbenchConfigurationTitle": "Area di lavoro" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/ita/src/vs/platform/theme/common/colorRegistry.i18n.json index 5375e34f3cb..28433311cf7 100644 --- a/i18n/ita/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/ita/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -63,7 +63,12 @@ "editorWidgetBorder": "Colore bordo dei widget dell'editor. Il colore viene utilizzato solo se il widget sceglie di avere un bordo e se il colore non è sottoposto a override da un widget.", "editorSelectionBackground": "Colore della selezione dell'editor.", "editorSelectionForeground": "Colore del testo selezionato per il contrasto elevato.", + "editorInactiveSelection": "Colore della selezione in un editor non attivo. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", + "editorSelectionHighlight": "Colore delle aree con lo stesso contenuto della selezione. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", "editorFindMatch": "Colore della corrispondenza di ricerca corrente.", + "findMatchHighlight": "Colore degli altri risultati della ricerca. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", + "findRangeHighlight": "Colore dell'intervallo limite della ricerca. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", + "hoverHighlight": "Evidenziazione sotto la parola per cui è visualizzata un'area sensibile al passaggio del mouse. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", "hoverBackground": "Colore di sfondo dell'area sensibile al passaggio del mouse dell'editor.", "hoverBorder": "Colore del bordo dell'area sensibile al passaggio del mouse dell'editor.", "activeLinkForeground": "Colore dei collegamenti attivi.", @@ -71,6 +76,12 @@ "diffEditorRemoved": "Colore di sfondo del testo che è stato rimosso.", "diffEditorInsertedOutline": "Colore del contorno del testo che è stato inserito.", "diffEditorRemovedOutline": "Colore del contorno del testo che è stato rimosso.", + "mergeCurrentHeaderBackground": "Sfondo intestazione corrente in conflitti di merge in linea. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", + "mergeCurrentContentBackground": "Sfondo contenuto corrente in conflitti di merge in linea. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", + "mergeIncomingHeaderBackground": "Sfondo intestazione modifica in ingresso in conflitti di merge in linea. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", + "mergeIncomingContentBackground": "Sfondo contenuto modifica in ingresso in conflitti di merge in linea. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", + "mergeCommonHeaderBackground": "Sfondo dell'intestazione dell'antenato comune nei conflitti di merge in linea. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", + "mergeCommonContentBackground": "Sfondo del contenuto dell'antenato comune nei conflitti di merge in linea. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.", "mergeBorder": "Colore bordo su intestazioni e sulla barra di divisione di conflitti di merge in linea.", "overviewRulerCurrentContentForeground": "Colore primo piano righello panoramica attuale per i conflitti di merge in linea.", "overviewRulerIncomingContentForeground": "Colore primo piano del righello panoramica modifiche in arrivo per i conflitti di merge in linea.", diff --git a/i18n/ita/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json b/i18n/ita/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json new file mode 100644 index 00000000000..c6ca6920d97 --- /dev/null +++ b/i18n/ita/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirestring": "la proprietà `{0}` è obbligatoria e deve essere di tipo `string`", + "optstring": "la proprietà `{0}` può essere omessa o deve essere di tipo `string`" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 7729690837e..250efcc3000 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -19,8 +19,6 @@ "vscode.extension.contributes.debuggers.configurationAttributes": "Configurazioni dello schema JSON per la convalida di 'launch.json'.", "vscode.extension.contributes.debuggers.windows": "Impostazioni specifiche di Windows.", "vscode.extension.contributes.debuggers.windows.runtime": "Runtime usato per Windows.", - "vscode.extension.contributes.debuggers.osx": "Impostazioni specifiche di OS X.", - "vscode.extension.contributes.debuggers.osx.runtime": "Runtime usato per OS X.", "vscode.extension.contributes.debuggers.linux": "Impostazioni specifiche di Linux.", "vscode.extension.contributes.debuggers.linux.runtime": "Runtime usato per Linux.", "vscode.extension.contributes.breakpoints": "Punti di interruzione per contributes.", diff --git a/i18n/ita/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json index b29d6b897b6..cd92af0e23c 100644 --- a/i18n/ita/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json @@ -14,7 +14,6 @@ "findInFiles": "Cerca nei file", "openAnythingHandlerDescription": "Vai al file", "openSymbolDescriptionNormal": "Vai al simbolo nell'area di lavoro", - "searchOutputChannelTitle": "Cerca", "searchConfigurationTitle": "Cerca", "exclude": "Consente di configurare i criteri GLOB per escludere file e cartelle nelle ricerche. Eredita tutti i criteri GLOB dall'impostazione files.exclude.", "exclude.boolean": "Criterio GLOB da usare per trovare percorsi file. Impostare su True o False per abilitare o disabilitare il criterio.", diff --git a/i18n/jpn/extensions/typescript/out/features/quickFixProvider.i18n.json b/i18n/jpn/extensions/typescript/out/features/quickFixProvider.i18n.json new file mode 100644 index 00000000000..4c0d77d1fd0 --- /dev/null +++ b/i18n/jpn/extensions/typescript/out/features/quickFixProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fixAllInFileLabel": "{0} (ファイルの中のすべてを修正する)" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json index 6d5f2ea1582..8a9677dc258 100644 --- a/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -40,9 +40,9 @@ "wordWrapColumn": "'editor.wordWrap' が 'wordWrapColumn' または 'bounded' の場合に、エディターの折り返し桁を制御します。", "wrappingIndent": "折り返し行のインデントを制御します。'none'、'same'、または 'indent' のいずれかを指定できます。", "mouseWheelScrollSensitivity": "マウス ホイール スクロール イベントの `deltaX` と `deltaY` で使用される乗数", - "multiCursorModifier.ctrlCmd": "Windows および Linux 上の `Control` と OSX 上の `Command` にマップします。", - "multiCursorModifier.alt": "Windows および Linux 上の `Alt` と OSX 上の `Option` にマップします。", - "multiCursorModifier": "マウスで複数のカーソルを追加するときに使用する修飾キーです。`ctrlCmd` は Windows および Linux 上の `Control` キーと OSX 上の `Command` キーにマップします。「定義に移動」や「リンクを開く」のマウス操作は、マルチカーソルの修飾キーと競合しないように適用されます。", + "multiCursorModifier.ctrlCmd": "Windows および Linux 上の `Control` キーと macOS 上の `Command` キーに割り当てます。", + "multiCursorModifier.alt": "Windows および Linux 上の `Alt` キーと macOS 上の `Option` キーに割り当てます。", + "multiCursorModifier": "マウスを使用して複数のカーソルを追加するときに使用する修飾キーです。`ctrlCmd` は Windows および Linux 上の `Control` キーと macOS 上の `Command` キーに割り当てます。「定義に移動」や「リンクを開く」のマウス操作は、マルチカーソルの修飾キーと競合しないように適用されます。", "quickSuggestions.strings": "文字列内でクイック候補を有効にします。", "quickSuggestions.comments": "コメント内でクイック候補を有効にします。", "quickSuggestions.other": "文字列およびコメント外でクイック候補を有効にします。", diff --git a/i18n/jpn/src/vs/platform/environment/node/argv.i18n.json b/i18n/jpn/src/vs/platform/environment/node/argv.i18n.json index 41c3e146387..ef9379487ec 100644 --- a/i18n/jpn/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/jpn/src/vs/platform/environment/node/argv.i18n.json @@ -31,6 +31,7 @@ "inspect-brk-extensions": "起動後に一時停止されている拡張ホストとの拡張機能のデバッグとプロファイリングを許可します。接続 URI を開発者ツールでチェックします。", "disableGPU": "GPU ハードウェア アクセラレータを無効にします。", "uploadLogs": "現在のセッションから安全なエンドポイントにログをアップロードします。", + "issue": "問題を報告します。", "usage": "使用法", "options": "オプション", "paths": "パス", diff --git a/i18n/jpn/src/vs/platform/list/browser/listService.i18n.json b/i18n/jpn/src/vs/platform/list/browser/listService.i18n.json new file mode 100644 index 00000000000..bebbbaf4486 --- /dev/null +++ b/i18n/jpn/src/vs/platform/list/browser/listService.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "workbenchConfigurationTitle": "ワークベンチ", + "multiSelectModifier.ctrlCmd": "Windows および Linux 上の `Control` キーと macOS 上の `Command` キーに割り当てます。", + "multiSelectModifier.alt": "Windows および Linux 上の `Alt` キーと macOS 上の `Option` キーに割り当てます。", + "multiSelectModifier": "(tたとえば、サポートしている場合、ツリーやリストで) マウスを使用して項目を複数選択するときに使用する修飾キーです。`ctrlCmd` は Windows および Linux 上の `Control` キーと macOS 上の `Command` に割り当てます。「横に開く」のマウス操作をサポートしている場合、複数選択の修飾キーと競合しないように適応されます。" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json b/i18n/jpn/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json new file mode 100644 index 00000000000..9178423f0e4 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "ローカリゼーションは配列にする必要があります", + "requirestring": " `{0}` プロパティは必須で、`string` 型でなければなりません", + "optstring": "`{0}` プロパティは省略するか、`string` 型にする必要があります", + "vscode.extension.contributes.localizations": "ローカリゼーションをエディターに提供します", + "vscode.extension.contributes.localizations.languageId": "表示文字列が翻訳される言語の id。", + "vscode.extension.contributes.localizations.languageName": "表示文字列が翻訳される言語名。", + "vscode.extension.contributes.localizations.translations": "提供されている言語のすべての翻訳ファイルを含むフォルダへの相対パス。" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/jpn/src/vs/workbench/electron-browser/actions.i18n.json index 68ba00974f3..2c9fa4def7f 100644 --- a/i18n/jpn/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/jpn/src/vs/workbench/electron-browser/actions.i18n.json @@ -29,6 +29,7 @@ "openRecent": "最近開いた項目…", "quickOpenRecent": "最近使用したものを開く...", "closeMessages": "通知メッセージを閉じる", + "openIssueReporter": "問題のレポーターを開く", "reportIssueInEnglish": "問題の報告", "reportPerformanceIssue": "パフォーマンスの問題のレポート", "keybindingsReference": "キーボード ショートカットの参照", diff --git a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 84777c482b2..ac2caf3a825 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -19,8 +19,8 @@ "vscode.extension.contributes.debuggers.configurationAttributes": "'launch.json' を検証するための JSON スキーマ構成。", "vscode.extension.contributes.debuggers.windows": "Windows 固有の設定。", "vscode.extension.contributes.debuggers.windows.runtime": "Windows で使用されるランタイム。", - "vscode.extension.contributes.debuggers.osx": "OS X 固有の設定。", - "vscode.extension.contributes.debuggers.osx.runtime": "OSX で使用されるランタイム。", + "vscode.extension.contributes.debuggers.osx": "macOS 固有の設定。", + "vscode.extension.contributes.debuggers.osx.runtime": "macOS で使用されるランタイム。", "vscode.extension.contributes.debuggers.linux": "Linux 固有の設定。", "vscode.extension.contributes.debuggers.linux.runtime": "Linux で使用されるランタイム。", "vscode.extension.contributes.breakpoints": "ブレークポイントを提供します。", diff --git a/i18n/jpn/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json b/i18n/jpn/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json index eb5578bf82e..e3313b2824f 100644 --- a/i18n/jpn/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json @@ -4,6 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "installingVSIXExtension": "VSIX から拡張機能をインストールしています...", + "installingMarketPlaceExtension": "マーケット プレースから拡張機能をインストールしています... ", + "uninstallingExtension": "拡張機能をアンインストールしています...", "enableDependeciesConfirmation": "'{0}' を有効にするとその依存関係も有効になります。続行しますか?", "enable": "はい", "doNotEnable": "いいえ", diff --git a/i18n/jpn/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json index 5253824e4bd..0a9eaace998 100644 --- a/i18n/jpn/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json @@ -14,7 +14,6 @@ "findInFiles": "フォルダーを指定して検索", "openAnythingHandlerDescription": "ファイルに移動する", "openSymbolDescriptionNormal": "ワークスペース内のシンボルへ移動", - "searchOutputChannelTitle": "検索", "searchConfigurationTitle": "検索", "exclude": "検索でファイルとフォルダーを除外するために glob パターンを構成します。files.exclude 設定からすべての glob パターンを継承します。", "exclude.boolean": "ファイル パスの照合基準となる glob パターン。これを true または false に設定すると、パターンがそれぞれ有効/無効になります。", diff --git a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index 189e87c799d..e264431a00f 100644 --- a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -13,6 +13,7 @@ "terminal.integrated.shellArgs.osx": "OS X 端末で使用するコマンド ライン引数。", "terminal.integrated.shell.windows": "Windows でターミナルが使用するシェルのパス。 Windows に同梱されているシェルを使用する場合 (cmd、PowerShell、または Bash on Ubuntu) 。", "terminal.integrated.shellArgs.windows": "Windows ターミナル上の場合に使用されるコマンド ライン引数。", + "terminal.integrated.macOptionIsMeta": "macOS のターミナルでは、オプション キーをメタ キーとして扱います。", "terminal.integrated.rightClickCopyPaste": "設定している場合、ターミナル内で右クリックしたときにコンテキスト メニューを表示させず、選択範囲がある場合はコピー、選択範囲がない場合は貼り付けの操作を行います。", "terminal.integrated.copyOnSelection": "設定した場合、ターミナルで選択しているテキストはクリップボードにコピーされます。", "terminal.integrated.fontFamily": "端末のフォント ファミリを制御します。既定値は editor.fontFamily になります。", diff --git a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 96aa73cab67..dfb2ffeb9e2 100644 --- a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -12,6 +12,7 @@ "workbench.action.terminal.selectAll": "すべて選択", "workbench.action.terminal.deleteWordLeft": "左の文字を削除", "workbench.action.terminal.deleteWordRight": "右の文字を削除", + "workbench.action.terminal.enterLineNavigationMode": "スクリーン リーダー移動モードにする", "workbench.action.terminal.new": "新しい統合ターミナルの作成", "workbench.action.terminal.new.short": "新しいターミナル", "workbench.action.terminal.newWorkspacePlaceholder": "新しいターミナルの作業ディレクトリを選択してください", diff --git a/i18n/kor/extensions/typescript/out/features/quickFixProvider.i18n.json b/i18n/kor/extensions/typescript/out/features/quickFixProvider.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/kor/extensions/typescript/out/features/quickFixProvider.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/kor/src/vs/editor/common/config/commonEditorConfig.i18n.json index 15922e98314..31de53acb3a 100644 --- a/i18n/kor/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/kor/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -40,9 +40,6 @@ "wordWrapColumn": "`editor.wordWrap`이 'wordWrapColumn' 또는 'bounded'인 경우 편집기의 열 줄 바꿈을 제어합니다.", "wrappingIndent": "줄 바꿈 행의 들여쓰기를 제어합니다. 'none', 'same' 또는 'indent' 중 하나일 수 있습니다.", "mouseWheelScrollSensitivity": "마우스 휠 스크롤 이벤트의 `deltaX` 및 `deltaY`에서 사용할 승수", - "multiCursorModifier.ctrlCmd": "Windows와 Linux의 'Control'을 OSX의 'Command'로 매핑합니다.", - "multiCursorModifier.alt": "Windows와 Linux의 'Alt'를 OSX의 'Option'으로 매핑합니다.", - "multiCursorModifier": "마우스로 여러 커서를 추가할 때 사용할 수정자입니다. `ctrlCmd`는 Windows와 Linux에서 `Control`로 매핑되고 OSX에서 `Command`로 매핑됩니다. Go To Definition 및 Open Link 마우스 제스처가 멀티커서 수정자와 충돌하지 않도록 조정됩니다.", "quickSuggestions.strings": "문자열 내에서 빠른 제안을 사용합니다.", "quickSuggestions.comments": "주석 내에서 빠른 제안을 사용합니다.", "quickSuggestions.other": "문자열 및 주석 외부에서 빠른 제안을 사용합니다.", diff --git a/i18n/kor/src/vs/platform/list/browser/listService.i18n.json b/i18n/kor/src/vs/platform/list/browser/listService.i18n.json new file mode 100644 index 00000000000..f1ae7883f32 --- /dev/null +++ b/i18n/kor/src/vs/platform/list/browser/listService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "workbenchConfigurationTitle": "워크벤치" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json b/i18n/kor/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json new file mode 100644 index 00000000000..31dbb01b8b0 --- /dev/null +++ b/i18n/kor/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirestring": "속성 `{0}`은(는) 필수이며 `string` 형식이어야 합니다.", + "optstring": "속성 `{0}`은(는) 생략할 수 있으며 `string` 형식이어야 합니다." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 0db91f83b2f..ba5ae3f8c3f 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -19,8 +19,6 @@ "vscode.extension.contributes.debuggers.configurationAttributes": "'launch.json'의 유효성 검사를 위한 JSON 스키마 구성입니다.", "vscode.extension.contributes.debuggers.windows": "Windows 특정 설정", "vscode.extension.contributes.debuggers.windows.runtime": "Windows에 사용되는 런타임입니다.", - "vscode.extension.contributes.debuggers.osx": "OS X 특정 설정입니다.", - "vscode.extension.contributes.debuggers.osx.runtime": "OSX에 사용되는 런타임입니다.", "vscode.extension.contributes.debuggers.linux": "Linux 특정 설정", "vscode.extension.contributes.debuggers.linux.runtime": "Linux에 사용되는 런타임입니다.", "vscode.extension.contributes.breakpoints": "중단점을 적용합니다.", diff --git a/i18n/kor/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json index bbdbfe77846..4233df18482 100644 --- a/i18n/kor/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json @@ -12,7 +12,6 @@ "findInFiles": "파일에서 찾기", "openAnythingHandlerDescription": "파일로 이동", "openSymbolDescriptionNormal": "작업 영역에서 기호로 이동", - "searchOutputChannelTitle": "검색", "searchConfigurationTitle": "검색", "exclude": "검색에서 파일 및 폴더를 제외하도록 GLOB 패턴을 구성합니다. files.exclude 설정에서 모든 GLOB 패턴을 상속합니다.", "exclude.boolean": "파일 경로를 일치시킬 GLOB 패턴입니다. 패턴을 사용하거나 사용하지 않도록 설정하려면 true 또는 false로 설정하세요.", diff --git a/i18n/ptb/extensions/git/package.i18n.json b/i18n/ptb/extensions/git/package.i18n.json index 670378da7f5..3f76d9389b0 100644 --- a/i18n/ptb/extensions/git/package.i18n.json +++ b/i18n/ptb/extensions/git/package.i18n.json @@ -60,6 +60,7 @@ "config.enableLongCommitWarning": "Se mensagens longas de confirmação devem ter aviso", "config.confirmSync": "Confirmar antes de sincronizar repositórios git", "config.countBadge": "Controla o contador de distintivos do git. 'todos' considera todas as alterações. 'rastreado' considera apenas as alterações controladas. 'desligado' desliga o contador.", + "config.checkoutType": "Controla quais tipos de ramos são listados quando executando `Checkout para... `. `todos` mostra todas as referências, `local` mostra apenas os ramos locais, `etiquetas` mostra apenas etiquetas e `remoto` mostra apenas os ramos remotos.", "config.ignoreLegacyWarning": "Ignora o aviso de Git legado", "config.ignoreMissingGitWarning": "Ignora o aviso quando Git não existir.", "config.ignoreLimitWarning": "Ignora o aviso quando houver muitas alterações em um repositório", diff --git a/i18n/ptb/extensions/typescript/out/features/quickFixProvider.i18n.json b/i18n/ptb/extensions/typescript/out/features/quickFixProvider.i18n.json new file mode 100644 index 00000000000..7e0ce09dfcd --- /dev/null +++ b/i18n/ptb/extensions/typescript/out/features/quickFixProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fixAllInFileLabel": "{0} (Reparar tudo no arquivo)" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/ptb/src/vs/editor/common/config/commonEditorConfig.i18n.json index 3e9436d02bf..3cb267503b9 100644 --- a/i18n/ptb/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/ptb/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -40,9 +40,9 @@ "wordWrapColumn": "Controla a coluna de quebra de linha do editor quando editor.wordWrap` é 'wordWrapColumn' ou 'bounded'.", "wrappingIndent": "Controla o recuo de linhas quebradas. Pode ser \"none\", \"same\" ou \"indent\".", "mouseWheelScrollSensitivity": "Um multiplicador a ser usado em \"deltaX\" e \"deltaY\" dos eventos de rolagem do botão de rolagem do mouse", - "multiCursorModifier.ctrlCmd": "Mapeia para 'Control' no Windows e Linux e 'Command' no OSX.", - "multiCursorModifier.alt": "Mapeia para 'Alt' em Windows e Linux e 'Option' em OSX.", - "multiCursorModifier": "O modificador a ser usado para adicionar vários cursores com o mouse. `ctrlCmd` mapeia 'Control' no Windows e Linux e 'Command' no OSX. Os gestos do mouse Ir para definição e Abrir Link irão adaptar-se tal maneira que eles não entrem em conflito com o modificador multicursor.", + "multiCursorModifier.ctrlCmd": "Mapeia para 'Control' no Windows e Linux e para 'Command' no macOS.", + "multiCursorModifier.alt": "Mapeia para 'Alt' em Windows e Linux e para 'Option' em macOS.", + "multiCursorModifier": "O modificador a ser usado para adicionar vários cursores com o mouse. `ctrlCmd` mapeia para 'Control' no Windows e Linux e para 'Command' no macOS. Os gestos do mouse Ir para definição e Abrir Link irão adaptar-se de forma que eles não entrem em conflito com o modificador multicursor.", "quickSuggestions.strings": "Habilitar sugestões rápidas dentro de strings.", "quickSuggestions.comments": "Habilitar sugestões rápidas dentro de comentários.", "quickSuggestions.other": "Habilitar sugestões rápidas fora de strings e comentários.", diff --git a/i18n/ptb/src/vs/platform/environment/node/argv.i18n.json b/i18n/ptb/src/vs/platform/environment/node/argv.i18n.json index 72fb01e6637..c7a8e620a99 100644 --- a/i18n/ptb/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/ptb/src/vs/platform/environment/node/argv.i18n.json @@ -31,6 +31,7 @@ "inspect-brk-extensions": "Permitir depuração e criação de perfil de extensões com o host de extensão em pausa após o início. Verifique as ferramentas do desenvolvedor para a conexão uri.", "disableGPU": "Desabilita aceleração de hardware da GPU.", "uploadLogs": "Envia os registros de atividade da sessão atual para um destino seguro.", + "issue": "Reportar um problema.", "usage": "Uso", "options": "opções", "paths": "caminhos", diff --git a/i18n/ptb/src/vs/platform/list/browser/listService.i18n.json b/i18n/ptb/src/vs/platform/list/browser/listService.i18n.json new file mode 100644 index 00000000000..f0c45d298c0 --- /dev/null +++ b/i18n/ptb/src/vs/platform/list/browser/listService.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "workbenchConfigurationTitle": "Área de Trabalho", + "multiSelectModifier.ctrlCmd": "Mapeia para 'Control' no Windows e Linux e para 'Command' no macOS.", + "multiSelectModifier.alt": "Mapeia para 'Alt' no Windows e Linux e 'Option' no macOS.", + "multiSelectModifier": "O modificador a ser usado para adicionar um item à múltiplas seleções com o mouse (por exemplo, em árvores e listas, se suportado) `ctrlCmd` mapeia para 'Control' no Windows e Linux e 'Command' no macOS. Os gestos do mouse para 'Abrir do Lado' - se suportado - irá adaptar-se de forma que eles não entrem em conflito com o modificador de múltiplas seleções." +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json b/i18n/ptb/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json new file mode 100644 index 00000000000..299a2d2ab1d --- /dev/null +++ b/i18n/ptb/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirestring": "a propriedade `{0}` é obrigatória e deve ser do tipo `string`", + "optstring": "a propriedade `{0}` é opcional ou deve ser do tipo `string`" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 3908acc5028..f196dbc34be 100644 --- a/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -19,8 +19,6 @@ "vscode.extension.contributes.debuggers.configurationAttributes": "Configurações de esquema JSON para validar 'launch.json'.", "vscode.extension.contributes.debuggers.windows": "Configurações específicas do Windows.", "vscode.extension.contributes.debuggers.windows.runtime": "Runtime usado para Windows.", - "vscode.extension.contributes.debuggers.osx": "Configurações específicas do OS X.", - "vscode.extension.contributes.debuggers.osx.runtime": "Runtime usado para o OS X.", "vscode.extension.contributes.debuggers.linux": "Configurações específicas do Linux.", "vscode.extension.contributes.debuggers.linux.runtime": "Runtime usado para o Linux.", "vscode.extension.contributes.breakpoints": "Contribui aos pontos de interrupção.", diff --git a/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index d532a7ba72e..9d1bc5a5312 100644 --- a/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -13,6 +13,8 @@ "reallyRecommendedExtensionPack": "O pacote de extensão '{0}' é recomendado para este tipo de arquivo.", "showRecommendations": "Mostrar Recomendações", "install": "Instalar", + "showLanguageExtensions": "A Loja tem extensões que podem ajudar com arquivos '.{0}'", + "searchMarketplace": "Pesquisar na Loja", "workspaceRecommended": "Este espaço de trabalho possui recomendações de extensão.", "installAll": "Instalar Tudo", "ignoreExtensionRecommendations": "Você quer ignorar todas as recomendações de extensão?", diff --git a/i18n/ptb/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json b/i18n/ptb/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json index 3ab045563d8..07aeb8dd560 100644 --- a/i18n/ptb/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.i18n.json @@ -4,6 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "installingVSIXExtension": "Instalando extensão do VSIX...", + "installingMarketPlaceExtension": "Instalando extensão da Loja...", + "uninstallingExtension": "Desinstalando extensão...", "enableDependeciesConfirmation": "Habilitando '{0}' também habilita suas dependências. Gostaria de continuar?", "enable": "Sim", "doNotEnable": "Não", diff --git a/i18n/ptb/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json index 1676173518c..d407ebde609 100644 --- a/i18n/ptb/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json @@ -14,7 +14,6 @@ "findInFiles": "Localizar nos Arquivos", "openAnythingHandlerDescription": "Ir para o Arquivo", "openSymbolDescriptionNormal": "Ir para o Símbolo em Área de Trabalho", - "searchOutputChannelTitle": "Pesquisar", "searchConfigurationTitle": "Pesquisar", "exclude": "Configure os padrões glob para excluir arquivos e pastas nas pesquisas. Herda todos os padrões glob da configuração files.exclude.", "exclude.boolean": "O padrão glob com o qual combinar os caminhos de arquivo. Defina para verdadeiro ou falso para habilitar ou desabilitar o padrão.", diff --git a/i18n/ptb/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/ptb/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index 5411c925e8d..76ee2be0031 100644 --- a/i18n/ptb/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -5,7 +5,7 @@ // Do not edit this file. It is machine generated. { "welcomePage.vscode": "Visual Studio Code", - "welcomePage.editingEvolved": "Edição evoluiu", + "welcomePage.editingEvolved": "Edição evoluída", "welcomePage.start": "Início", "welcomePage.newFile": "Novo arquivo", "welcomePage.openFolder": "Abrir pasta...", diff --git a/i18n/rus/extensions/typescript/out/features/quickFixProvider.i18n.json b/i18n/rus/extensions/typescript/out/features/quickFixProvider.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/rus/extensions/typescript/out/features/quickFixProvider.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/rus/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/rus/src/vs/editor/common/config/commonEditorConfig.i18n.json index acc13bcc696..9d201095183 100644 --- a/i18n/rus/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/rus/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -40,9 +40,6 @@ "wordWrapColumn": "Определяет столбец переноса редактора, если значение \"editor.wordWrap\" — \"wordWrapColumn\" или \"bounded\".", "wrappingIndent": "Управляет отступом строк с переносом по словам. Допустимые значения: \"none\", \"same\" или \"indent\".", "mouseWheelScrollSensitivity": "Множитель, используемый для параметров deltaX и deltaY событий прокрутки колесика мыши.", - "multiCursorModifier.ctrlCmd": "Соответствует клавише CTRL в Windows и Linux и клавише COMMAND в OS X.", - "multiCursorModifier.alt": "Соответствует клавише ALT в Windows и Linux и клавише OPTION в OS X.", - "multiCursorModifier": "Модификатор, который будет использоваться для добавления нескольких курсоров с помощью мыши. \"ctrlCmd\" соответствует клавише CTRL в Windows и Linux и клавише COMMAND в OS X. Жесты мыши \"Перейти к определению\" и \"Открыть ссылку\" будут изменены так, чтобы они не конфликтовали с несколькими курсорами.", "quickSuggestions.strings": "Разрешение кратких предложений в строках.", "quickSuggestions.comments": "Разрешение кратких предложений в комментариях.", "quickSuggestions.other": "Разрешение кратких предложений вне строк и комментариев.", diff --git a/i18n/rus/src/vs/platform/list/browser/listService.i18n.json b/i18n/rus/src/vs/platform/list/browser/listService.i18n.json new file mode 100644 index 00000000000..933a96a0d6f --- /dev/null +++ b/i18n/rus/src/vs/platform/list/browser/listService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "workbenchConfigurationTitle": "Рабочее место" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json b/i18n/rus/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json new file mode 100644 index 00000000000..16bdf1f2fc4 --- /dev/null +++ b/i18n/rus/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirestring": "свойство \"{0}\" является обязательным и должно иметь тип string", + "optstring": "свойство \"{0}\" может быть опущено или должно иметь тип string" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 63d876aca0d..c98dad92f14 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -19,8 +19,6 @@ "vscode.extension.contributes.debuggers.configurationAttributes": "Конфигурации схемы JSON для проверки launch.json.", "vscode.extension.contributes.debuggers.windows": "Параметры, связанные с Windows.", "vscode.extension.contributes.debuggers.windows.runtime": "Среда выполнения, используемая для Windows.", - "vscode.extension.contributes.debuggers.osx": "Параметры, связанные с OS X.", - "vscode.extension.contributes.debuggers.osx.runtime": "Среда выполнения, используемая для OS X.", "vscode.extension.contributes.debuggers.linux": "Параметры, связанные с Linux.", "vscode.extension.contributes.debuggers.linux.runtime": "Среда выполнения, используемая для Linux.", "vscode.extension.contributes.breakpoints": "Добавляет точки останова.", diff --git a/i18n/rus/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json index e2ad0465583..ad29f26eb2e 100644 --- a/i18n/rus/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json @@ -12,7 +12,6 @@ "findInFiles": "Найти в файлах", "openAnythingHandlerDescription": "Перейти к файлу", "openSymbolDescriptionNormal": "Перейти к символу в рабочей области", - "searchOutputChannelTitle": "Поиск", "searchConfigurationTitle": "Поиск", "exclude": "Настройте стандартные маски для исключения файлов и папок при поиске. Все стандартные маски наследуются от параметра file.exclude.", "exclude.boolean": "Стандартная маска, соответствующая путям к файлам. Задайте значение true или false, чтобы включить или отключить маску.", diff --git a/i18n/trk/extensions/git/out/commands.i18n.json b/i18n/trk/extensions/git/out/commands.i18n.json index 1f602af17de..3e01d946db5 100644 --- a/i18n/trk/extensions/git/out/commands.i18n.json +++ b/i18n/trk/extensions/git/out/commands.i18n.json @@ -74,6 +74,7 @@ "push with tags success": "Başarılı bir şekilde etiketlerle gönderildi.", "pick remote": "'{0}' dalının yayınlanacağı bir uzak uçbirim seçin:", "sync is unpredictable": "Bu eylem, '{0}' esas projesine commitleri gönderecek ve alacaktır.", + "never again": "Tamam, Tekrar Gösterme", "no remotes to publish": "Deponuzda yayınlamanın yapılacağı hiçbir uzak uçbirim yapılandırılmamış.", "no changes stash": "Geçici olarak saklanacak bir değişiklik yok.", "provide stash message": "İsteğe bağlı olarak bir geçici olarak saklama mesajı belirtin", diff --git a/i18n/trk/extensions/git/package.i18n.json b/i18n/trk/extensions/git/package.i18n.json index 193dcf3dff8..7e10d7b3dae 100644 --- a/i18n/trk/extensions/git/package.i18n.json +++ b/i18n/trk/extensions/git/package.i18n.json @@ -60,6 +60,7 @@ "config.enableLongCommitWarning": "Uzun commit mesajları hakkında uyarıda bulunulup bulunulmayacağı", "config.confirmSync": "Git depolarını senkronize etmeden önce onaylayın", "config.countBadge": "Git gösterge sayacını denetler. `all` tüm değişiklikleri sayar. `tracked` sadece izlenen değişikliklikleri sayar. `off` ise kapatır.", + "config.checkoutType": "`Geçiş Yap...` çalıştırılırken listelenecek dal türlerini denetler. `all` tüm başvuruları gösterir, `local` sadece yerel dalları gösterir, `tags` sadece etiketleri gösterir ve `remote` sadece uzak uçbirim dallarını gösterir.", "config.ignoreLegacyWarning": "Eski Git uyarısını görmezden gelir", "config.ignoreMissingGitWarning": "Git mevcut olmadığında uyarıyı yok sayar", "config.ignoreLimitWarning": "Bir depoda çok fazla değişiklik var uyarısını görmezden gelir", diff --git a/i18n/trk/extensions/typescript/out/features/quickFixProvider.i18n.json b/i18n/trk/extensions/typescript/out/features/quickFixProvider.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/trk/extensions/typescript/out/features/quickFixProvider.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/trk/src/vs/base/node/ps.i18n.json b/i18n/trk/src/vs/base/node/ps.i18n.json index 8b6ad71cd4e..1ecdfb5a807 100644 --- a/i18n/trk/src/vs/base/node/ps.i18n.json +++ b/i18n/trk/src/vs/base/node/ps.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "collecting": "CPU ve bellek bilgisi toplanıyor. Bu işlem birkaç saniye sürebilir." +} \ No newline at end of file diff --git a/i18n/trk/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/trk/src/vs/editor/common/config/commonEditorConfig.i18n.json index d00cee8579f..0987f2e64af 100644 --- a/i18n/trk/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/trk/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -40,9 +40,9 @@ "wordWrapColumn": "`editor.wordWrap` ögesi, 'wordWrapColumn' veya 'bounded' iken düzenleyicinin kaydırma sütununu denetler.", "wrappingIndent": "Kaydırılan satır girintisini denetler. 'none', 'same' veya 'indent' değerlerinden biri olabilir.", "mouseWheelScrollSensitivity": "Fare tekerleği kaydırma olaylarında `deltaX` ve `deltaY` üzerinde kullanılan bir çarpan", - "multiCursorModifier.ctrlCmd": "Windows ve Linux'da `Control` ve OSX'de `Command` ile eşleşir.", - "multiCursorModifier.alt": "Windows ve Linux'da `Alt` ve OSX'de `Option` ile eşleşir.", - "multiCursorModifier": "Fare ile birden çok imleç eklenmesinde kullanılacak değiştirici. `ctrlCmd` Windows ve Linux'da `Control` ve OSX'de `Command` ile eşleşir. Tanıma Git ve Bağlantıyı Aç fare hareketleri, birden çok imleç değiştiricisi ile çakışmayacak şekilde uyum sağlarlar.", + "multiCursorModifier.ctrlCmd": "Windows ve Linux'da `Control` ve macOS'de `Command` ile eşleşir.", + "multiCursorModifier.alt": "Windows ve Linux'da `Alt` ve macOS'de `Option` ile eşleşir.", + "multiCursorModifier": "Fare ile birden çok imleç eklenmesinde kullanılacak değiştirici. `ctrlCmd` Windows ve Linux'da `Control` ve macOS'de `Command` ile eşleşir. Tanıma Git ve Bağlantıyı Aç fare hareketleri, birden çok imleç değiştiricisi ile çakışmayacak şekilde uyum sağlarlar.", "quickSuggestions.strings": "Dizelerin içinde hızlı önerileri etkinleştir.", "quickSuggestions.comments": "Yorumların içinde hızlı önerileri etkinleştir.", "quickSuggestions.other": "Dizeler ve yorumlar dışında hızlı önerileri etkinleştirin.", diff --git a/i18n/trk/src/vs/editor/contrib/gotoError/gotoError.i18n.json b/i18n/trk/src/vs/editor/contrib/gotoError/gotoError.i18n.json index b9f1dd5ddfd..47acac3ba2a 100644 --- a/i18n/trk/src/vs/editor/contrib/gotoError/gotoError.i18n.json +++ b/i18n/trk/src/vs/editor/contrib/gotoError/gotoError.i18n.json @@ -5,6 +5,8 @@ // Do not edit this file. It is machine generated. { "title.wo_source": "({0}/{1})", + "markerAction.next.label": "Sonraki Soruna Git (Hata, Uyarı, Bilgi)", + "markerAction.previous.label": "Önceki Soruna Git (Hata, Uyarı, Bilgi)", "editorMarkerNavigationError": "Düzenleyicinin işaretçi gezinti aracının hata rengi.", "editorMarkerNavigationWarning": "Düzenleyicinin işaretçi gezinti aracının uyarı rengi.", "editorMarkerNavigationInfo": "Düzenleyicinin işaretçi gezinti aracının bilgilendirme rengi.", diff --git a/i18n/trk/src/vs/platform/environment/node/argv.i18n.json b/i18n/trk/src/vs/platform/environment/node/argv.i18n.json index 6838345e4f9..c0a53eb4448 100644 --- a/i18n/trk/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/trk/src/vs/platform/environment/node/argv.i18n.json @@ -30,6 +30,7 @@ "inspect-extensions": "Eklentilerde hata ayıklama ve ayrımlamaya izin ver. Bağlantı URI'ı için geliştirici araçlarını kontrol edin.", "inspect-brk-extensions": "Eklentilerde hata ayıklama ve ayrımlamaya eklenti sunucusu başladıktan hemen sonra duraklatılacak şekilde izin ver. Bağlantı URI'ı için geliştirici araçlarını kontrol edin.", "disableGPU": "GPU donanım hızlandırmasını devre dışı bırak.", + "issue": "Sorun bildirin.", "usage": "Kullanım", "options": "seçenekler", "paths": "yollar", diff --git a/i18n/trk/src/vs/platform/list/browser/listService.i18n.json b/i18n/trk/src/vs/platform/list/browser/listService.i18n.json new file mode 100644 index 00000000000..9f083e8ed4a --- /dev/null +++ b/i18n/trk/src/vs/platform/list/browser/listService.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "workbenchConfigurationTitle": "Çalışma Ekranı", + "multiSelectModifier.ctrlCmd": "Windows ve Linux'da `Control` ve macOS'de `Command` ile eşleşir.", + "multiSelectModifier.alt": "Windows ve Linux'da `Alt` ve macOS'de `Option` ile eşleşir." +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json b/i18n/trk/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json new file mode 100644 index 00000000000..0ca04fc5f49 --- /dev/null +++ b/i18n/trk/src/vs/workbench/api/browser/localizationsExtensionPoint.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirestring": "`{0}` özelliği zorunludur ve `string` türünde olmalıdır", + "optstring": "`{0}` özelliği atlanabilir veya `string` türünde olmalıdır" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index ea94460b89a..bd924b59861 100644 --- a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -19,8 +19,6 @@ "vscode.extension.contributes.debuggers.configurationAttributes": "'launch.json' dosyasını doğrulayacak JSON şema yapılandırmaları.", "vscode.extension.contributes.debuggers.windows": "Windows'a özel ayarlar.", "vscode.extension.contributes.debuggers.windows.runtime": "Windows'da kullanılacak çalışma zamanı.", - "vscode.extension.contributes.debuggers.osx": "OS X'e özel ayarlar.", - "vscode.extension.contributes.debuggers.osx.runtime": "OS X'de kullanılacak çalışma zamanı.", "vscode.extension.contributes.debuggers.linux": "Linux'a özel ayarlar.", "vscode.extension.contributes.debuggers.linux.runtime": "Linux'da kullanılacak çalışma zamanı.", "vscode.extension.contributes.breakpoints": "Kesme noktalarına ekleme yapar.", diff --git a/i18n/trk/src/vs/workbench/parts/feedback/electron-browser/feedbackStatusbarItem.i18n.json b/i18n/trk/src/vs/workbench/parts/feedback/electron-browser/feedbackStatusbarItem.i18n.json index 8b6ad71cd4e..f2a7a6f5dc4 100644 --- a/i18n/trk/src/vs/workbench/parts/feedback/electron-browser/feedbackStatusbarItem.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/feedback/electron-browser/feedbackStatusbarItem.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "hide": "Gizle" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/logs/electron-browser/logs.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/logs/electron-browser/logs.contribution.i18n.json index aeb7121cb05..d1c3589857b 100644 --- a/i18n/trk/src/vs/workbench/parts/logs/electron-browser/logs.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/logs/electron-browser/logs.contribution.i18n.json @@ -4,5 +4,8 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "mainLog": "Günlük (Temel)", + "sharedLog": "Günlük (Ortak)", + "rendererLog": "Günlük (Pencere)", "developer": "Geliştirici" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/logs/electron-browser/logsActions.i18n.json b/i18n/trk/src/vs/workbench/parts/logs/electron-browser/logsActions.i18n.json index ad7b602e907..06c087ca4a9 100644 --- a/i18n/trk/src/vs/workbench/parts/logs/electron-browser/logsActions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/logs/electron-browser/logsActions.i18n.json @@ -6,6 +6,8 @@ { "openLogsFolder": "Günlük Klasörünü Aç", "showLogs": "Günlükleri Göster...", + "mainProcess": "Temel", + "sharedProcess": "Ortak", "rendererProcess": "Pencere", "extensionHost": "Eklenti Sunucusu", "selectProcess": "İşlem seçin", diff --git a/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index 06bd99d62b1..137024a0daf 100644 --- a/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -7,5 +7,6 @@ "toggleGitViewlet": "Git'i Göster", "source control": "Kaynak Kontrolü", "toggleSCMViewlet": "SCM'yi Göster", - "view": "Görüntüle" + "view": "Görüntüle", + "scmConfigurationTitle": "SCM" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json index 58d2149f726..5643091fd7a 100644 --- a/i18n/trk/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/search/electron-browser/search.contribution.i18n.json @@ -14,7 +14,6 @@ "findInFiles": "Dosyalarda Bul", "openAnythingHandlerDescription": "Dosyaya Git", "openSymbolDescriptionNormal": "Çalışma Alanında Sembole Git", - "searchOutputChannelTitle": "Ara", "searchConfigurationTitle": "Ara", "exclude": "Aramalarda dosyaları ve klasörleri hariç tutmak için glob desenlerini yapılandırın. files.exclude ayarından, tüm glob desenlerini devralır.", "exclude.boolean": "Dosya yollarının eşleştirileceği glob deseni. Deseni etkinleştirmek veya devre dışı bırakmak için true veya false olarak ayarlayın.", diff --git a/package.json b/package.json index 5079c68d462..bfd9b7a1eb9 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "gulp": "gulp --max_old_space_size=4096", "7z": "7z", "update-grammars": "node build/npm/update-all-grammars.js", + "update-localization-extension": "node build/npm/update-localization-extension.js", "smoketest": "cd test/smoke && mocha" }, "dependencies": { @@ -45,7 +46,7 @@ "vscode-debugprotocol": "1.25.0", "vscode-ripgrep": "^0.7.1-patch.0", "vscode-textmate": "^3.2.0", - "vscode-xterm": "3.1.0-beta10", + "vscode-xterm": "3.1.0-beta11", "yauzl": "2.8.0" }, "devDependencies": { @@ -115,7 +116,7 @@ "vinyl": "^0.4.5", "vinyl-fs": "^2.4.3", "vsce": "1.33.2", - "vscode-nls-dev": "^2.0.1" + "vscode-nls-dev": "^3.0.5" }, "repository": { "type": "git", diff --git a/src/bootstrap-amd.js b/src/bootstrap-amd.js index b5e142fca8e..8b91b77b671 100644 --- a/src/bootstrap-amd.js +++ b/src/bootstrap-amd.js @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ var path = require('path'); +var fs = require('fs'); var loader = require('./vs/loader'); function uriFromPath(_path) { @@ -16,9 +17,40 @@ function uriFromPath(_path) { return encodeURI('file://' + pathName); } +function readFile(file) { + return new Promise(function(resolve, reject) { + fs.readFile(file, 'utf8', function(err, data) { + if (err) { + reject(err); + return; + } + resolve(data); + }); + }); +} + var rawNlsConfig = process.env['VSCODE_NLS_CONFIG']; var nlsConfig = rawNlsConfig ? JSON.parse(rawNlsConfig) : { availableLanguages: {} }; +// We have a special location of the nls files. They come from a language pack +if (nlsConfig._resolvedLanguagePackCoreLocation) { + let bundles = Object.create(null); + nlsConfig.loadBundle = function(bundle, language, cb) { + let result = bundles[bundle]; + if (result) { + cb(undefined, result); + return; + } + let bundleFile = path.join(nlsConfig._resolvedLanguagePackCoreLocation, bundle.replace(/\//g, '!') + '.nls.json'); + readFile(bundleFile).then(function (content) { + let json = JSON.parse(content); + bundles[bundle] = json; + cb(undefined, json); + }) + .catch(cb); + }; +} + loader.config({ baseUrl: uriFromPath(__dirname), catchError: true, diff --git a/src/main.js b/src/main.js index 6e29b5203a6..127e6500797 100644 --- a/src/main.js +++ b/src/main.js @@ -2,44 +2,41 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ - 'use strict'; -var perf = require('./vs/base/common/performance'); +let perf = require('./vs/base/common/performance'); perf.mark('main:started'); // Perf measurements global.perfStartTime = Date.now(); -var app = require('electron').app; -var fs = require('fs'); -var path = require('path'); -var minimist = require('minimist'); -var paths = require('./paths'); +let app = require('electron').app; +let fs = require('fs'); +let path = require('path'); +let minimist = require('minimist'); +let paths = require('./paths'); -var args = minimist(process.argv, { +let args = minimist(process.argv, { string: ['user-data-dir', 'locale'] }); function stripComments(content) { - var regexp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g; - var result = content.replace(regexp, function (match, m1, m2, m3, m4) { + let regexp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g; + let result = content.replace(regexp, function (match, m1, m2, m3, m4) { // Only one of m1, m2, m3, m4 matches if (m3) { // A block comment. Replace with nothing return ''; - } - else if (m4) { + } else if (m4) { // A line comment. If it ends in \r?\n then keep it. - var length_1 = m4.length; + let length_1 = m4.length; if (length_1 > 2 && m4[length_1 - 1] === '\n') { return m4[length_1 - 2] === '\r' ? '\r\n' : '\n'; } else { return ''; } - } - else { + } else { // We match a string return match; } @@ -47,71 +44,309 @@ function stripComments(content) { return result; } -function getNLSConfiguration() { - var locale = args['locale']; +let _commit; +function getCommit() { + if (_commit) { + return _commit; + } + if (_commit === null) { + return undefined; + } + try { + let productJson = require(path.join(__dirname, '../product.json')); + if (productJson.commit) { + _commit = productJson.commit; + } else { + _commit = null; + } + } catch (exp) { + _commit = null; + } +} - if (!locale) { - var userData = app.getPath('userData'); - var localeConfig = path.join(userData, 'User', 'locale.json'); - if (fs.existsSync(localeConfig)) { - try { - var content = stripComments(fs.readFileSync(localeConfig, 'utf8')); - var value = JSON.parse(content).locale; - if (value && typeof value === 'string') { - locale = value; +function mkdirp(dir) { + return mkdir(dir) + .then(null, (err) => { + if (err && err.code === 'ENOENT') { + let parent = path.dirname(dir); + if (parent !== dir) { // if not arrived at root + return mkdirp(parent) + .then(() => { + return mkdir(dir); + }); + } + } + throw err; + }); +} + +function mkdir(dir) { + return new Promise((resolve, reject) => { + fs.mkdir(dir, (err) => { + if (err && err.code !== 'EEXIST') { + reject(err); + } else { + resolve(dir); + } + }); + }); +} + +function exists(file) { + return new Promise((resolve) => { + fs.exists(file, (result) => { + resolve(result); + }); + }); +} + +function readFile(file) { + return new Promise((resolve, reject) => { + fs.readFile(file, 'utf8', (err, data) => { + if (err) { + reject(err); + return; + } + resolve(data); + }); + }); +} + +function writeFile(file, content) { + return new Promise((resolve, reject) => { + fs.writeFile(file, content, 'utf8', (err) => { + if (err) { + reject(err); + return; + } + resolve(undefined); + }); + }); +} + +function touch(file) { + return new Promise((resolve, reject) => { + let d = new Date(); + fs.utimes(file, d, d, (err) => { + if (err) { + reject(err); + return; + } + resolve(undefined); + }); + }); +} + +// Language tags are case insensitve however an amd loader is case sensitive +// To make this work on case preserving & insensitive FS we do the following: +// the language bundles have lower case language tags and we always lower case +// the locale we receive from the user or OS. + +function getUserDefinedLocale() { + let locale = args['locale']; + if (locale) { + return Promise.resolve(locale.toLowerCase()); + } + + let userData = app.getPath('userData'); + let localeConfig = path.join(userData, 'User', 'locale.json'); + return exists(localeConfig).then((result) => { + if (result) { + return readFile(localeConfig).then((content) => { + content = stripComments(content); + try { + let value = JSON.parse(content).locale; + return value && typeof value === 'string' ? value.toLowerCase() : undefined; + } catch (e) { + return undefined; + } + }); + } else { + return undefined; + } + }); +} + +function getLanguagePackConfigurations() { + let userData = app.getPath('userData'); + let configFile = path.join(userData, 'languagepacks.json'); + try { + return require(configFile); + } catch (err) { + // Do nothing. If we can't read the file we have no + // language pack config. + } + return undefined; +} + +function resolveLanguagePackLocale(config, locale) { + try { + while (locale) { + if (config[locale]) { + return locale; + } else { + let index = locale.lastIndexOf('-'); + if (index > 0) { + locale = locale.substring(0, index); + } else { + return undefined; } - } catch (e) { - // noop } } + } catch (err) { + console.error('Resolving language pack configuration failed.', err); + } + return undefined; +} + +function getNLSConfiguration(locale) { + if (locale === 'pseudo') { + return Promise.resolve({ locale: locale, availableLanguages: {}, pseudo: true }); } - var appLocale = app.getLocale(); - locale = locale || appLocale; - // Language tags are case insensitve however an amd loader is case sensitive - // To make this work on case preserving & insensitive FS we do the following: - // the language bundles have lower case language tags and we always lower case - // the locale we receive from the user or OS. - locale = locale ? locale.toLowerCase() : locale; - if (locale === 'pseudo') { - return { locale: locale, availableLanguages: {}, pseudo: true }; - } - var initialLocale = locale; if (process.env['VSCODE_DEV']) { - return { locale: locale, availableLanguages: {} }; + return Promise.resolve({ locale: locale, availableLanguages: {} }); } + let userData = app.getPath('userData'); + // We have a built version so we have extracted nls file. Try to find // the right file to use. // Check if we have an English locale. If so fall to default since that is our // English translation (we don't ship *.nls.en.json files) if (locale && (locale == 'en' || locale.startsWith('en-'))) { - return { locale: locale, availableLanguages: {} }; + return Promise.resolve({ locale: locale, availableLanguages: {} }); } + let initialLocale = locale; + function resolveLocale(locale) { while (locale) { - var candidate = path.join(__dirname, 'vs', 'code', 'electron-main', 'main.nls.') + locale + '.js'; + let candidate = path.join(__dirname, 'vs', 'code', 'electron-main', 'main.nls.') + locale + '.js'; if (fs.existsSync(candidate)) { return { locale: initialLocale, availableLanguages: { '*': locale } }; } else { - var index = locale.lastIndexOf('-'); + let index = locale.lastIndexOf('-'); if (index > 0) { locale = locale.substring(0, index); } else { - locale = null; + locale = undefined; } } } - return null; + return undefined; } - var resolvedLocale = resolveLocale(locale); - if (!resolvedLocale && appLocale && appLocale !== locale) { - resolvedLocale = resolveLocale(appLocale); + let isCoreLangaguage = true; + if (locale) { + isCoreLangaguage = ['de', 'es', 'fr', 'it', 'ja', 'ko', 'ru', 'tr', 'zh-cn', 'zh-tw'].some((language) => { + return locale === language || locale.startsWith(language + '-'); + }); + } + + if (isCoreLangaguage) { + return Promise.resolve(resolveLocale(locale)); + } else { + perf.mark('nlsGeneration:start'); + let defaultResult = function() { + perf.mark('nlsGeneration:end'); + return Promise.resolve({ locale: locale, availableLanguages: {} }); + }; + try { + let commit = getCommit(); + if (!commit) { + return defaultResult(); + } + let configs = getLanguagePackConfigurations(); + if (!configs) { + return defaultResult(); + } + let initialLocale = locale; + locale = resolveLanguagePackLocale(configs, locale); + if (!locale) { + return defaultResult(); + } + let packConfigs = configs[locale]; + if (!packConfigs || !Array.isArray(packConfigs) || packConfigs.length === 0) { + return defaultResult(); + } + // We take the first install language pack. No idea what to do if we have more + // than one :-) + let packConfig = packConfigs[0]; + if (typeof packConfig.translations !== 'string' || typeof packConfig.version !== 'string' || packConfig.version.match(/\d+\.\d+\.\d+/) === null) { + return defaultResult(); + } + return exists(packConfig.translations).then((fileExists) => { + if (!fileExists) { + return defaultResult(); + } + let packId = packConfig.extensionIdentifier.id + '-' + packConfig.version; + let cacheRoot = path.join(userData, 'clp', packId); + let coreLocation = path.join(cacheRoot, commit); + let result = { + locale: initialLocale, + availableLanguages: { '*': locale }, + _languagePackId: packId, + _languagePackLocation: packConfig.translations, + _cacheRoot: cacheRoot, + _resolvedLanguagePackCoreLocation: coreLocation + }; + return exists(coreLocation).then((fileExists) => { + if (fileExists) { + // We don't wait for this. No big harm if we can't touch + touch(coreLocation).catch(() => {}); + perf.mark('nlsGeneration:end'); + return result; + } + return mkdirp(coreLocation).then(() => { + return Promise.all([readFile(path.join(__dirname, 'nls.metadata.json')), readFile(path.join(packConfig.translations, 'main.i18n.json'))]); + }).then((values) => { + let metadata = JSON.parse(values[0]); + let packData = JSON.parse(values[1]).contents; + let bundles = Object.keys(metadata.bundles); + let writes = []; + for (let bundle of bundles) { + let modules = metadata.bundles[bundle]; + let target = Object.create(null); + for (let module of modules) { + let keys = metadata.keys[module]; + let defaultMessages = metadata.messages[module]; + let translations = packData[module]; + let targetStrings; + if (translations) { + targetStrings = []; + for (let i = 0; i < keys.length; i++) { + let elem = keys[i]; + let key = typeof elem === 'string' ? elem : elem.key; + let translatedMessage = translations[key]; + if (translatedMessage === undefined) { + translatedMessage = defaultMessages[i]; + } + targetStrings.push(translatedMessage); + } + } else { + targetStrings = defaultMessages; + } + target[module] = targetStrings; + } + writes.push(writeFile(path.join(coreLocation, bundle.replace(/\//g,'!') + '.nls.json'), JSON.stringify(target))); + } + return Promise.all(writes); + }).then(() => { + perf.mark('nlsGeneration:end'); + return result; + }).catch((err) => { + console.error('Generating translation files failed.', err); + return defaultResult(); + }); + }); + }); + } catch (err) { + console.error('Generating translation files failed.', err); + return defaultResult(); + } } - return resolvedLocale ? resolvedLocale : { locale: initialLocale, availableLanguages: {} }; } function getNodeCachedDataDir() { @@ -126,52 +361,24 @@ function getNodeCachedDataDir() { } // find commit id - var productJson = require(path.join(__dirname, '../product.json')); - if (!productJson.commit) { + let commit = getCommit(); + if (!commit) { return Promise.resolve(undefined); } - var dir = path.join(app.getPath('userData'), 'CachedData', productJson.commit); + let dir = path.join(app.getPath('userData'), 'CachedData', commit); return mkdirp(dir).then(undefined, function () { /*ignore*/ }); } -function mkdirp(dir) { - return mkdir(dir) - .then(null, function (err) { - if (err && err.code === 'ENOENT') { - var parent = path.dirname(dir); - if (parent !== dir) { // if not arrived at root - return mkdirp(parent) - .then(function () { - return mkdir(dir); - }); - } - } - throw err; - }); -} - -function mkdir(dir) { - return new Promise(function (resolve, reject) { - fs.mkdir(dir, function (err) { - if (err && err.code !== 'EEXIST') { - reject(err); - } else { - resolve(dir); - } - }); - }); -} - // Set userData path before app 'ready' event and call to process.chdir -var userData = path.resolve(args['user-data-dir'] || paths.getDefaultUserDataPath(process.platform)); +let userData = path.resolve(args['user-data-dir'] || paths.getDefaultUserDataPath(process.platform)); app.setPath('userData', userData); // Update cwd based on environment and platform try { if (process.platform === 'win32') { - process.env['VSCODE_CWD'] = process.cwd(); // remember as environment variable + process.env['VSCODE_CWD'] = process.cwd(); // remember as environment letiable process.chdir(path.dirname(app.getPath('exe'))); // always set application folder as cwd } else if (process.env['VSCODE_CWD']) { process.chdir(process.env['VSCODE_CWD']); @@ -187,8 +394,8 @@ app.on('open-file', function (event, path) { global.macOpenFiles.push(path); }); -var openUrls = []; -var onOpenUrl = function (event, url) { +let openUrls = []; +let onOpenUrl = function (event, url) { event.preventDefault(); openUrls.push(url); }; @@ -205,7 +412,7 @@ global.getOpenUrls = function () { // use '/CachedData'-directory to store // node/v8 cached data. -var nodeCachedDataDir = getNodeCachedDataDir().then(function (value) { +let nodeCachedDataDir = getNodeCachedDataDir().then(function (value) { if (value) { // store the data directory process.env['VSCODE_NODE_CACHED_DATA_DIR_' + process.pid] = value; @@ -214,15 +421,56 @@ var nodeCachedDataDir = getNodeCachedDataDir().then(function (value) { // but because we generate cached data it makes subsequent startups much faster app.commandLine.appendSwitch('--js-flags', '--nolazy'); } + return value; +}); + +let nlsConfiguration = undefined; +let userDefinedLocale = getUserDefinedLocale(); +userDefinedLocale.then((locale) => { + if (locale && !nlsConfiguration) { + nlsConfiguration = getNLSConfiguration(locale); + } }); // Load our code once ready app.once('ready', function () { perf.mark('main:appReady'); - var nlsConfig = getNLSConfiguration(); - process.env['VSCODE_NLS_CONFIG'] = JSON.stringify(nlsConfig); - - nodeCachedDataDir.then(function () { - require('./bootstrap-amd').bootstrap('vs/code/electron-main/main'); + Promise.all([nodeCachedDataDir, userDefinedLocale]).then((values) => { + let locale = values[1]; + if (locale && !nlsConfiguration) { + nlsConfiguration = getNLSConfiguration(locale); + } + if (!nlsConfiguration) { + nlsConfiguration = Promise.resolve(undefined); + } + // We first need to test a user defined locale. If it fails we try the app locale. + // If that fails we fall back to English. + nlsConfiguration.then((nlsConfig) => { + let boot = (nlsConfig) => { + process.env['VSCODE_NLS_CONFIG'] = JSON.stringify(nlsConfig); + require('./bootstrap-amd').bootstrap('vs/code/electron-main/main'); + }; + // We recevied a valid nlsConfig from a user defined locale + if (nlsConfig) { + boot(nlsConfig); + } else { + // Try to use the app locale. Please note that the app locale is only + // valid after we have received the app ready event. This is why the + // code is here. + let appLocale = app.getLocale(); + if (!appLocale) { + boot({ locale: 'en', availableLanguages: {} }); + } else { + // See above the comment about the loader and case sensitiviness + appLocale.toLowerCase(); + getNLSConfiguration(appLocale).then((nlsConfig) => { + if (!nlsConfig) { + nlsConfig = { locale: appLocale, availableLanguages: {} }; + } + boot(nlsConfig); + }); + } + } + }); }, console.error); }); diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index 92568a683f7..d5bec85ebaf 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -576,7 +576,7 @@ export function fuzzyScore(pattern: string, word: string, patternMaxWhitespaceIg _matchesCount = 0; _topScore = -100; _patternStartPos = patternStartPos; - _findAllMatches(patternLen, wordLen, 0, new LazyArray(), false); + _findAllMatches(patternLen, wordLen, patternLen === wordLen ? 1 : 0, new LazyArray(), false); if (_matchesCount === 0) { return undefined; diff --git a/src/vs/base/test/common/filters.test.ts b/src/vs/base/test/common/filters.test.ts index a6fe1a58b1a..bc330457fa8 100644 --- a/src/vs/base/test/common/filters.test.ts +++ b/src/vs/base/test/common/filters.test.ts @@ -393,11 +393,11 @@ suite('Filters', () => { // issue #17836 // assertTopScore(fuzzyScore, 'TEdit', 1, 'TextEditorDecorationType', 'TextEdit', 'TextEditor'); - assertTopScore(fuzzyScore, 'p', 0, 'parse', 'posix', 'pafdsa', 'path', 'p'); + assertTopScore(fuzzyScore, 'p', 4, 'parse', 'posix', 'pafdsa', 'path', 'p'); assertTopScore(fuzzyScore, 'pa', 0, 'parse', 'pafdsa', 'path'); // issue #14583 - assertTopScore(fuzzyScore, 'log', 3, 'HTMLOptGroupElement', 'ScrollLogicalPosition', 'SVGFEMorphologyElement', 'log'); + assertTopScore(fuzzyScore, 'log', 3, 'HTMLOptGroupElement', 'ScrollLogicalPosition', 'SVGFEMorphologyElement', 'log', 'logger'); assertTopScore(fuzzyScore, 'e', 2, 'AbstractWorker', 'ActiveXObject', 'else'); // issue #14446 @@ -415,6 +415,8 @@ suite('Filters', () => { assertTopScore(fuzzyScore, 'is', 0, 'isValidViewletId', 'import statement'); assertTopScore(fuzzyScore, 'title', 1, 'files.trimTrailingWhitespace', 'window.title'); + + assertTopScore(fuzzyScore, 'const', 1, 'constructor', 'const', 'cuOnstrul'); }); test('Unexpected suggestion scoring, #28791', function () { diff --git a/src/vs/base/test/common/resources.test.ts b/src/vs/base/test/common/resources.test.ts index 4c0925bcf14..e29e625f4c7 100644 --- a/src/vs/base/test/common/resources.test.ts +++ b/src/vs/base/test/common/resources.test.ts @@ -48,7 +48,7 @@ suite('Resources', () => { assert.equal(d.fsPath, normalize('/some/file', true)); // does not explode (https://github.com/Microsoft/vscode/issues/41987) - URI.from({ scheme: 'file', authority: '/users/someone/portal.h' }); + dirname(URI.from({ scheme: 'file', authority: '/users/someone/portal.h' })); done(); }); }); \ No newline at end of file diff --git a/src/vs/code/electron-browser/issue/issueReporter.js b/src/vs/code/electron-browser/issue/issueReporter.js index ac9730d0d58..06cbab83f42 100644 --- a/src/vs/code/electron-browser/issue/issueReporter.js +++ b/src/vs/code/electron-browser/issue/issueReporter.js @@ -6,6 +6,7 @@ 'use strict'; const path = require('path'); +const fs = require('fs'); const remote = require('electron').remote; function parseURLQueryArgs() { @@ -36,6 +37,18 @@ function uriFromPath(_path) { return encodeURI('file://' + pathName); } +function readFile(file) { + return new Promise(function(resolve, reject) { + fs.readFile(file, 'utf8', function(err, data) { + if (err) { + reject(err); + return; + } + resolve(data); + }); + }); +} + function main() { const args = parseURLQueryArgs(); const configuration = JSON.parse(args['config'] || '{}') || {}; @@ -75,6 +88,24 @@ function main() { } catch (e) { /*noop*/ } } + if (nlsConfig._resolvedLanguagePackCoreLocation) { + let bundles = Object.create(null); + nlsConfig.loadBundle = function(bundle, language, cb) { + let result = bundles[bundle]; + if (result) { + cb(undefined, result); + return; + } + let bundleFile = path.join(nlsConfig._resolvedLanguagePackCoreLocation, bundle.replace(/\//g, '!') + '.nls.json'); + readFile(bundleFile).then(function (content) { + let json = JSON.parse(content); + bundles[bundle] = json; + cb(undefined, json); + }) + .catch(cb); + }; + } + var locale = nlsConfig.availableLanguages['*'] || 'en'; if (locale === 'zh-tw') { locale = 'zh-Hant'; diff --git a/src/vs/code/electron-browser/issue/issueReporterMain.ts b/src/vs/code/electron-browser/issue/issueReporterMain.ts index 93be7de5db0..e851e2e65b1 100644 --- a/src/vs/code/electron-browser/issue/issueReporterMain.ts +++ b/src/vs/code/electron-browser/issue/issueReporterMain.ts @@ -9,9 +9,11 @@ import 'vs/css!./media/issueReporter'; import { shell, ipcRenderer, webFrame, remote } from 'electron'; import { localize } from 'vs/nls'; import { $ } from 'vs/base/browser/dom'; +import * as collections from 'vs/base/common/collections'; import * as browser from 'vs/base/browser/browser'; import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; +import * as os from 'os'; import { Disposable } from 'vs/base/common/lifecycle'; import { Client as ElectronIPCClient } from 'vs/base/parts/ipc/electron-browser/ipc.electron-browser'; import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc'; @@ -27,11 +29,17 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; import { WindowsChannelClient } from 'vs/platform/windows/common/windowsIpc'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { IssueReporterModel, IssueReporterData } from 'vs/code/electron-browser/issue/issueReporterModel'; -import { IssueReporterStyles } from 'vs/platform/issue/common/issue'; +import { IssueReporterModel, IssueType } from 'vs/code/electron-browser/issue/issueReporterModel'; +import { IssueReporterData, IssueReporterStyles } from 'vs/platform/issue/common/issue'; import BaseHtml from 'vs/code/electron-browser/issue/issueReporterPage'; +import { ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { debounce } from 'vs/base/common/decorators'; -export function startup(configuration: IWindowConfiguration) { +export interface IssueReporterConfiguration extends IWindowConfiguration { + data: IssueReporterData; +} + +export function startup(configuration: IssueReporterConfiguration) { document.body.innerHTML = BaseHtml(); const issueReporter = new IssueReporter(configuration); @@ -47,19 +55,22 @@ export class IssueReporter extends Disposable { private telemetryService: ITelemetryService; private issueReporterModel: IssueReporterModel; - constructor(configuration: IWindowConfiguration) { + constructor(configuration: IssueReporterConfiguration) { super(); + this.initServices(configuration); + this.issueReporterModel = new IssueReporterModel({ - issueType: 0, + issueType: IssueType.Bug, includeSystemInfo: true, includeWorkspaceInfo: true, - includeProcessInfo: true - }); - - ipcRenderer.on('issueStyleResponse', (event, styles: IssueReporterStyles) => { - this.applyZoom(styles.zoomLevel); - this.applyStyles(styles); + includeProcessInfo: true, + includeExtensions: true, + versionInfo: { + vscodeVersion: `${pkg.name} ${pkg.version} (${product.commit || 'Commit unknown'}, ${product.date || 'Date unknown'})`, + os: `${os.type()} ${os.arch()} ${os.release()}` + }, + extensionsDisabled: this.environmentService.disableExtensions }); ipcRenderer.on('issueInfoResponse', (event, info) => { @@ -73,14 +84,15 @@ export class IssueReporter extends Disposable { }); ipcRenderer.send('issueInfoRequest'); - ipcRenderer.send('issueStyleRequest'); - - this.initServices(configuration); - this.setEventHandlers(); if (window.document.documentElement.lang !== 'en') { show(document.getElementById('english')); } + + this.setEventHandlers(); + this.applyZoom(configuration.data.zoomLevel); + this.applyStyles(configuration.data.styles); + this.handleExtensionData(configuration.data.enabledExtensions); } render(): void { @@ -148,6 +160,18 @@ export class IssueReporter extends Disposable { document.body.style.color = styles.color; } + private handleExtensionData(extensions: ILocalExtension[]) { + const { nonThemes, themes } = collections.groupBy(extensions, ext => { + const manifestKeys = ext.manifest.contributes ? Object.keys(ext.manifest.contributes) : []; + const onlyTheme = !ext.manifest.activationEvents && manifestKeys.length === 1 && manifestKeys[0] === 'themes'; + return onlyTheme ? 'themes' : 'nonThemes'; + }); + + const numberOfThemeExtesions = themes && themes.length; + this.issueReporterModel.update({ numberOfThemeExtesions, enabledNonThemeExtesions: nonThemes }); + this.updateExtensionTable(nonThemes, numberOfThemeExtesions); + } + private initServices(configuration: IWindowConfiguration): void { const serviceCollection = new ServiceCollection(); const mainProcessClient = new ElectronIPCClient(String(`window${configuration.windowId}`)); @@ -182,61 +206,18 @@ export class IssueReporter extends Disposable { this.render(); }); - document.getElementById('includeSystemInfo').addEventListener('click', (event: Event) => { - event.stopPropagation(); - this.issueReporterModel.update({ includeSystemInfo: !this.issueReporterModel.getData().includeSystemInfo }); - }); - - document.getElementById('includeProcessInfo').addEventListener('click', (event: Event) => { - event.stopPropagation(); - this.issueReporterModel.update({ includeProcessInfo: !this.issueReporterModel.getData().includeSystemInfo }); - }); - - document.getElementById('includeWorkspaceInfo').addEventListener('click', (event: Event) => { - event.stopPropagation(); - this.issueReporterModel.update({ includeWorkspaceInfo: !this.issueReporterModel.getData().includeWorkspaceInfo }); + ['includeSystemInfo', 'includeProcessInfo', 'includeWorkspaceInfo', 'includeExtensions'].forEach(elementId => { + document.getElementById(elementId).addEventListener('click', (event: Event) => { + event.stopPropagation(); + this.issueReporterModel.update({ [elementId]: !this.issueReporterModel.getData()[elementId] }); + }); }); document.getElementById('description').addEventListener('blur', (event: Event) => { this.issueReporterModel.update({ issueDescription: (event.target).value }); }); - function addIssuesToList(list, issueJSON) { - for (let i = 0; i < 5; i++) { - const link = $('a', { href: issueJSON[i].html_url }); - link.textContent = issueJSON[i].title; - link.addEventListener('click', (event) => { - shell.openExternal((event.target).href); - }); - - const item = $('li', {}, link); - list.appendChild(item); - } - } - - document.getElementById('issue-title').addEventListener('blur', (event) => { - const title = (event.target).value; - const similarIssues = document.getElementById('similar-issues'); - similarIssues.innerHTML = ''; - - if (title) { - const query = `is:issue+repo:microsoft/vscode+${title}`; - window.fetch(`https://api.github.com/search/issues?q=${query}&per_page=5`).then((response) => { - response.json().then(result => { - if (result.items.length) { - const issues = $('ul'); - const issuesText = $('div.list-title'); - issuesText.textContent = localize('similarIssues', "Similar issues"); - addIssuesToList(issues, result.items); - similarIssues.appendChild(issuesText); - similarIssues.appendChild(issues); - } - }); - }).catch((error) => { - console.log(error); - }); - } - }); + document.getElementById('issue-title').addEventListener('input', this.searchGitHub); document.getElementById('github-submit-btn').addEventListener('click', () => this.createIssue()); @@ -250,41 +231,79 @@ export class IssueReporter extends Disposable { }; } + @debounce(300) + private searchGitHub(event: Event) { + const title = (event.target).value; + const similarIssues = document.getElementById('similar-issues'); + if (title) { + const query = `is:issue+repo:microsoft/vscode+${title}`; + window.fetch(`https://api.github.com/search/issues?q=${query}`).then((response) => { + response.json().then(result => { + similarIssues.innerHTML = ''; + if (result && result.items && result.items.length) { + const issues = $('ul'); + const issuesText = $('div.list-title'); + issuesText.textContent = localize('similarIssues', "Similar issues"); + + const { items } = result; + const numResultsToDisplay = items.length < 5 ? items.length : 5; + for (let i = 0; i < numResultsToDisplay; i++) { + const link = $('a', { href: items[i].html_url }); + link.textContent = items[i].title; + link.addEventListener('click', (event) => { + shell.openExternal((event.target).href); + }); + + const item = $('li', {}, link); + issues.appendChild(item); + } + + similarIssues.appendChild(issuesText); + similarIssues.appendChild(issues); + } + }); + }).catch((error) => { + console.log(error); + }); + } else { + similarIssues.innerHTML = ''; + } + } + private renderBlocks(): void { // Depending on Issue Type, we render different blocks and text const { issueType } = this.issueReporterModel.getData(); const systemBlock = document.querySelector('.block-system'); const processBlock = document.querySelector('.block-process'); const workspaceBlock = document.querySelector('.block-workspace'); + const extensionsBlock = document.querySelector('.block-extensions'); const descriptionTitle = document.getElementById('issue-description-label'); const descriptionSubtitle = document.getElementById('issue-description-subtitle'); - // 1 - Bug - if (issueType === 0) { + if (issueType === IssueType.Bug) { show(systemBlock); hide(processBlock); hide(workspaceBlock); + show(extensionsBlock); descriptionTitle.innerHTML = `${localize('stepsToReproduce', "Steps to Reproduce")} *`; show(descriptionSubtitle); descriptionSubtitle.innerHTML = localize('bugDescription', "How did you encounter this problem? Please provide clear steps to reproduce the problem during our investigation. What did you expect to happen and what actually did happen?"); - } - // 2 - Perf Issue - else if (issueType === 1) { + } else if (issueType === IssueType.PerformanceIssue) { show(systemBlock); show(processBlock); show(workspaceBlock); + show(extensionsBlock); descriptionTitle.innerHTML = `${localize('stepsToReproduce', "Steps to Reproduce")} *`; show(descriptionSubtitle); descriptionSubtitle.innerHTML = localize('performanceIssueDesciption', "When did this performance issue happen? For example, does it occur on startup or after a specific series of actions? Any details you can provide help our investigation."); - } - // 3 - Feature Request - else { + } else { hide(systemBlock); hide(processBlock); hide(workspaceBlock); + hide(extensionsBlock); descriptionTitle.innerHTML = `${localize('description', "Description")} *`; hide(descriptionSubtitle); @@ -352,29 +371,20 @@ export class IssueReporter extends Disposable { */ private updateAllBlocks(state) { - this.updateVersionInfo(state); this.updateSystemInfo(state); this.updateProcessInfo(state); this.updateWorkspaceInfo(state); } - private updateVersionInfo = (state: IssueReporterData) => { - const version = document.getElementById('vscode-version'); - (version).value = state.versionInfo.vscodeVersion; - - const osversion = document.getElementById('os'); - (osversion).value = state.versionInfo.os; - } - private updateSystemInfo = (state) => { const target = document.querySelector('.block-system .block-info'); let tableHtml = ''; Object.keys(state.systemInfo).forEach(k => { tableHtml += ` - - ${k} - ${state.systemInfo[k]} -`; + + ${k} + ${state.systemInfo[k]} + `; }); target.innerHTML = `${tableHtml}
`; } @@ -383,28 +393,64 @@ export class IssueReporter extends Disposable { const target = document.querySelector('.block-process .block-info'); let tableHtml = ` - - pid - CPU % - Memory (MB) - Name - -`; + + pid + CPU % + Memory (MB) + Name + `; + state.processInfo.forEach(p => { tableHtml += ` - - ${p.pid} - ${p.cpu} - ${p.memory} - ${p.name} -`; + + ${p.pid} + ${p.cpu} + ${p.memory} + ${p.name} + `; }); + target.innerHTML = `${tableHtml}
`; } private updateWorkspaceInfo = (state) => { document.querySelector('.block-workspace .block-info code').textContent = '\n' + state.workspaceInfo; } + + private updateExtensionTable(extensions: ILocalExtension[], numThemeExtensions: number): void { + const target = document.querySelector('.block-extensions .block-info'); + + if (this.environmentService.disableExtensions) { + target.innerHTML = localize('disabledExtensions', "Extensions are disabled"); + return; + } + + const themeExclusionStr = numThemeExtensions ? `\n(${numThemeExtensions} theme extensions excluded)` : ''; + extensions = extensions || []; + + if (!extensions.length) { + target.innerHTML = 'Extensions: none' + themeExclusionStr; + return; + } + + let table = ` + + Extension + Author (truncated) + Version + `; + + extensions.forEach(extension => { + table += ` + + ${extension.manifest.name} + ${extension.manifest.publisher.substr(0, 3)} + ${extension.manifest.version} + `; + }); + + target.innerHTML = `${table}
${themeExclusionStr}`; + } } // helper functions diff --git a/src/vs/code/electron-browser/issue/issueReporterModel.ts b/src/vs/code/electron-browser/issue/issueReporterModel.ts index ab6facf3a25..3da55c9d6cc 100644 --- a/src/vs/code/electron-browser/issue/issueReporterModel.ts +++ b/src/vs/code/electron-browser/issue/issueReporterModel.ts @@ -6,9 +6,16 @@ 'use strict'; import { assign } from 'vs/base/common/objects'; +import { ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; + +export enum IssueType { + Bug, + PerformanceIssue, + FeatureRequest +} export interface IssueReporterData { - issueType?: number; + issueType?: IssueType; issueDescription?: string; versionInfo?: any; systemInfo?: any; @@ -17,6 +24,10 @@ export interface IssueReporterData { includeSystemInfo?: boolean; includeWorkspaceInfo?: boolean; includeProcessInfo?: boolean; + includeExtensions?: boolean; + numberOfThemeExtesions?: number; + enabledNonThemeExtesions?: ILocalExtension[]; + extensionsDisabled?: boolean; } export class IssueReporterModel { @@ -55,9 +66,9 @@ ${this.getInfos()} } private getIssueTypeTitle(): string { - if (this._data.issueType === 0) { + if (this._data.issueType === IssueType.Bug) { return 'Bug'; - } else if (this._data.issueType === 1) { + } else if (this._data.issueType === IssueType.PerformanceIssue) { return 'Performance Issue'; } else { return 'Feature Request'; @@ -71,8 +82,13 @@ ${this.getInfos()} info += this.generateSystemInfoMd(); } - // For perf issue, add process info and workspace info too - if (this._data.issueType === 1) { + if (this._data.issueType === IssueType.Bug) { + if (this._data.includeExtensions) { + info += this.generateExtensionsMd(); + } + } + + if (this._data.issueType === IssueType.PerformanceIssue) { if (this._data.includeProcessInfo) { info += this.generateProcessInfoMd(); @@ -81,6 +97,10 @@ ${this.getInfos()} if (this._data.includeWorkspaceInfo) { info += this.generateWorkspaceInfoMd(); } + + if (this._data.includeExtensions) { + info += this.generateExtensionsMd(); + } } return info; @@ -131,4 +151,38 @@ ${this._data.workspaceInfo}; `; } + + private generateExtensionsMd(): string { + if (this._data.extensionsDisabled) { + return 'Extensions disabled'; + } + + const themeExclusionStr = this._data.numberOfThemeExtesions ? `\n(${this._data.numberOfThemeExtesions} theme extensions excluded)` : ''; + + if (!this._data.enabledNonThemeExtesions) { + return 'Extensions: none' + themeExclusionStr; + } + + let tableHeader = `Extension|Author (truncated)|Version +---|---|---`; + const table = this._data.enabledNonThemeExtesions.map(e => { + return `${e.manifest.name}|${e.manifest.publisher.substr(0, 3)}|${e.manifest.version}`; + }).join('\n'); + + const extensionTable = `
Extensions (${this._data.enabledNonThemeExtesions.length}) + +${tableHeader} +${table} +${themeExclusionStr} + +
`; + + // 2000 chars is browsers de-facto limit for URLs, 400 chars are allowed for other string parts of the issue URL + // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers + if (encodeURIComponent(extensionTable).length > 1600) { + return 'the listing length exceeds browsers\' URL characters limit'; + } + + return extensionTable; + } } \ No newline at end of file diff --git a/src/vs/code/electron-browser/issue/issueReporterPage.ts b/src/vs/code/electron-browser/issue/issueReporterPage.ts index 5836f45bd10..19085c508fa 100644 --- a/src/vs/code/electron-browser/issue/issueReporterPage.ts +++ b/src/vs/code/electron-browser/issue/issueReporterPage.ts @@ -6,6 +6,8 @@ import { escape } from 'vs/base/common/strings'; import { localize } from 'vs/nls'; +import * as os from 'os'; +import pkg from 'vs/platform/node/package'; export default (): string => `
@@ -32,11 +34,11 @@ export default (): string => `
- +
- +
@@ -79,6 +81,18 @@ export default (): string => `
+
+
+ ${escape(localize('extensions', "My Extensions"))} + + + + +
+ +
+
+
@@ -89,7 +103,7 @@ export default (): string => `
- ${escape(localize('githubMarkdown', "We support GitHub-flavored Markdown. You will still be able to edit your issue when we preview it on GitHub."))} + ${escape(localize('githubMarkdown', "We support GitHub-flavored Markdown. You will still be able to edit your issue and add screenshots when we preview it on GitHub."))}
diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcess.js b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js index 5f4f1dae5bd..94481666801 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcess.js +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js @@ -6,6 +6,7 @@ 'use strict'; const path = require('path'); +const fs = require('fs'); function assign(destination, source) { return Object.keys(source) @@ -40,6 +41,18 @@ function uriFromPath(_path) { return encodeURI('file://' + pathName); } +function readFile(file) { + return new Promise(function(resolve, reject) { + fs.readFile(file, 'utf8', function(err, data) { + if (err) { + reject(err); + return; + } + resolve(data); + }); + }); +} + function main() { const args = parseURLQueryArgs(); const configuration = JSON.parse(args['config'] || '{}') || {}; @@ -57,6 +70,24 @@ function main() { } catch (e) { /*noop*/ } } + if (nlsConfig._resolvedLanguagePackCoreLocation) { + let bundles = Object.create(null); + nlsConfig.loadBundle = function(bundle, language, cb) { + let result = bundles[bundle]; + if (result) { + cb(undefined, result); + return; + } + let bundleFile = path.join(nlsConfig._resolvedLanguagePackCoreLocation, bundle.replace(/\//g, '!') + '.nls.json'); + readFile(bundleFile).then(function (content) { + let json = JSON.parse(content); + bundles[bundle] = json; + cb(undefined, json); + }) + .catch(cb); + }; + } + var locale = nlsConfig.availableLanguages['*'] || 'en'; if (locale === 'zh-tw') { locale = 'zh-Hant'; diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 64c73d5b91c..06ce9b9d2f0 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -452,12 +452,6 @@ export class CodeApplication { // Start shared process here this.sharedProcess.spawn(); - - // Launch Issue BrowserWindow if --issue is specified - if (this.environmentService.args.issue) { - const issueService = accessor.get(IIssueService); - issueService.openReporter(); - } } private dispose(): void { diff --git a/src/vs/code/electron-main/diagnostics.ts b/src/vs/code/electron-main/diagnostics.ts index 8a3fb1445fd..926ce809c15 100644 --- a/src/vs/code/electron-main/diagnostics.ts +++ b/src/vs/code/electron-main/diagnostics.ts @@ -39,7 +39,6 @@ export interface ProcessInfo { } export interface DiagnosticInfo { - versionInfo?: VersionInfo; systemInfo?: SystemInfo; processInfo?: ProcessInfo[]; workspaceInfo?: string; @@ -80,7 +79,6 @@ export function buildDiagnostics(info: IMainProcessInfo): Promise mapPidToWindowTitle.set(window.pid, window.title)); const processes: ProcessInfo[] = []; - getProcessItem(mapPidToWindowTitle, processes, rootProcess, 0); if (rootProcess) { getProcessItem(mapPidToWindowTitle, processes, rootProcess, 0); diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 76be406fa4e..f6f96d5cf64 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -944,7 +944,7 @@ export class CodeMenu { const label = nls.localize({ key: 'miReportIssue', comment: ['&& denotes a mnemonic', 'Translate this to "Report Issue in English" in all languages please!'] }, "Report &&Issue"); if (this.windowsMainService.getWindowCount() > 0) { - reportIssuesItem = this.createMenuItem(label, 'workbench.action.reportIssues'); + reportIssuesItem = this.createMenuItem(label, 'workbench.action.openIssueReporter'); } else { reportIssuesItem = new MenuItem({ label: this.mnemonicLabel(label), click: () => this.openUrl(product.reportIssueUrl, 'openReportIssues') }); } diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index b47a0015178..03b86b8c36d 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -347,6 +347,6 @@ function eventuallyExit(code: number): void { main(process.argv) .then(() => eventuallyExit(0)) .then(null, err => { - console.error(err.stack ? err.stack : err); + console.error(err.message || err.stack || err); eventuallyExit(1); }); diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index 0e21b9588b5..436f7a96967 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -364,7 +364,7 @@ abstract class BareHitTestRequest { this.mouseVerticalOffset = Math.max(0, ctx.getCurrentScrollTop() + pos.y - editorPos.y); this.mouseContentHorizontalOffset = ctx.getCurrentScrollLeft() + pos.x - editorPos.x - ctx.layoutInfo.contentLeft; - this.isInMarginArea = (pos.x - editorPos.x < ctx.layoutInfo.contentLeft); + this.isInMarginArea = (pos.x - editorPos.x < ctx.layoutInfo.contentLeft && pos.x - editorPos.x >= ctx.layoutInfo.glyphMarginLeft); this.isInContentArea = !this.isInMarginArea; this.mouseColumn = Math.max(0, MouseTargetFactory._getMouseColumn(this.mouseContentHorizontalOffset, ctx.typicalHalfwidthCharacterWidth)); } @@ -587,6 +587,8 @@ export class MouseTargetFactory { offsetX: offset }; + offset -= ctx.layoutInfo.glyphMarginLeft; + if (offset <= ctx.layoutInfo.glyphMarginWidth) { // On the glyph margin return request.fulfill(MouseTargetType.GUTTER_GLYPH_MARGIN, pos, res.range, detail); diff --git a/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts b/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts index 73ae56f5e38..ed1121cfcdd 100644 --- a/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts +++ b/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts @@ -99,7 +99,13 @@ export class EditorScrollbar extends ViewPart { const layoutInfo = this._context.configuration.editor.layoutInfo; this.scrollbarDomNode.setLeft(layoutInfo.contentLeft); - this.scrollbarDomNode.setWidth(layoutInfo.contentWidth + layoutInfo.minimapWidth); + + const side = this._context.configuration.editor.viewInfo.minimap.side; + if (side === 'right') { + this.scrollbarDomNode.setWidth(layoutInfo.contentWidth + layoutInfo.minimapWidth); + } else { + this.scrollbarDomNode.setWidth(layoutInfo.contentWidth); + } this.scrollbarDomNode.setHeight(layoutInfo.contentHeight); } diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 62c2629841d..b1da0a53ed6 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -82,6 +82,10 @@ class MinimapOptions { public readonly lineHeight: number; + /** + * container dom node left position (in CSS px) + */ + public readonly minimapLeft: number; /** * container dom node width (in CSS px) */ @@ -121,6 +125,7 @@ class MinimapOptions { this.pixelRatio = pixelRatio; this.typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; this.lineHeight = configuration.editor.lineHeight; + this.minimapLeft = layoutInfo.minimapLeft; this.minimapWidth = layoutInfo.minimapWidth; this.minimapHeight = layoutInfo.height; @@ -138,6 +143,7 @@ class MinimapOptions { && this.pixelRatio === other.pixelRatio && this.typicalHalfwidthCharacterWidth === other.typicalHalfwidthCharacterWidth && this.lineHeight === other.lineHeight + && this.minimapLeft === other.minimapLeft && this.minimapWidth === other.minimapWidth && this.minimapHeight === other.minimapHeight && this.canvasInnerWidth === other.canvasInnerWidth @@ -456,7 +462,6 @@ export class Minimap extends ViewPart { this._domNode.setPosition('absolute'); this._domNode.setAttribute('role', 'presentation'); this._domNode.setAttribute('aria-hidden', 'true'); - this._domNode.setRight(this._context.configuration.editor.layoutInfo.verticalScrollbarWidth); this._shadow = createFastDomNode(document.createElement('div')); this._shadow.setClassName('minimap-shadow-hidden'); @@ -563,6 +568,7 @@ export class Minimap extends ViewPart { } private _applyLayout(): void { + this._domNode.setLeft(this._options.minimapLeft); this._domNode.setWidth(this._options.minimapWidth); this._domNode.setHeight(this._options.minimapHeight); this._shadow.setHeight(this._options.minimapHeight); diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index a51f6df0ba1..6f6f9040b52 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -264,6 +264,12 @@ const editorConfiguration: IConfigurationNode = { 'default': EDITOR_DEFAULTS.viewInfo.minimap.enabled, 'description': nls.localize('minimap.enabled', "Controls if 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. Possible values are \'right\' and \'left\'") + }, 'editor.minimap.showSlider': { 'type': 'string', 'enum': ['always', 'mouseover'], diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index c230f0088e2..442d8e9cff7 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -102,6 +102,11 @@ export interface IEditorMinimapOptions { * Defaults to false. */ 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'. @@ -740,6 +745,7 @@ export interface InternalEditorScrollbarOptions { export interface InternalEditorMinimapOptions { readonly enabled: boolean; + readonly side: 'right' | 'left'; readonly showSlider: 'always' | 'mouseover'; readonly renderCharacters: boolean; readonly maxColumn: number; @@ -1019,6 +1025,7 @@ export class InternalEditorOptions { && 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 @@ -1101,6 +1108,7 @@ export class InternalEditorOptions { 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 @@ -1288,6 +1296,10 @@ export interface EditorLayoutInfo { */ readonly contentHeight: number; + /** + * The position for the minimap + */ + readonly minimapLeft: number; /** * The width of the minimap */ @@ -1553,6 +1565,7 @@ export class EditorOptionsValidator { } 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), @@ -1769,6 +1782,7 @@ export class InternalEditorOptionsFactory { scrollbar: opts.viewInfo.scrollbar, minimap: { enabled: (accessibilityIsOn ? false : opts.viewInfo.minimap.enabled), // DISABLED WHEN SCREEN READER IS ATTACHED + side: opts.viewInfo.minimap.side, renderCharacters: opts.viewInfo.minimap.renderCharacters, showSlider: opts.viewInfo.minimap.showSlider, maxColumn: opts.viewInfo.minimap.maxColumn @@ -1850,6 +1864,7 @@ export class InternalEditorOptionsFactory { 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 @@ -1982,6 +1997,7 @@ export interface IEditorLayoutProviderOpts { horizontalScrollbarHeight: number; minimap: boolean; + minimapSide: string; minimapRenderCharacters: boolean; minimapMaxColumn: number; pixelRatio: number; @@ -2007,6 +2023,7 @@ export class EditorLayoutProvider { 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; @@ -2022,17 +2039,19 @@ export class EditorLayoutProvider { glyphMarginWidth = lineHeight; } - const glyphMarginLeft = 0; - const lineNumbersLeft = glyphMarginLeft + glyphMarginWidth; - const decorationsLeft = lineNumbersLeft + lineNumbersWidth; - const contentLeft = decorationsLeft + lineDecorationsWidth; + let glyphMarginLeft = 0; + let lineNumbersLeft = glyphMarginLeft + glyphMarginWidth; + let decorationsLeft = lineNumbersLeft + lineNumbersWidth; + let contentLeft = decorationsLeft + lineDecorationsWidth; const remainingWidth = outerWidth - glyphMarginWidth - lineNumbersWidth - lineDecorationsWidth; let renderMinimap: RenderMinimap; + let minimapLeft: number; let minimapWidth: number; let contentWidth: number; if (!minimap) { + minimapLeft = 0; minimapWidth = 0; renderMinimap = RenderMinimap.None; contentWidth = remainingWidth; @@ -2064,6 +2083,16 @@ export class EditorLayoutProvider { minimapWidth = Math.floor(minimapMaxColumn * minimapCharWidth); } contentWidth = remainingWidth - minimapWidth; + + if (minimapSide === 'left') { + minimapLeft = 0; + glyphMarginLeft += minimapWidth; + lineNumbersLeft += minimapWidth; + decorationsLeft += minimapWidth; + contentLeft += minimapWidth; + } else { + minimapLeft = outerWidth - minimapWidth - verticalScrollbarWidth; + } } const viewportColumn = Math.max(1, Math.floor((contentWidth - verticalScrollbarWidth) / typicalHalfwidthCharacterWidth)); @@ -2091,6 +2120,7 @@ export class EditorLayoutProvider { contentHeight: outerHeight, renderMinimap: renderMinimap, + minimapLeft: minimapLeft, minimapWidth: minimapWidth, viewportColumn: viewportColumn, @@ -2206,6 +2236,7 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = { }, minimap: { enabled: true, + side: 'right', showSlider: 'mouseover', renderCharacters: true, maxColumn: 120 diff --git a/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts index 3c98e8b6b31..d5497dd4c34 100644 --- a/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts +++ b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts @@ -721,14 +721,17 @@ export class PieceTreeBase { for (let i = 0; i < lineStarts.length; i++) { lineStarts[i] += startOffset + 1; } - (this._buffers[0].lineStarts).push(...lineStarts.slice(1)); + + this._buffers[0].lineStarts = (this._buffers[0].lineStarts).concat(lineStarts.slice(1)); this._buffers[0].buffer += '_' + text; startOffset += 1; } else { - for (let i = 0; i < lineStarts.length; i++) { - lineStarts[i] += startOffset; + if (startOffset !== 0) { + for (let i = 0; i < lineStarts.length; i++) { + lineStarts[i] += startOffset; + } } - (this._buffers[0].lineStarts).push(...lineStarts.slice(1)); + this._buffers[0].lineStarts = (this._buffers[0].lineStarts).concat(lineStarts.slice(1)); this._buffers[0].buffer += text; } @@ -920,7 +923,8 @@ export class PieceTreeBase { // _lastChangeBufferPos is already wrong this._lastChangeBufferPos = { line: this._lastChangeBufferPos.line - 1, column: startOffset - prevStartOffset }; } - (this._buffers[0].lineStarts).push(...lineStarts.slice(1)); + + this._buffers[0].lineStarts = (this._buffers[0].lineStarts).concat(lineStarts.slice(1)); let endIndex = this._buffers[0].lineStarts.length - 1; let endColumn = this._buffers[0].buffer.length - this._buffers[0].lineStarts[endIndex]; let endPos = { line: endIndex, column: endColumn }; diff --git a/src/vs/editor/standalone/browser/standaloneLanguages.ts b/src/vs/editor/standalone/browser/standaloneLanguages.ts index 1e4f3f4fc29..eded61cea6f 100644 --- a/src/vs/editor/standalone/browser/standaloneLanguages.ts +++ b/src/vs/editor/standalone/browser/standaloneLanguages.ts @@ -530,6 +530,18 @@ export interface CompletionItem { * line completions were [requested](#CompletionItemProvider.provideCompletionItems) at.~~ */ textEdit?: model.ISingleEditOperation; + /** + * An optional array of additional text edits that are applied when + * selecting this completion. Edits must not overlap with the main edit + * nor with themselves. + */ + additionalTextEdits?: model.ISingleEditOperation[]; + /** + * An optional set of characters that when pressed while this completion is active will accept it first and + * then type that character. *Note* that all commit characters should have `length=1` and that superfluous + * characters will be ignored. + */ + commitCharacters?: string[]; } /** * Represents a collection of [completion items](#CompletionItem) to be presented @@ -639,7 +651,9 @@ class SuggestAdapter { command: item.command, sortText: item.sortText, filterText: item.filterText, - snippetType: 'internal' + snippetType: 'internal', + additionalTextEdits: item.additionalTextEdits, + commitCharacters: item.commitCharacters }; let editRange = item.textEdit ? item.textEdit.range : item.range; if (editRange) { diff --git a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts index 53ac8d481a6..eddae34ccc2 100644 --- a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts +++ b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts @@ -31,6 +31,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -55,6 +56,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 800, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 99, @@ -87,6 +89,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 13, verticalScrollbarHasArrows: true, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -111,6 +114,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 800, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 97, @@ -143,6 +147,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -167,6 +172,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 800, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 89, @@ -199,6 +205,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -223,6 +230,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 89, @@ -255,6 +263,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -279,6 +288,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 89, @@ -311,6 +321,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -335,6 +346,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 84, @@ -367,6 +379,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -391,6 +404,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 84, @@ -423,6 +437,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -447,6 +462,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 83, @@ -479,6 +495,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -503,6 +520,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 172, @@ -535,6 +553,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: false, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -559,6 +578,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 900, renderMinimap: RenderMinimap.None, + minimapLeft: 0, minimapWidth: 0, viewportColumn: 170, @@ -591,6 +611,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: true, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 1, @@ -615,6 +636,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 800, renderMinimap: RenderMinimap.Small, + minimapLeft: 910, minimapWidth: 90, viewportColumn: 90, @@ -647,6 +669,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: true, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 2, @@ -671,6 +694,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 800, renderMinimap: RenderMinimap.Large, + minimapLeft: 910, minimapWidth: 90, viewportColumn: 90, @@ -703,6 +727,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { scrollbarArrowSize: 0, verticalScrollbarHasArrows: false, minimap: true, + minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, pixelRatio: 4, @@ -727,6 +752,65 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentHeight: 800, renderMinimap: RenderMinimap.Large, + minimapLeft: 953, + minimapWidth: 47, + viewportColumn: 94, + + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + + overviewRuler: { + top: 0, + width: 0, + height: 800, + right: 0 + } + }); + }); + + test('EditorLayoutProvider 10 - render minimap to left', () => { + doTest({ + outerWidth: 1000, + outerHeight: 800, + showGlyphMargin: false, + lineHeight: 16, + showLineNumbers: false, + lineNumbersMinChars: 0, + lineNumbersDigitCount: 1, + lineDecorationsWidth: 10, + typicalHalfwidthCharacterWidth: 10, + maxDigitWidth: 10, + verticalScrollbarWidth: 0, + horizontalScrollbarHeight: 0, + scrollbarArrowSize: 0, + verticalScrollbarHasArrows: false, + minimap: true, + minimapSide: 'left', + minimapRenderCharacters: true, + minimapMaxColumn: 150, + pixelRatio: 4, + }, { + width: 1000, + height: 800, + + glyphMarginLeft: 47, + glyphMarginWidth: 0, + glyphMarginHeight: 800, + + lineNumbersLeft: 47, + lineNumbersWidth: 0, + lineNumbersHeight: 800, + + decorationsLeft: 47, + decorationsWidth: 10, + decorationsHeight: 800, + + contentLeft: 57, + contentWidth: 943, + contentHeight: 800, + + renderMinimap: RenderMinimap.Large, + minimapLeft: 0, minimapWidth: 47, viewportColumn: 94, diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index fcaccb90a61..c4adbda4a91 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2395,6 +2395,11 @@ declare module monaco.editor { * Defaults to false. */ 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'. @@ -2961,6 +2966,7 @@ declare module monaco.editor { export interface InternalEditorMinimapOptions { readonly enabled: boolean; + readonly side: 'right' | 'left'; readonly showSlider: 'always' | 'mouseover'; readonly renderCharacters: boolean; readonly maxColumn: number; @@ -3162,6 +3168,10 @@ declare module monaco.editor { * The height of the content (actual height) */ readonly contentHeight: number; + /** + * The position for the minimap + */ + readonly minimapLeft: number; /** * The width of the minimap */ @@ -4170,6 +4180,18 @@ declare module monaco.languages { * line completions were [requested](#CompletionItemProvider.provideCompletionItems) at.~~ */ textEdit?: editor.ISingleEditOperation; + /** + * An optional array of additional text edits that are applied when + * selecting this completion. Edits must not overlap with the main edit + * nor with themselves. + */ + additionalTextEdits?: editor.ISingleEditOperation[]; + /** + * An optional set of characters that when pressed while this completion is active will accept it first and + * then type that character. *Note* that all commit characters should have `length=1` and that superfluous + * characters will be ignored. + */ + commitCharacters?: string[]; } /** diff --git a/src/vs/nls.js b/src/vs/nls.js index 231b85d0c86..2d633b44f9a 100644 --- a/src/vs/nls.js +++ b/src/vs/nls.js @@ -1,126 +1,140 @@ /*--------------------------------------------------------------------------------------------- -* Copyright (c) Microsoft Corporation. All rights reserved. -* Licensed under the MIT License. See License.txt in the project root for license information. -*--------------------------------------------------------------------------------------------*/ + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------- -*--------------------------------------------------------------------------------------------- -*--------------------------------------------------------------------------------------------- -*--------------------------------------------------------------------------------------------- -*--------------------------------------------------------------------------------------------- -* Please make sure to make edits in the .ts file at https://github.com/Microsoft/vscode-loader/ -*--------------------------------------------------------------------------------------------- -*--------------------------------------------------------------------------------------------- -*--------------------------------------------------------------------------------------------- -*--------------------------------------------------------------------------------------------- -*--------------------------------------------------------------------------------------------*/ + *--------------------------------------------------------------------------------------------- + *--------------------------------------------------------------------------------------------- + *--------------------------------------------------------------------------------------------- + *--------------------------------------------------------------------------------------------- + * Please make sure to make edits in the .ts file at https://github.com/Microsoft/vscode-loader/ + *--------------------------------------------------------------------------------------------- + *--------------------------------------------------------------------------------------------- + *--------------------------------------------------------------------------------------------- + *--------------------------------------------------------------------------------------------- + *--------------------------------------------------------------------------------------------*/ 'use strict'; var NLSLoaderPlugin; (function (NLSLoaderPlugin) { - var Environment = (function () { - function Environment(isPseudo) { - this.isPseudo = isPseudo; - // - } - Environment.detect = function () { - var isPseudo = (typeof document !== 'undefined' && document.location && document.location.hash.indexOf('pseudo=true') >= 0); - return new Environment(isPseudo); - }; - return Environment; - }()); - function _format(message, args, env) { - var result; - if (args.length === 0) { - result = message; - } - else { - result = message.replace(/\{(\d+)\}/g, function (match, rest) { - var index = rest[0]; - return typeof args[index] !== 'undefined' ? args[index] : match; - }); - } - if (env.isPseudo) { - // FF3B and FF3D is the Unicode zenkaku representation for [ and ] - result = '\uFF3B' + result.replace(/[aouei]/g, '$&$&') + '\uFF3D'; - } - return result; - } - function findLanguageForModule(config, name) { - var result = config[name]; - if (result) - return result; - result = config['*']; - if (result) - return result; - return null; - } - function localize(env, data, message) { - var args = []; - for (var _i = 3; _i < arguments.length; _i++) { - args[_i - 3] = arguments[_i]; - } - return _format(message, args, env); - } - function createScopedLocalize(scope, env) { - return function (idx, defaultValue) { - var restArgs = Array.prototype.slice.call(arguments, 2); - return _format(scope[idx], restArgs, env); - }; - } - var NLSPlugin = (function () { - function NLSPlugin(env) { - var _this = this; - this._env = env; - this.localize = function (data, message) { - var args = []; - for (var _i = 2; _i < arguments.length; _i++) { - args[_i - 2] = arguments[_i]; - } - return localize.apply(void 0, [_this._env, data, message].concat(args)); - }; - } - NLSPlugin.prototype.setPseudoTranslation = function (value) { - this._env = new Environment(value); - }; - NLSPlugin.prototype.create = function (key, data) { - return { - localize: createScopedLocalize(data[key], this._env) - }; - }; - NLSPlugin.prototype.load = function (name, req, load, config) { - var _this = this; - config = config || {}; - if (!name || name.length === 0) { - load({ - localize: this.localize - }); - } - else { - var pluginConfig = config['vs/nls'] || {}; - var language = pluginConfig.availableLanguages ? findLanguageForModule(pluginConfig.availableLanguages, name) : null; - var suffix = '.nls'; - if (language !== null && language !== NLSPlugin.DEFAULT_TAG) { - suffix = suffix + '.' + language; - } - req([name + suffix], function (messages) { - if (Array.isArray(messages)) { - messages.localize = createScopedLocalize(messages, _this._env); - } - else { - messages.localize = createScopedLocalize(messages[name], _this._env); - } - load(messages); - }); - } - }; - return NLSPlugin; - }()); - NLSPlugin.DEFAULT_TAG = 'i-default'; - NLSLoaderPlugin.NLSPlugin = NLSPlugin; - function init() { - define('vs/nls', new NLSPlugin(Environment.detect())); - } - NLSLoaderPlugin.init = init; - if (typeof doNotInitLoader === 'undefined') { - init(); - } + var Environment = /** @class */ (function () { + function Environment(isPseudo) { + this.isPseudo = isPseudo; + // + } + Environment.detect = function () { + var isPseudo = (typeof document !== 'undefined' && document.location && document.location.hash.indexOf('pseudo=true') >= 0); + return new Environment(isPseudo); + }; + return Environment; + }()); + function _format(message, args, env) { + var result; + if (args.length === 0) { + result = message; + } + else { + result = message.replace(/\{(\d+)\}/g, function (match, rest) { + var index = rest[0]; + return typeof args[index] !== 'undefined' ? args[index] : match; + }); + } + if (env.isPseudo) { + // FF3B and FF3D is the Unicode zenkaku representation for [ and ] + result = '\uFF3B' + result.replace(/[aouei]/g, '$&$&') + '\uFF3D'; + } + return result; + } + function findLanguageForModule(config, name) { + var result = config[name]; + if (result) + return result; + result = config['*']; + if (result) + return result; + return null; + } + function localize(env, data, message) { + var args = []; + for (var _i = 3; _i < arguments.length; _i++) { + args[_i - 3] = arguments[_i]; + } + return _format(message, args, env); + } + function createScopedLocalize(scope, env) { + return function (idx, defaultValue) { + var restArgs = Array.prototype.slice.call(arguments, 2); + return _format(scope[idx], restArgs, env); + }; + } + var NLSPlugin = /** @class */ (function () { + function NLSPlugin(env) { + var _this = this; + this._env = env; + this.localize = function (data, message) { + var args = []; + for (var _i = 2; _i < arguments.length; _i++) { + args[_i - 2] = arguments[_i]; + } + return localize.apply(void 0, [_this._env, data, message].concat(args)); + }; + } + NLSPlugin.prototype.setPseudoTranslation = function (value) { + this._env = new Environment(value); + }; + NLSPlugin.prototype.create = function (key, data) { + return { + localize: createScopedLocalize(data[key], this._env) + }; + }; + NLSPlugin.prototype.load = function (name, req, load, config) { + var _this = this; + config = config || {}; + if (!name || name.length === 0) { + load({ + localize: this.localize + }); + } + else { + var pluginConfig = config['vs/nls'] || {}; + var language = pluginConfig.availableLanguages ? findLanguageForModule(pluginConfig.availableLanguages, name) : null; + var suffix = '.nls'; + if (language !== null && language !== NLSPlugin.DEFAULT_TAG) { + suffix = suffix + '.' + language; + } + var messagesLoaded_1 = function (messages) { + if (Array.isArray(messages)) { + messages.localize = createScopedLocalize(messages, _this._env); + } + else { + messages.localize = createScopedLocalize(messages[name], _this._env); + } + load(messages); + }; + if (typeof pluginConfig.loadBundle === 'function') { + pluginConfig.loadBundle(name, language, function (err, messages) { + // We have an error. Load the English default strings to not fail + if (err) { + req([name + '.nls'], messagesLoaded_1); + } + else { + messagesLoaded_1(messages); + } + }); + } + else { + req([name + suffix], messagesLoaded_1); + } + } + }; + NLSPlugin.DEFAULT_TAG = 'i-default'; + return NLSPlugin; + }()); + NLSLoaderPlugin.NLSPlugin = NLSPlugin; + function init() { + define('vs/nls', new NLSPlugin(Environment.detect())); + } + NLSLoaderPlugin.init = init; + if (typeof doNotInitLoader === 'undefined') { + init(); + } })(NLSLoaderPlugin || (NLSLoaderPlugin = {})); diff --git a/src/vs/platform/actions/test/common/menuService.test.ts b/src/vs/platform/actions/test/common/menuService.test.ts index d3844428fbe..caf6313eafb 100644 --- a/src/vs/platform/actions/test/common/menuService.test.ts +++ b/src/vs/platform/actions/test/common/menuService.test.ts @@ -48,6 +48,10 @@ class MockExtensionService implements IExtensionService { throw new Error('Not implemented'); } + public canProfileExtensionHost() { + return false; + } + public startExtensionHostProfile(): TPromise { throw new Error('Not implemented'); } diff --git a/src/vs/platform/commands/test/commandService.test.ts b/src/vs/platform/commands/test/commandService.test.ts index 9b03a2f1eea..1a08ba578ef 100644 --- a/src/vs/platform/commands/test/commandService.test.ts +++ b/src/vs/platform/commands/test/commandService.test.ts @@ -40,6 +40,9 @@ class SimpleExtensionService implements IExtensionService { getExtensions(): TPromise { return TPromise.wrap([]); } + canProfileExtensionHost() { + return false; + } startExtensionHostProfile(): TPromise { throw new Error('Not implemented'); } diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index 6a3155f7aad..f40bd669a54 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -6,6 +6,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; +import { isFalsyOrWhitespace } from 'vs/base/common/strings'; export enum ContextKeyExprType { Defined = 1, @@ -30,7 +31,7 @@ export abstract class ContextKeyExpr { return new ContextKeyNotEqualsExpr(key, value); } - public static regex(key: string, value: string): ContextKeyExpr { + public static regex(key: string, value: RegExp): ContextKeyExpr { return new ContextKeyRegexExpr(key, value); } @@ -67,7 +68,7 @@ export abstract class ContextKeyExpr { if (serializedOne.indexOf('=~') >= 0) { let pieces = serializedOne.split('=~'); - return new ContextKeyRegexExpr(pieces[0].trim(), this._deserializeValue(pieces[1])); + return new ContextKeyRegexExpr(pieces[0].trim(), this._deserializeRegexValue(pieces[1])); } if (/^\!\s*/.test(serializedOne)) { @@ -96,6 +97,29 @@ export abstract class ContextKeyExpr { return serializedValue; } + private static _deserializeRegexValue(serializedValue: string): RegExp { + + if (isFalsyOrWhitespace(serializedValue)) { + console.warn('missing regexp-value for =~-expression'); + return null; + } + + let start = serializedValue.indexOf('/'); + let end = serializedValue.lastIndexOf('/'); + if (start === end || start < 0 /* || to < 0 */) { + console.warn(`bad regexp-value '${serializedValue}', missing /-enclosure`); + return null; + } + + let value = serializedValue.slice(start + 1, end); + try { + return new RegExp(value); + } catch (e) { + console.warn(`bad regexp-value '${serializedValue}', parse error: ${e}`); + return null; + } + } + public abstract getType(): ContextKeyExprType; public abstract equals(other: ContextKeyExpr): boolean; public abstract evaluate(context: IContext): boolean; @@ -334,15 +358,8 @@ export class ContextKeyNotExpr implements ContextKeyExpr { export class ContextKeyRegexExpr implements ContextKeyExpr { - private regexp: { source: string, test(s: string): boolean }; - - constructor(private key: string, value: any) { - try { - this.regexp = new RegExp(value); - } catch (e) { - this.regexp = { source: '', test() { return false; } }; - console.warn(`Bad value for glob-context key expression: ${value}`); - } + constructor(private key: string, private regexp: RegExp) { + // } public getType(): ContextKeyExprType { @@ -356,10 +373,11 @@ export class ContextKeyRegexExpr implements ContextKeyExpr { if (this.key > other.key) { return 1; } - if (this.regexp.source < other.regexp.source) { + const source = this.regexp ? this.regexp.source : undefined; + if (source < other.regexp.source) { return -1; } - if (this.regexp.source > other.regexp.source) { + if (source > other.regexp.source) { return 1; } return 0; @@ -367,13 +385,14 @@ export class ContextKeyRegexExpr implements ContextKeyExpr { public equals(other: ContextKeyExpr): boolean { if (other instanceof ContextKeyRegexExpr) { - return (this.key === other.key && this.regexp.source === other.regexp.source); + const source = this.regexp ? this.regexp.source : undefined; + return (this.key === other.key && source === other.regexp.source); } return false; } public evaluate(context: IContext): boolean { - return this.regexp.test(context.getValue(this.key)); + return this.regexp ? this.regexp.test(context.getValue(this.key)) : false; } public normalize(): ContextKeyExpr { @@ -381,7 +400,7 @@ export class ContextKeyRegexExpr implements ContextKeyExpr { } public serialize(): string { - return this.key + ' =~ \'' + this.regexp.source + '\''; + return `${this.keys} =~ /${this.regexp ? this.regexp.source : ''}/`; } public keys(): string[] { diff --git a/src/vs/platform/contextkey/test/common/contextkey.test.ts b/src/vs/platform/contextkey/test/common/contextkey.test.ts index 9433bf7ca02..beafc373f80 100644 --- a/src/vs/platform/contextkey/test/common/contextkey.test.ts +++ b/src/vs/platform/contextkey/test/common/contextkey.test.ts @@ -21,8 +21,8 @@ suite('ContextKeyExpr', () => { ContextKeyExpr.has('a1'), ContextKeyExpr.and(ContextKeyExpr.has('and.a')), ContextKeyExpr.has('a2'), - ContextKeyExpr.regex('d3', 'd.*'), - ContextKeyExpr.regex('d4', '\\*\\*/3*'), + ContextKeyExpr.regex('d3', /d.*/), + ContextKeyExpr.regex('d4', /\*\*3*/), ContextKeyExpr.equals('b1', 'bb1'), ContextKeyExpr.equals('b2', 'bb2'), ContextKeyExpr.notEquals('c1', 'cc1'), @@ -34,11 +34,11 @@ suite('ContextKeyExpr', () => { ContextKeyExpr.equals('b2', 'bb2'), ContextKeyExpr.notEquals('c1', 'cc1'), ContextKeyExpr.not('d1'), - ContextKeyExpr.regex('d4', '\\*\\*/3*'), + ContextKeyExpr.regex('d4', /\*\*3*/), ContextKeyExpr.notEquals('c2', 'cc2'), ContextKeyExpr.has('a2'), ContextKeyExpr.equals('b1', 'bb1'), - ContextKeyExpr.regex('d3', 'd.*'), + ContextKeyExpr.regex('d3', /d.*/), ContextKeyExpr.has('a1'), ContextKeyExpr.and(ContextKeyExpr.equals('and.a', true)), ContextKeyExpr.not('d2') @@ -80,7 +80,7 @@ suite('ContextKeyExpr', () => { testExpression(expr + ' == 5', value == '5'); testExpression(expr + ' != 5', value != '5'); testExpression('!' + expr, !value); - testExpression(expr + ' =~ d.*', /d.*/.test(value)); + testExpression(expr + ' =~ /d.*/', /d.*/.test(value)); } testBatch('a', true); @@ -92,6 +92,7 @@ suite('ContextKeyExpr', () => { testExpression('a && !b', true && !false); testExpression('a && b', true && false); testExpression('a && !b && c == 5', true && !false && '5' == '5'); + testExpression('dddd =~ d.*', false); /* tslint:enable:triple-equals */ }); }); diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 7bd8700a868..7af1337322a 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -12,7 +12,6 @@ export interface ParsedArgs { help?: boolean; version?: boolean; status?: boolean; - issue?: boolean; wait?: boolean; waitMarkerFilePath?: string; diff?: boolean; diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index fade5e83e1a..967ad4ab533 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -74,7 +74,6 @@ const options: minimist.Opts = { 'new-window': 'n', 'reuse-window': 'r', performance: 'p', - 'issue': 'i', 'disable-extensions': 'disableExtensions', 'extensions-dir': 'extensionHomePath', 'debugPluginHost': 'inspect-extensions', @@ -168,7 +167,6 @@ const troubleshootingHelp: { [name: string]: string; } = { '--inspect-brk-extensions': 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': localize('disableGPU', "Disable GPU hardware acceleration."), '--upload-logs': localize('uploadLogs', "Uploads logs from current session to a secure endpoint."), - '-i, --issue': localize('issue', "Report an issue."), }; export function formatOptions(options: { [name: string]: string; }, columns: number): string { diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index fcc62b80c75..f70b6e81a5a 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -156,7 +156,6 @@ export class EnvironmentService implements IEnvironmentService { get performance(): boolean { return this._args.performance; } get status(): boolean { return this._args.status; } - get issue(): boolean { return this._args.issue; } @memoize get mainIPCHandle(): string { return getIPCHandle(this.userDataPath, 'main'); } diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 6512e977822..5eb1cb408ab 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -232,7 +232,6 @@ export enum StatisticType { export interface IReportedExtension { id: IExtensionIdentifier; malicious: boolean; - slow: boolean; } export interface IExtensionGalleryService { @@ -280,6 +279,7 @@ export interface IExtensionManagementService { installFromGallery(extension: IGalleryExtension): TPromise; uninstall(extension: ILocalExtension, force?: boolean): TPromise; getInstalled(type?: LocalExtensionType): TPromise; + getExtensionsReport(): TPromise; updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): TPromise; } diff --git a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts index 15bb2aa58df..9cb9488880e 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc'; -import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, LocalExtensionType, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata } from './extensionManagement'; +import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, LocalExtensionType, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension } from './extensionManagement'; import Event, { buffer } from 'vs/base/common/event'; export interface IExtensionManagementChannel extends IChannel { @@ -19,6 +19,7 @@ export interface IExtensionManagementChannel extends IChannel { call(command: 'installFromGallery', extension: IGalleryExtension): TPromise; call(command: 'uninstall', args: [ILocalExtension, boolean]): TPromise; call(command: 'getInstalled'): TPromise; + call(command: 'getExtensionsReport'): TPromise; call(command: string, arg?: any): TPromise; } @@ -47,6 +48,7 @@ export class ExtensionManagementChannel implements IExtensionManagementChannel { case 'uninstall': return this.service.uninstall(arg[0], arg[1]); case 'getInstalled': return this.service.getInstalled(arg); case 'updateMetadata': return this.service.updateMetadata(arg[0], arg[1]); + case 'getExtensionsReport': return this.service.getExtensionsReport(); } return undefined; } @@ -89,4 +91,8 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): TPromise { return this.channel.call('updateMetadata', [local, metadata]); } + + getExtensionsReport(): TPromise { + return this.channel.call('getExtensionsReport'); + } } \ No newline at end of file diff --git a/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts index 3b60c27a367..73519179b53 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts @@ -5,7 +5,7 @@ 'use strict'; -import { ILocalExtension, IGalleryExtension, EXTENSION_IDENTIFIER_REGEX, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ILocalExtension, IGalleryExtension, EXTENSION_IDENTIFIER_REGEX, IExtensionIdentifier, IReportedExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; export function areSameExtensions(a: IExtensionIdentifier, b: IExtensionIdentifier): boolean { if (a.uuid && b.uuid) { @@ -101,4 +101,16 @@ export function getGalleryExtensionTelemetryData(extension: IGalleryExtension): } export const BetterMergeDisabledNowKey = 'extensions/bettermergedisablednow'; -export const BetterMergeId = 'pprice.better-merge'; \ No newline at end of file +export const BetterMergeId = 'pprice.better-merge'; + +export function getMaliciousExtensionsSet(report: IReportedExtension[]): Set { + const result = new Set(); + + for (const extension of report) { + if (extension.malicious) { + result.add(extension.id.id); + } + } + + return result; +} \ No newline at end of file diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index ae9aa3ca924..81b8e3cc744 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -743,12 +743,6 @@ export class ExtensionGalleryService implements IExtensionGalleryService { map.set(id, ext); } - for (const id of result.slow) { - const ext = map.get(id) || { id: { id }, malicious: false, slow: true }; - ext.slow = true; - map.set(id, ext); - } - return TPromise.as(values(map)); }); }); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 84ab67e438e..5bc3e740751 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -19,9 +19,10 @@ import { IGalleryExtension, IExtensionManifest, IGalleryMetadata, InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, LocalExtensionType, StatisticType, - IExtensionIdentifier + IExtensionIdentifier, + IReportedExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getGalleryExtensionIdFromLocal, adoptToGalleryExtensionId, areSameExtensions, getGalleryExtensionId, groupByExtension } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { getGalleryExtensionIdFromLocal, adoptToGalleryExtensionId, areSameExtensions, getGalleryExtensionId, groupByExtension, getMaliciousExtensionsSet } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { localizeManifest } from '../common/extensionNls'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { Limiter } from 'vs/base/common/async'; @@ -103,8 +104,9 @@ export class ExtensionManagementService implements IExtensionManagementService { private extensionsPath: string; private uninstalledPath: string; - private userDataPath: string; private uninstalledFileLimiter: Limiter; + private reportedExtensions: TPromise | undefined; + private lastReportTimestamp = 0; private disposables: IDisposable[] = []; private readonly _onInstallExtension = new Emitter(); @@ -122,20 +124,19 @@ export class ExtensionManagementService implements IExtensionManagementService { onDidUninstallExtension: Event = this._onDidUninstallExtension.event; constructor( - @IEnvironmentService environmentService: IEnvironmentService, + @IEnvironmentService private environmentService: IEnvironmentService, @IChoiceService private choiceService: IChoiceService, @IExtensionGalleryService private galleryService: IExtensionGalleryService, - @ILogService private logService: ILogService, + @ILogService private logService: ILogService ) { this.extensionsPath = environmentService.extensionsPath; this.uninstalledPath = path.join(this.extensionsPath, '.obsolete'); - this.userDataPath = environmentService.userDataPath; this.uninstalledFileLimiter = new Limiter(1); this.disposables.push(toDisposable(() => this.installingExtensions.clear())); } private deleteExtensionsManifestCache(): void { - const cacheFolder = path.join(this.userDataPath, MANIFEST_CACHE_FOLDER); + const cacheFolder = path.join(this.environmentService.userDataPath, MANIFEST_CACHE_FOLDER); const cacheFile = path.join(cacheFolder, USER_MANIFEST_CACHE_FILE); pfs.del(cacheFile).done(() => { }, () => { }); @@ -269,9 +270,22 @@ export class ExtensionManagementService implements IExtensionManagementService { private downloadAndInstallExtension(extension: IGalleryExtension): TPromise { let installingExtension = this.installingExtensions.get(extension.identifier.id); if (!installingExtension) { - installingExtension = this.downloadInstallableExtension(extension).then(installableExtension => this.installExtension(installableExtension)); + installingExtension = this.getExtensionsReport() + .then(report => { + if (getMaliciousExtensionsSet(report).has(extension.identifier.id)) { + throw new Error(nls.localize('malicious extension', "Can't install extension since it was reported to be malicious.")); + } else { + return extension; + } + }) + .then(extension => this.downloadInstallableExtension(extension)) + .then(installableExtension => this.installExtension(installableExtension)) + .then( + local => { this.installingExtensions.delete(extension.identifier.id); return local; }, + e => { this.installingExtensions.delete(extension.identifier.id); return TPromise.wrapError(e); } + ); + this.installingExtensions.set(extension.identifier.id, installingExtension); - installingExtension.then(local => { this.installingExtensions.delete(extension.identifier.id); return local; }, e => { this.installingExtensions.delete(extension.identifier.id); return TPromise.wrapError(e); }); } return installingExtension; } @@ -367,6 +381,8 @@ export class ExtensionManagementService implements IExtensionManagementService { } private installExtension(installableExtension: InstallableExtension): TPromise { + // BLOCK REPORTED EXTENSIONS HERE? + return this.unsetUninstalledAndGetLocal(installableExtension.id) .then( local => { @@ -776,6 +792,30 @@ export class ExtensionManagementService implements IExtensionManagementService { }); } + getExtensionsReport(): TPromise { + const now = new Date().getTime(); + + if (!this.reportedExtensions || now - this.lastReportTimestamp > 1000 * 60 * 5) { // 5 minute cache freshness + this.reportedExtensions = this.updateReportCache(); + this.lastReportTimestamp = now; + } + + return this.reportedExtensions; + } + + private updateReportCache(): TPromise { + this.logService.trace('ExtensionManagementService.refreshReportedCache'); + + return this.galleryService.getExtensionsReport() + .then(result => { + this.logService.trace(`ExtensionManagementService.refreshReportedCache - got ${result.length} reported extensions from service`); + return result; + }, err => { + this.logService.trace('ExtensionManagementService.refreshReportedCache - failed to get extension report'); + return []; + }); + } + dispose() { this.disposables = dispose(this.disposables); } diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index fe757879b07..ec5d37cfa9f 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -168,6 +168,11 @@ export interface IExtensionService { */ getExtensionsStatus(): { [id: string]: IExtensionsStatus }; + /** + * Check if the extension host can be profiled. + */ + canProfileExtensionHost(): boolean; + /** * Begin an extension host process profile session. */ diff --git a/src/vs/platform/issue/common/issue.ts b/src/vs/platform/issue/common/issue.ts index 5d43f4e5c4a..1f80ba156b7 100644 --- a/src/vs/platform/issue/common/issue.ts +++ b/src/vs/platform/issue/common/issue.ts @@ -7,6 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; export const ID = 'issueService'; export const IIssueService = createDecorator(ID); @@ -23,10 +24,15 @@ export interface IssueReporterStyles { buttonBackground: string; buttonForeground: string; buttonHoverBackground: string; +} + +export interface IssueReporterData { + styles: IssueReporterStyles; zoomLevel: number; + enabledExtensions: ILocalExtension[]; } export interface IIssueService { _serviceBrand: any; - openReporter(theme?: IssueReporterStyles): TPromise; + openReporter(data: IssueReporterData): TPromise; } \ No newline at end of file diff --git a/src/vs/platform/issue/common/issueIpc.ts b/src/vs/platform/issue/common/issueIpc.ts index f9f05c05ede..99d73534b5e 100644 --- a/src/vs/platform/issue/common/issueIpc.ts +++ b/src/vs/platform/issue/common/issueIpc.ts @@ -7,10 +7,10 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IIssueService, IssueReporterStyles } from './issue'; +import { IIssueService, IssueReporterData } from './issue'; export interface IIssueChannel extends IChannel { - call(command: 'openIssueReporter', arg: IssueReporterStyles): TPromise; + call(command: 'openIssueReporter', arg: IssueReporterData): TPromise; call(command: 'getStatusInfo'): TPromise; call(command: string, arg?: any): TPromise; } @@ -34,7 +34,7 @@ export class IssueChannelClient implements IIssueService { constructor(private channel: IIssueChannel) { } - openReporter(theme: IssueReporterStyles): TPromise { - return this.channel.call('openIssueReporter', theme); + openReporter(data: IssueReporterData): TPromise { + return this.channel.call('openIssueReporter', data); } } \ 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 096aec418c8..f103065344f 100644 --- a/src/vs/platform/issue/electron-main/issueService.ts +++ b/src/vs/platform/issue/electron-main/issueService.ts @@ -7,7 +7,9 @@ import { TPromise, Promise } from 'vs/base/common/winjs.base'; import { localize } from 'vs/nls'; -import { IIssueService, IssueReporterStyles } from 'vs/platform/issue/common/issue'; +import * as objects from 'vs/base/common/objects'; +import { parseArgs } from 'vs/platform/environment/node/argv'; +import { IIssueService, IssueReporterData } from 'vs/platform/issue/common/issue'; import { BrowserWindow, ipcMain } from 'electron'; import { ILaunchService } from 'vs/code/electron-main/launch'; import { buildDiagnostics, DiagnosticInfo } from 'vs/code/electron-main/diagnostics'; @@ -25,31 +27,24 @@ export class IssueService implements IIssueService { @ILaunchService private launchService: ILaunchService ) { } - openReporter(theme?: IssueReporterStyles): TPromise { + openReporter(data: IssueReporterData): TPromise { ipcMain.on('issueInfoRequest', event => { this.getStatusInfo().then(msg => { event.sender.send('issueInfoResponse', msg); }); }); - // When launching from cli, no theme is provided. Match theme if passed from workbench. - if (theme) { - ipcMain.on('issueStyleRequest', event => { - event.sender.send('issueStyleResponse', theme); - }); - } - this._issueWindow = new BrowserWindow({ width: 800, - height: 900, + height: 1000, title: localize('issueReporter', "Issue Reporter"), parent: BrowserWindow.getFocusedWindow(), - backgroundColor: theme && theme.backgroundColor || DEFAULT_BACKGROUND_COLOR + backgroundColor: data.styles.backgroundColor || DEFAULT_BACKGROUND_COLOR }); this._issueWindow.setMenuBarVisibility(false); // workaround for now, until a menu is implemented - this._issueWindow.loadURL(this.getIssueReporterPath()); + this._issueWindow.loadURL(this.getIssueReporterPath(data)); return TPromise.as(null); } @@ -68,13 +63,23 @@ export class IssueService implements IIssueService { }); } - private getIssueReporterPath() { - const config = { + private getIssueReporterPath(data: IssueReporterData) { + const windowConfiguration = { appRoot: this.environmentService.appRoot, nodeCachedDataDir: this.environmentService.nodeCachedDataDir, windowId: this._issueWindow.id, - machineId: this.machineId + machineId: this.machineId, + data }; + + const environment = parseArgs(process.argv); + const config = objects.assign(environment, windowConfiguration); + for (let key in config) { + if (config[key] === void 0 || config[key] === null || config[key] === '') { + delete config[key]; // only send over properties that have a true value + } + } + return `${require.toUrl('vs/code/electron-browser/issue/issueReporter.html')}?config=${encodeURIComponent(JSON.stringify(config))}`; } } diff --git a/src/vs/platform/request/electron-browser/requestService.ts b/src/vs/platform/request/electron-browser/requestService.ts index 513ab815132..27bb2bba0c2 100644 --- a/src/vs/platform/request/electron-browser/requestService.ts +++ b/src/vs/platform/request/electron-browser/requestService.ts @@ -51,7 +51,7 @@ export const xhrRequest: IRequestFunction = (options: IRequestOptions): TPromise setRequestHeaders(xhr, options); xhr.responseType = 'arraybuffer'; - xhr.onerror = e => reject(new Error('XHR failed: ' + xhr.statusText)); + xhr.onerror = e => reject(new Error(xhr.statusText && ('XHR failed: ' + xhr.statusText))); xhr.onload = (e) => { resolve({ res: { diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index 41c3db8d63f..1b3b0233b7b 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -75,6 +75,7 @@ const configurationValueWhitelist = [ 'editor.roundedSelection', 'editor.scrollBeyondLastLine', 'editor.minimap.enabled', + 'editor.minimap.side', 'editor.minimap.renderCharacters', 'editor.minimap.maxColumn', 'editor.find.seedSearchStringFromSelection', diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 09bafe76fc7..073054ad61a 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -270,6 +270,18 @@ declare module 'vscode' { * An event that is emitted when a breakpoint is added, removed, or changed. */ export const onDidChangeBreakpoints: Event; + + /** + * Add breakpoints. + * @param breakpoints The breakpoints to add. + */ + export function addBreakpoints(breakpoints: Breakpoint[]): Thenable; + + /** + * Remove breakpoints. + * @param breakpoints The breakpoints to remove. + */ + export function removeBreakpoints(breakpoints: Breakpoint[]): Thenable; } /** @@ -309,7 +321,7 @@ declare module 'vscode' { */ readonly hitCondition?: string; - protected constructor(enabled: boolean, condition: string, hitCondition: string); + protected constructor(enabled?: boolean, condition?: string, hitCondition?: string); } /** @@ -321,7 +333,10 @@ declare module 'vscode' { */ readonly location: Location; - private constructor(enabled: boolean, condition: string, hitCondition: string, location: Location); + /** + * Create a new breakpoint for a source location. + */ + constructor(location: Location, enabled?: boolean, condition?: string, hitCondition?: string); } /** @@ -333,7 +348,10 @@ declare module 'vscode' { */ readonly functionName: string; - private constructor(enabled: boolean, condition: string, hitCondition: string, functionName: string); + /** + * Create a new function breakpoint. + */ + constructor(functionName: string, enabled?: boolean, condition?: string, hitCondition?: string); } /** diff --git a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts index f43810a894f..82c4bf07937 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts @@ -6,10 +6,13 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import uri from 'vs/base/common/uri'; -import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint } from 'vs/workbench/parts/debug/common/debug'; +import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IRawBreakpoint } from 'vs/workbench/parts/debug/common/debug'; import { TPromise } from 'vs/base/common/winjs.base'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext, IExtHostContext, IBreakpointsDelta, ISourceBreakpointData, IFunctionBreakpointData } from '../node/extHost.protocol'; +import { + ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext, + IExtHostContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto, IBreakpointIndexDto +} from '../node/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import severity from 'vs/base/common/severity'; @@ -59,15 +62,15 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape { // set up a handler to send more this._toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(e => { if (e) { - const delta: IBreakpointsDelta = {}; + const delta: IBreakpointsDeltaDto = {}; if (e.added) { - delta.added = this.toWire(e.added); + delta.added = this.convertToDto(e.added); } if (e.removed) { delta.removed = e.removed.map(x => x.getId()); } if (e.changed) { - delta.changed = this.toWire(e.changed); + delta.changed = this.convertToDto(e.changed); } if (delta.added || delta.removed || delta.changed) { @@ -81,7 +84,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape { const fbps = this.debugService.getModel().getFunctionBreakpoints(); if (bps.length > 0 || fbps.length > 0) { this._proxy.$acceptBreakpointsDelta({ - added: this.toWire(bps).concat(this.toWire(fbps)) + added: this.convertToDto(bps).concat(this.convertToDto(fbps)) }); } } @@ -89,30 +92,66 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape { return TPromise.wrap(undefined); } - private toWire(bps: (IBreakpoint | IFunctionBreakpoint)[]): (ISourceBreakpointData | IFunctionBreakpointData)[] { + public async $registerBreakpoints(DTOs: (ISourceMultiBreakpointDto | IFunctionBreakpointDto)[]): TPromise { + const result: IBreakpointIndexDto[] = []; + for (let dto of DTOs) { + if (dto.type === 'sourceMulti') { + const sdto = dto; + const rawbps = dto.lines.map(l => + { + enabled: l.enabled, + lineNumber: l.line + 1, + column: l.character > 0 ? l.character + 1 : 0, + condition: l.condition, + hitCondition: l.hitCondition + } + ); + const bps = await this.debugService.addBreakpoints(uri.revive(dto.uri), rawbps); + bps.forEach((bp, ix) => result.push({ + index: sdto.lines[ix].index, + id: bp.getId() + })); + } else if (dto.type === 'function') { + const fbs = this.debugService.addFunctionBreakpoint(dto.functionName); + result.push({ + index: dto.index, + id: fbs.getId() + }); + } + } + return result; + } + + public $unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[]): TPromise { + breakpointIds.forEach(id => this.debugService.removeBreakpoints(id)); + functionBreakpointIds.forEach(id => this.debugService.removeFunctionBreakpoints(id)); + return void 0; + } + + private convertToDto(bps: (IBreakpoint | IFunctionBreakpoint)[]): (ISourceBreakpointDto | IFunctionBreakpointDto)[] { return bps.map(bp => { if ('name' in bp) { const fbp = bp; - return { + return { type: 'function', - id: bp.getId(), - enabled: bp.enabled, + id: fbp.getId(), + enabled: fbp.enabled, functionName: fbp.name, - hitCondition: bp.hitCondition, - /* condition: bp.condition */ + hitCondition: fbp.hitCondition, + /* condition: fbp.condition */ }; } else { const sbp = bp; - return { + return { type: 'source', - id: bp.getId(), - enabled: bp.enabled, + id: sbp.getId(), + enabled: sbp.enabled, condition: sbp.condition, - hitCondition: bp.hitCondition, + hitCondition: sbp.hitCondition, uri: sbp.uri, line: sbp.lineNumber > 0 ? sbp.lineNumber - 1 : 0, - character: (typeof sbp.column === 'number' && sbp.column > 0) ? sbp.column - 1 : 0 + character: (typeof sbp.column === 'number' && sbp.column > 0) ? sbp.column - 1 : 0, }; } }); diff --git a/src/vs/workbench/api/electron-browser/mainThreadTask.ts b/src/vs/workbench/api/electron-browser/mainThreadTask.ts index f85ee2a039a..9980e755deb 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTask.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTask.ts @@ -13,6 +13,7 @@ import { ITaskService } from 'vs/workbench/parts/tasks/common/taskService'; import { ExtHostContext, MainThreadTaskShape, ExtHostTaskShape, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +import URI from 'vs/base/common/uri'; @extHostNamedCustomer(MainContext.MainThreadTask) export class MainThreadTask implements MainThreadTaskShape { @@ -45,7 +46,7 @@ export class MainThreadTask implements MainThreadTaskShape { let uri = (task._source as any as ExtensionTaskSourceTransfer).__workspaceFolder; if (uri) { delete (task._source as any as ExtensionTaskSourceTransfer).__workspaceFolder; - (task._source as any).workspaceFolder = this._workspaceContextServer.getWorkspaceFolder(uri); + (task._source as any).workspaceFolder = this._workspaceContextServer.getWorkspaceFolder(URI.revive(uri)); } } } @@ -57,7 +58,7 @@ export class MainThreadTask implements MainThreadTaskShape { return TPromise.wrap(undefined); } - public $unregisterTaskProvider(handle: number): TPromise { + public $unregisterTaskProvider(handle: number): TPromise { this._taskService.unregisterTaskProvider(handle); delete this._activeHandles[handle]; return TPromise.wrap(undefined); diff --git a/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts b/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts index 67bd6438fe5..b2970e5f093 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts @@ -67,7 +67,7 @@ class TreeViewDataProvider implements ITreeViewDataProvider { return this.postGetElements(elements); }, err => { this.messageService.show(Severity.Error, err); - return null; + return []; }); } @@ -80,7 +80,7 @@ class TreeViewDataProvider implements ITreeViewDataProvider { return this.postGetElements(children); }, err => { this.messageService.show(Severity.Error, err); - return null; + return []; }); } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 7a88fb760b2..3b62afdfdfe 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -541,7 +541,13 @@ export function createApiFactory( }, registerDebugConfigurationProvider(debugType: string, provider: vscode.DebugConfigurationProvider) { return extHostDebugService.registerDebugConfigurationProvider(debugType, provider); - } + }, + addBreakpoints: proposedApiFunction(extension, (breakpoints: vscode.Breakpoint[]) => { + return extHostDebugService.addBreakpoints(breakpoints); + }), + removeBreakpoints: proposedApiFunction(extension, (breakpoints: vscode.Breakpoint[]) => { + return extHostDebugService.removeBreakpoints(breakpoints); + }) }; diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index d04a8c74f1a..dd1bd6574d5 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -4,13 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { - createMainContextProxyIdentifier as createMainId, - createExtHostContextProxyIdentifier as createExtId, - ProxyIdentifier, - IRPCProtocol, - ProxyType -} from 'vs/workbench/services/extensions/node/proxyIdentifier'; +import { createMainContextProxyIdentifier as createMainId, createExtHostContextProxyIdentifier as createExtId, ProxyIdentifier, IRPCProtocol } from 'vs/workbench/services/extensions/node/proxyIdentifier'; import * as vscode from 'vscode'; @@ -375,8 +369,8 @@ export interface MainThreadFileSystemShape extends IDisposable { } export interface MainThreadTaskShape extends IDisposable { - $registerTaskProvider(handle: number): TPromise; - $unregisterTaskProvider(handle: number): TPromise; + $registerTaskProvider(handle: number): TPromise; + $unregisterTaskProvider(handle: number): TPromise; } export interface MainThreadExtensionServiceShape extends IDisposable { @@ -449,6 +443,8 @@ export interface MainThreadDebugServiceShape extends IDisposable { $customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): TPromise; $appendDebugConsole(value: string): TPromise; $startBreakpointEvents(): TPromise; + $registerBreakpoints(breakpoints: (ISourceMultiBreakpointDto | IFunctionBreakpointDto)[]): TPromise; + $unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[]): TPromise; } export interface MainThreadWindowShape extends IDisposable { @@ -703,30 +699,49 @@ export interface ExtHostTaskShape { $provideTasks(handle: number): TPromise; } -export interface IBreakpointData { - type: 'source' | 'function'; - id: string; +export interface IFunctionBreakpointDto { + type: 'function'; + index: number; + id?: string; enabled: boolean; condition?: string; hitCondition?: string; + functionName: string; } -export interface ISourceBreakpointData extends IBreakpointData { +export interface ISourceBreakpointDto { type: 'source'; + id?: string; + enabled: boolean; + condition?: string; + hitCondition?: string; uri: UriComponents; line: number; character: number; } -export interface IFunctionBreakpointData extends IBreakpointData { - type: 'function'; - functionName: string; +export interface IBreakpointsDeltaDto { + added?: (ISourceBreakpointDto | IFunctionBreakpointDto)[]; + removed?: string[]; + changed?: (ISourceBreakpointDto | IFunctionBreakpointDto)[]; } -export interface IBreakpointsDelta { - added?: (ISourceBreakpointData | IFunctionBreakpointData)[]; - removed?: string[]; - changed?: (ISourceBreakpointData | IFunctionBreakpointData)[]; +export interface ISourceMultiBreakpointDto { + type: 'sourceMulti'; + uri: UriComponents; + lines: { + index: number; + enabled: boolean; + condition?: string; + hitCondition?: string; + line: number; + character: number; + }[]; +} + +export interface IBreakpointIndexDto { + index: number; + id: string; } export interface ExtHostDebugServiceShape { @@ -736,7 +751,7 @@ export interface ExtHostDebugServiceShape { $acceptDebugSessionTerminated(id: DebugSessionUUID, type: string, name: string): void; $acceptDebugSessionActiveChanged(id: DebugSessionUUID | undefined, type?: string, name?: string): void; $acceptDebugSessionCustomEvent(id: DebugSessionUUID, type: string, name: string, event: any): void; - $acceptBreakpointsDelta(delat: IBreakpointsDelta): void; + $acceptBreakpointsDelta(delat: IBreakpointsDeltaDto): void; } @@ -789,7 +804,7 @@ export const MainContext = { MainThreadFileSystem: createMainId('MainThreadFileSystem'), MainThreadExtensionService: createMainId('MainThreadExtensionService'), MainThreadSCM: createMainId('MainThreadSCM'), - MainThreadTask: createMainId('MainThreadTask', ProxyType.CustomMarshaller), + MainThreadTask: createMainId('MainThreadTask'), MainThreadWindow: createMainId('MainThreadWindow'), }; @@ -814,7 +829,7 @@ export const ExtHostContext = { ExtHostLogService: createExtId('ExtHostLogService'), ExtHostTerminalService: createExtId('ExtHostTerminalService'), ExtHostSCM: createExtId('ExtHostSCM'), - ExtHostTask: createExtId('ExtHostTask', ProxyType.CustomMarshaller), + ExtHostTask: createExtId('ExtHostTask'), ExtHostWorkspace: createExtId('ExtHostWorkspace'), ExtHostWindow: createExtId('ExtHostWindow'), }; diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 3276d4348ea..feae87b4e7d 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -7,7 +7,10 @@ import { TPromise } from 'vs/base/common/winjs.base'; import Event, { Emitter } from 'vs/base/common/event'; import { asWinJsPromise } from 'vs/base/common/async'; -import { MainContext, MainThreadDebugServiceShape, ExtHostDebugServiceShape, DebugSessionUUID, IMainContext, IBreakpointsDelta, ISourceBreakpointData, IFunctionBreakpointData } from 'vs/workbench/api/node/extHost.protocol'; +import { + MainContext, MainThreadDebugServiceShape, ExtHostDebugServiceShape, DebugSessionUUID, + IMainContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, IFunctionBreakpointDto +} from 'vs/workbench/api/node/extHost.protocol'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import * as vscode from 'vscode'; @@ -95,51 +98,162 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { return result; } - public $acceptBreakpointsDelta(delta: IBreakpointsDelta): void { + public $acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void { let a: vscode.Breakpoint[] = []; let r: vscode.Breakpoint[] = []; let c: vscode.Breakpoint[] = []; if (delta.added) { - a = delta.added.map(bpd => { - const bp = this.fromWire(bpd); + for (const bpd of delta.added) { + let bp: vscode.Breakpoint; + if (bpd.type === 'function') { + bp = new FunctionBreakpoint(bpd.functionName, bpd.enabled, bpd.condition, bpd.hitCondition); + } else { + const uri = URI.revive(bpd.uri); + bp = new SourceBreakpoint(new Location(uri, new Position(bpd.line, bpd.character)), bpd.enabled, bpd.condition, bpd.hitCondition); + } + bp['_id'] = bpd.id; this._breakpoints.set(bpd.id, bp); - return bp; - }); + a.push(bp); + } } if (delta.removed) { - r = delta.removed.map(id => { + for (const id of delta.removed) { const bp = this._breakpoints.get(id); if (bp) { this._breakpoints.delete(id); + r.push(bp); } - return bp; - }); + } } if (delta.changed) { - c = delta.changed.map(bpd => { - const bp = this.fromWire(bpd); - this._breakpoints.set(bpd.id, bp); - return bp; - }); + for (const bpd of delta.changed) { + let bp = this._breakpoints.get(bpd.id); + if (bp) { + if (bpd.type === 'function') { + const fbp = bp; + fbp.enabled = bpd.enabled; + fbp.condition = bpd.condition; + fbp.hitCondition = bpd.hitCondition; + fbp.functionName = bpd.functionName; + } else { + const sbp = bp; + sbp.enabled = bpd.enabled; + sbp.condition = bpd.condition; + sbp.hitCondition = bpd.hitCondition; + } + c.push(bp); + } + } } - this._onDidChangeBreakpoints.fire(Object.freeze({ - added: Object.freeze(a || []), - removed: Object.freeze(r || []), - changed: Object.freeze(c || []) - })); + this.fireBreakpointChanges(a, r, c); } - private fromWire(bp: ISourceBreakpointData | IFunctionBreakpointData): vscode.Breakpoint { - if (bp.type === 'function') { - return new FunctionBreakpoint(bp.enabled, bp.condition, bp.hitCondition, bp.functionName); + public addBreakpoints(breakpoints0: vscode.Breakpoint[]): TPromise { + + this.startBreakpoints(); + + // assign temporary ids for brand new breakpoints + const breakpoints: vscode.Breakpoint[] = []; + for (const bp of breakpoints0) { + let id = bp['_id']; + if (id) { // has already id + if (!this._breakpoints.has(id)) { + breakpoints.push(bp); + } + } else { + // no id -> assign temp id + breakpoints.push(bp); + } + } + + // convert to DTOs + const dtos: (ISourceMultiBreakpointDto | IFunctionBreakpointDto)[] = []; + const map = new Map(); + for (let i = 0; i < breakpoints.length; i++) { + const bp = breakpoints[i]; + if (bp instanceof SourceBreakpoint) { + let dto = map.get(bp.location.uri.toString()); + if (!dto) { + dto = { + type: 'sourceMulti', + uri: bp.location.uri, + lines: [] + }; + map.set(bp.location.uri.toString(), dto); + dtos.push(dto); + } + dto.lines.push({ + index: i, + enabled: bp.enabled, + condition: bp.condition, + hitCondition: bp.hitCondition, + line: bp.location.range.start.line, + character: bp.location.range.start.character + }); + } else if (bp instanceof FunctionBreakpoint) { + dtos.push({ + type: 'function', + index: i, + enabled: bp.enabled, + functionName: bp.functionName, + hitCondition: bp.hitCondition, + condition: bp.condition + }); + } + } + + // register with VS Code + return this._debugServiceProxy.$registerBreakpoints(dtos).then(ids => { + + // assign VS Code ids to breakpoints and store them in map + ids.forEach(id => { + const bp = breakpoints[id.index]; + bp['_id'] = id.id; + this._breakpoints.set(id.id, bp); + }); + + // send notification + this.fireBreakpointChanges(breakpoints, [], []); + + return void 0; + }); + } + + public removeBreakpoints(breakpoints0: vscode.Breakpoint[]): TPromise { + + this.startBreakpoints(); + + // remove from array + const breakpoints: vscode.Breakpoint[] = []; + for (const b of breakpoints0) { + let id = b['_id']; + if (id && this._breakpoints.delete(id)) { + breakpoints.push(b); + } + } + + // send notification + this.fireBreakpointChanges([], breakpoints, []); + + // unregister with VS Code + const ids = breakpoints.filter(bp => bp instanceof SourceBreakpoint).map(bp => bp['_id']); + const fids = breakpoints.filter(bp => bp instanceof FunctionBreakpoint).map(bp => bp['_id']); + return this._debugServiceProxy.$unregisterBreakpoints(ids, fids); + } + + private fireBreakpointChanges(added: vscode.Breakpoint[], removed: vscode.Breakpoint[], changed: vscode.Breakpoint[]) { + if (added.length > 0 || removed.length > 0 || changed.length > 0) { + this._onDidChangeBreakpoints.fire(Object.freeze({ + added: Object.freeze(added), + removed: Object.freeze(removed), + changed: Object.freeze(changed) + })); } - const uri = URI.revive(bp.uri); - return new SourceBreakpoint(bp.enabled, bp.condition, bp.hitCondition, new Location(uri, new Position(bp.line, bp.character))); } public registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider): vscode.Disposable { diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index 41cb0357367..58357c83862 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -294,11 +294,11 @@ namespace ShellConfiguration { namespace Tasks { - export function from(tasks: vscode.Task[], rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): TaskSystem.Task[] { + export function from(tasks: vscode.Task[], rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): TaskSystem.ContributedTask[] { if (tasks === void 0 || tasks === null) { return []; } - let result: TaskSystem.Task[] = []; + let result: TaskSystem.ContributedTask[] = []; for (let task of tasks) { let converted = fromSingle(task, rootFolder, extension); if (converted) { @@ -351,7 +351,7 @@ namespace Tasks { // We can't transfer a workspace folder object from the extension host to main since they differ // in shape and we don't have backwards converting function. So transfer the URI and resolve the // workspace folder on the main side. - (source as any).__workspaceFolder = workspaceFolder ? workspaceFolder.uri as URI : undefined; + (source as any as TaskSystem.ExtensionTaskSourceTransfer).__workspaceFolder = workspaceFolder ? workspaceFolder.uri as URI : undefined; let label = nls.localize('task.label', '{0}: {1}', source.label, task.name); let key = (task as types.Task).definitionKey; let kind = (task as types.Task).definition; diff --git a/src/vs/workbench/api/node/extHostTreeViews.ts b/src/vs/workbench/api/node/extHostTreeViews.ts index a1807377c88..effb25dd985 100644 --- a/src/vs/workbench/api/node/extHostTreeViews.ts +++ b/src/vs/workbench/api/node/extHostTreeViews.ts @@ -114,7 +114,7 @@ class ExtHostTreeView extends Disposable { } return null; }) - ))).then(extTreeItems => extTreeItems.map((({ element, extTreeItem }) => this.createTreeItem(element, extTreeItem, parentHandle)))); + ))).then(extTreeItems => coalesce(extTreeItems).map((({ element, extTreeItem }) => this.createTreeItem(element, extTreeItem, parentHandle)))); } getExtensionElement(treeItemHandle: TreeItemHandle): T { diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index af2825a3eb8..ce9749e81fc 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -1581,19 +1581,21 @@ export class Breakpoint { readonly condition?: string; readonly hitCondition?: string; - protected constructor(enabled: boolean, condition: string, hitCondition: string) { - this.enabled = enabled; - this.condition = condition; - this.hitCondition = hitCondition; - this.condition = condition; - this.hitCondition = hitCondition; + protected constructor(enabled?: boolean, condition?: string, hitCondition?: string) { + this.enabled = typeof enabled === 'boolean' ? enabled : true; + if (typeof condition === 'string') { + this.condition = condition; + } + if (typeof hitCondition === 'string') { + this.hitCondition = hitCondition; + } } } export class SourceBreakpoint extends Breakpoint { readonly location: Location; - constructor(enabled: boolean, condition: string, hitCondition: string, location: Location) { + constructor(location: Location, enabled?: boolean, condition?: string, hitCondition?: string) { super(enabled, condition, hitCondition); this.location = location; } @@ -1602,7 +1604,7 @@ export class SourceBreakpoint extends Breakpoint { export class FunctionBreakpoint extends Breakpoint { readonly functionName: string; - constructor(enabled: boolean, condition: string, hitCondition: string, functionName: string) { + constructor(functionName: string, enabled?: boolean, condition?: string, hitCondition?: string) { super(enabled, condition, hitCondition); this.functionName = functionName; } diff --git a/src/vs/workbench/browser/parts/editor/binaryEditor.ts b/src/vs/workbench/browser/parts/editor/binaryEditor.ts index 8d4b64f9f4b..b4cea8223f8 100644 --- a/src/vs/workbench/browser/parts/editor/binaryEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryEditor.ts @@ -10,7 +10,6 @@ import Event, { Emitter } from 'vs/base/common/event'; import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { Dimension, Builder, $ } from 'vs/base/browser/builder'; -import { ResourceViewer, ResourceViewerContext } from 'vs/base/browser/ui/resourceviewer/resourceViewer'; import { EditorModel, EditorInput, EditorOptions } from 'vs/workbench/common/editor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; @@ -19,6 +18,7 @@ import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableEle import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IWindowsService } from 'vs/platform/windows/common/windows'; +import { ResourceViewerContext, ResourceViewer } from 'vs/workbench/browser/parts/editor/resourceViewer'; /* * This class is only intended to be subclassed and not instantiated. diff --git a/src/vs/base/browser/ui/resourceviewer/resourceviewer.css b/src/vs/workbench/browser/parts/editor/media/resourceviewer.css similarity index 91% rename from src/vs/base/browser/ui/resourceviewer/resourceviewer.css rename to src/vs/workbench/browser/parts/editor/media/resourceviewer.css index 1f7b897d6b8..54dac885b18 100644 --- a/src/vs/base/browser/ui/resourceviewer/resourceviewer.css +++ b/src/vs/workbench/browser/parts/editor/media/resourceviewer.css @@ -16,11 +16,8 @@ padding: 10px 10px 0 10px; background-position: 0 0, 8px 8px; background-size: 16px 16px; - display: grid; -} - -.monaco-resource-viewer.image.full-size { - padding: 0; + display: flex; + box-sizing: border-box; } .vs .monaco-resource-viewer.image { @@ -39,13 +36,14 @@ image-rendering: pixelated; } -.monaco-resource-viewer img.untouched { +.monaco-resource-viewer img.scale-to-fit { max-width: 100%; + max-height: 100%; object-fit: contain; } .monaco-resource-viewer img { - margin: auto; /* centers the image */ + margin: auto; } .monaco-resource-viewer.zoom-in { diff --git a/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts b/src/vs/workbench/browser/parts/editor/resourceViewer.ts similarity index 53% rename from src/vs/base/browser/ui/resourceviewer/resourceViewer.ts rename to src/vs/workbench/browser/parts/editor/resourceViewer.ts index 1cc85d0ae29..4e3d9571b6d 100644 --- a/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts +++ b/src/vs/workbench/browser/parts/editor/resourceViewer.ts @@ -5,7 +5,7 @@ 'use strict'; -import 'vs/css!./resourceviewer'; +import 'vs/css!./media/resourceviewer'; import nls = require('vs/nls'); import mimes = require('vs/base/common/mime'); import URI from 'vs/base/common/uri'; @@ -16,6 +16,17 @@ import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableEle import { LRUCache } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; import { clamp } from 'vs/base/common/numbers'; +import { Themable } from 'vs/workbench/common/theme'; +import { IStatusbarItem, StatusbarItemDescriptor, IStatusbarRegistry, Extensions, StatusbarAlignment } from 'vs/workbench/browser/parts/statusbar/statusbar'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { } from 'vs/platform/workspace/common/workspace'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { Action } from 'vs/base/common/actions'; +import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; +import { memoize } from 'vs/base/common/decorators'; interface MapExtToMediaMimes { [index: string]: string; @@ -236,8 +247,95 @@ class GenericBinaryFileView { } } +type Scale = number | 'fit'; + +class ZoomStatusbarItem extends Themable implements IStatusbarItem { + showTimeout: number; + public static instance: ZoomStatusbarItem; + + private statusBarItem: HTMLElement; + + private onSelectScale?: (scale: Scale) => void; + + constructor( + @IContextMenuService private contextMenuService: IContextMenuService, + @IEditorGroupService editorGroupService: IEditorGroupService, + @IThemeService themeService: IThemeService + ) { + super(themeService); + ZoomStatusbarItem.instance = this; + this.toUnbind.push(editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); + } + + private onEditorsChanged(): void { + this.hide(); + this.onSelectScale = undefined; + } + + public show(scale: Scale, onSelectScale: (scale: number) => void) { + clearTimeout(this.showTimeout); + this.showTimeout = setTimeout(() => { + this.onSelectScale = onSelectScale; + this.statusBarItem.style.display = 'block'; + this.updateLabel(scale); + }, 0); + } + + public hide() { + this.statusBarItem.style.display = 'none'; + } + + public render(container: HTMLElement): IDisposable { + if (!this.statusBarItem && container) { + this.statusBarItem = $(container).a() + .addClass('.zoom-statusbar-item') + .on('click', () => { + this.contextMenuService.showContextMenu({ + getAnchor: () => container, + getActions: () => TPromise.as(this.zoomActions) + }); + }) + .getHTMLElement(); + this.statusBarItem.style.display = 'none'; + } + return this; + } + + private updateLabel(scale: Scale) { + this.statusBarItem.textContent = ZoomStatusbarItem.zoomLabel(scale); + } + + @memoize + private get zoomActions(): Action[] { + const scales: Scale[] = [10, 5, 2, 1, 0.5, 0.25, 'fit']; + return scales.map(scale => + new Action('zoom.' + scale, ZoomStatusbarItem.zoomLabel(scale), undefined, undefined, () => { + if (this.onSelectScale) { + this.onSelectScale(scale); + } + return null; + })); + } + + private static zoomLabel(scale: Scale): string { + return scale === 'fit' + ? nls.localize('zoom.action.fit.label', 'Whole Image') + : `${+(scale * 100).toFixed(2)}%`; + } +} + +Registry.as(Extensions.Statusbar).registerStatusbarItem( + new StatusbarItemDescriptor(ZoomStatusbarItem, StatusbarAlignment.RIGHT, 101) +); + +interface ImageState { + scale: Scale; + offsetX: number; + offsetY: number; +} + class InlineImageView { - private static readonly SCALE_PINCH_FACTOR = 0.1; + private static readonly SCALE_PINCH_FACTOR = 0.05; private static readonly SCALE_FACTOR = 1.5; private static readonly MAX_SCALE = 20; private static readonly MIN_SCALE = 0.1; @@ -256,9 +354,9 @@ class InlineImageView { private static IMAGE_RESOURCE_ETAG_CACHE = new LRUCache(100); /** - * Store the scale of an image so it can be restored when changing editor tabs + * Store the scale and position of an image so it can be restored when changing editor tabs */ - private static readonly IMAGE_SCALE_CACHE = new LRUCache(100); + private static readonly imageStateCache = new LRUCache(100); public static create( container: Builder, @@ -269,92 +367,157 @@ class InlineImageView { const context = { layout(dimension: Dimension) { } }; + + const cacheKey = descriptor.resource.toString(); + + let scaleDirection = ScaleDirection.IN; + const initialState: ImageState = InlineImageView.imageStateCache.get(cacheKey) || { scale: 'fit', offsetX: 0, offsetY: 0 }; + let scale = initialState.scale; + let img: Builder | null = null; + let imgElement: HTMLImageElement | null = null; + + function updateScale(newScale: Scale) { + if (!img || !imgElement.parentElement) { + return; + } + + if (newScale === 'fit') { + scale = 'fit'; + img.addClass('scale-to-fit'); + img.removeClass('pixelated'); + img.style('min-width', 'auto'); + img.style('width', 'auto'); + InlineImageView.imageStateCache.set(cacheKey, null); + } else { + const oldWidth = imgElement.width; + const oldHeight = imgElement.height; + + scale = clamp(newScale, InlineImageView.MIN_SCALE, InlineImageView.MAX_SCALE); + if (scale >= InlineImageView.PIXELATION_THRESHOLD) { + img.addClass('pixelated'); + } else { + img.removeClass('pixelated'); + } + + const { scrollTop, scrollLeft } = imgElement.parentElement; + const dx = (scrollLeft + imgElement.parentElement.clientWidth / 2) / imgElement.parentElement.scrollWidth; + const dy = (scrollTop + imgElement.parentElement.clientHeight / 2) / imgElement.parentElement.scrollHeight; + + img.removeClass('scale-to-fit'); + img.style('min-width', `${(imgElement.naturalWidth * scale)}px`); + img.style('width', `${(imgElement.naturalWidth * scale)}px`); + + const newWidth = imgElement.width; + const scaleFactor = (newWidth - oldWidth) / oldWidth; + + const newScrollLeft = ((oldWidth * scaleFactor * dx) + scrollLeft); + const newScrollTop = ((oldHeight * scaleFactor * dy) + scrollTop); + scrollbar.setScrollPosition({ + scrollLeft: newScrollLeft, + scrollTop: newScrollTop, + }); + + InlineImageView.imageStateCache.set(cacheKey, { scale: scale, offsetX: newScrollLeft, offsetY: newScrollTop }); + + } + ZoomStatusbarItem.instance.show(scale, updateScale); + scrollbar.scanDomNode(); + } + + function firstZoom() { + scale = imgElement.clientWidth / imgElement.naturalWidth; + updateScale(scale); + } + + $(container) + .on(DOM.EventType.KEY_DOWN, (e: KeyboardEvent, c) => { + if (!img) { + return; + } + + if (e.altKey) { + scaleDirection = ScaleDirection.OUT; + c.removeClass('zoom-in').addClass('zoom-out'); + } + }) + .on(DOM.EventType.KEY_UP, (e: KeyboardEvent, c) => { + if (!img) { + return; + } + + if (!e.altKey) { + scaleDirection = ScaleDirection.IN; + c.removeClass('zoom-out').addClass('zoom-in'); + } + }) + .on(DOM.EventType.CLICK, (e: MouseEvent) => { + if (!img) { + return; + } + + if (e.button !== 0) { + return; + } + + // left click + if (scale === 'fit') { + firstZoom(); + } + + const scaleMultiplier = scaleDirection === ScaleDirection.IN + ? InlineImageView.SCALE_FACTOR + : 1 / InlineImageView.SCALE_FACTOR; + updateScale(scale as number * scaleMultiplier); + }) + .on(DOM.EventType.WHEEL, (e: WheelEvent) => { + if (!img) { + return; + } + // pinching is reported as scroll wheel + ctrl + if (!e.ctrlKey) { + return; + } + if (scale === 'fit') { + firstZoom(); + } + + // scrolling up, pinching out should increase the scale + const delta = -e.deltaY; + updateScale(scale as number + delta * InlineImageView.SCALE_PINCH_FACTOR); + }) + .on(DOM.EventType.SCROLL, () => { + if (!imgElement || !imgElement.parentElement || scale === 'fit') { + return; + } + + const entry = InlineImageView.imageStateCache.get(cacheKey); + if (entry) { + const { scrollTop, scrollLeft } = imgElement.parentElement; + InlineImageView.imageStateCache.set(cacheKey, { scale: entry.scale, offsetX: scrollLeft, offsetY: scrollTop }); + } + }); + $(container) .empty() .addClass('image', 'zoom-in') .img({ src: InlineImageView.imageSrc(descriptor) }) - .addClass('untouched') - .on(DOM.EventType.LOAD, (e, img) => { - const imgElement = img.getHTMLElement(); - const cacheKey = descriptor.resource.toString(); - let scaleDirection = ScaleDirection.IN; - let scale = InlineImageView.IMAGE_SCALE_CACHE.get(cacheKey) || null; - if (scale) { - img.removeClass('untouched'); - updateScale(scale); - } - function setImageWidth(width) { - img.style('width', `${width}px`); - img.style('height', 'auto'); - } - function updateScale(newScale) { - scale = clamp(newScale, InlineImageView.MIN_SCALE, InlineImageView.MAX_SCALE); - if (scale >= InlineImageView.PIXELATION_THRESHOLD) { - img.addClass('pixelated'); - } else { - img.removeClass('pixelated'); - } - setImageWidth(Math.floor(imgElement.naturalWidth * scale)); - InlineImageView.IMAGE_SCALE_CACHE.set(cacheKey, scale); - scrollbar.scanDomNode(); - updateMetadata(); - } - function updateMetadata() { - if (metadataClb) { - const scale = Math.round((imgElement.width / imgElement.naturalWidth) * 10000) / 100; - metadataClb(nls.localize('imgMeta', '{0}% {1}x{2} {3}', scale, imgElement.naturalWidth, imgElement.naturalHeight, BinarySize.formatSize(descriptor.size))); - } - } - context.layout = updateMetadata; - function firstZoom() { - const { clientWidth, naturalWidth } = imgElement; - setImageWidth(clientWidth); - img.removeClass('untouched'); - scale = clientWidth / naturalWidth; - } - $(container) - .on(DOM.EventType.KEY_DOWN, (e: KeyboardEvent, c) => { - if (e.altKey) { - scaleDirection = ScaleDirection.OUT; - c.removeClass('zoom-in').addClass('zoom-out'); - } - }) - .on(DOM.EventType.KEY_UP, (e: KeyboardEvent, c) => { - if (!e.altKey) { - scaleDirection = ScaleDirection.IN; - c.removeClass('zoom-out').addClass('zoom-in'); - } - }); - $(container).on(DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => { - if (scale === null) { - firstZoom(); - } - // right click - if (e.button === 2) { - updateScale(1); - } - else { - const scaleFactor = scaleDirection === ScaleDirection.IN - ? InlineImageView.SCALE_FACTOR - : 1 / InlineImageView.SCALE_FACTOR; - updateScale(scale * scaleFactor); - } - }); - $(container).on(DOM.EventType.WHEEL, (e: WheelEvent) => { - // pinching is reported as scroll wheel + ctrl - if (!e.ctrlKey) { - return; - } - if (scale === null) { - firstZoom(); - } - // scrolling up, pinching out should increase the scale - const delta = -e.deltaY; - updateScale(scale + delta * InlineImageView.SCALE_PINCH_FACTOR); - }); - updateMetadata(); + .style('visibility', 'hidden') + .addClass('scale-to-fit') + .on(DOM.EventType.LOAD, (e, i) => { + img = i; + imgElement = img.getHTMLElement() as HTMLImageElement; + metadataClb(nls.localize('imgMeta', '{0}x{1} {2}', imgElement.naturalWidth, imgElement.naturalHeight, BinarySize.formatSize(descriptor.size))); scrollbar.scanDomNode(); + img.style('visibility', 'visible'); + updateScale(scale); + if (initialState.scale !== 'fit') { + scrollbar.setScrollPosition({ + scrollLeft: initialState.offsetX, + scrollTop: initialState.offsetY, + }); + } }); + return context; } @@ -379,3 +542,5 @@ class InlineImageView { return cached.src; } } + + diff --git a/src/vs/workbench/browser/parts/views/media/views.css b/src/vs/workbench/browser/parts/views/media/views.css index f3b98771b75..3cda0e9caf6 100644 --- a/src/vs/workbench/browser/parts/views/media/views.css +++ b/src/vs/workbench/browser/parts/views/media/views.css @@ -20,10 +20,17 @@ content: ' '; } -.file-icon-themable-tree.align-icons-and-twisties .monaco-tree-row:not(.has-children) .content::before { +.file-icon-themable-tree.align-icons-and-twisties .monaco-tree-row:not(.has-children) .content::before, +.file-icon-themable-tree.hide-arrows .monaco-tree-row .content::before { display: none; } +/** Show the twistie content if the parent has opt in icon **/ +.tree-explorer-viewlet-tree-view.file-icon-themable-tree.align-icons-and-twisties .monaco-tree-row:not(.has-children) .content.parent-has-icon::before, +.tree-explorer-viewlet-tree-view.file-icon-themable-tree.hide-arrows .monaco-tree-row .content.parent-has-icon::before { + display: inline-block; +} + .file-icon-themable-tree .monaco-tree-row.has-children.expanded .content::before { background-image: url("expanded.svg"); } @@ -49,10 +56,6 @@ background-image: url("collapsed-hc.svg"); } -.file-icon-themable-tree.hide-arrows .monaco-tree-row .content::before { - display: none; -} - .tree-explorer-viewlet-tree-view .monaco-tree .monaco-tree-row .custom-view-tree-node-item { display: flex; height: 22px; diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index a72b589137a..98235ba28b6 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -245,7 +245,8 @@ class TreeDataSource implements IDataSource { return children; }); } - return TPromise.as(null); + + return TPromise.as([]); } public shouldAutoexpand(tree: ITree, node: ITreeItem): boolean { @@ -262,6 +263,7 @@ class TreeDataSource implements IDataSource { } interface ITreeExplorerTemplateData { + container: HTMLElement; label: HTMLElement; resourceLabel: ResourceLabel; icon: HTMLElement; @@ -300,14 +302,13 @@ class TreeRenderer implements IRenderer { actionRunner: new MultipleSelectionActionRunner(() => tree.getSelection()) }); - return { label, resourceLabel, icon, actionBar }; + return { container, label, resourceLabel, icon, actionBar }; } public renderElement(tree: ITree, node: ITreeItem, templateId: string, templateData: ITreeExplorerTemplateData): void { const resource = node.resourceUri ? URI.revive(node.resourceUri) : null; const name = node.label || basename(resource.path); - const theme = this.themeService.getTheme(); - const icon = theme.type === LIGHT ? node.icon : node.iconDark; + const icon = this.themeService.getTheme().type === LIGHT ? node.icon : node.iconDark; // reset templateData.resourceLabel.clear(); @@ -331,6 +332,14 @@ class TreeRenderer implements IRenderer { templateData.actionBar.context = ({ $treeViewId: this.treeViewId, $treeItemHandle: node.handle }); templateData.actionBar.push(this.menus.getResourceActions(node), { icon: true, label: false }); + + // Fix when the theme do not show folder icons but parent has opt in icon. + DOM.toggleClass(templateData.container, 'parent-has-icon', this.hasParentHasOptInIcon(node, tree)); + } + + private hasParentHasOptInIcon(node: ITreeItem, tree: ITree): boolean { + const parent: ITreeItem = tree.getNavigator(node).parent(); + return parent ? !!(this.themeService.getTheme().type === LIGHT ? parent.icon : parent.iconDark) : false; } public disposeTemplate(tree: ITree, templateId: string, templateData: ITreeExplorerTemplateData): void { diff --git a/src/vs/workbench/electron-browser/actions.ts b/src/vs/workbench/electron-browser/actions.ts index 8d7c147db61..94d13e96a34 100644 --- a/src/vs/workbench/electron-browser/actions.ts +++ b/src/vs/workbench/electron-browser/actions.ts @@ -363,6 +363,7 @@ export class ShowStartupPerformance extends Action { if (metrics.initialStartup) { table.push({ Topic: '[main] start => app.isReady', 'Took (ms)': metrics.timers.ellapsedAppReady }); + table.push({ Topic: '[main] nls:start => nls:end', 'Took (ms)': metrics.timers.ellapsedNlsGeneration }); table.push({ Topic: '[main] app.isReady => window.loadUrl()', 'Took (ms)': metrics.timers.ellapsedWindowLoad }); } @@ -755,29 +756,41 @@ export class OpenIssueReporterAction extends Action { id: string, label: string, @IIssueService private issueService: IIssueService, - @IThemeService private themeService: IThemeService + @IThemeService private themeService: IThemeService, + @IExtensionManagementService private extensionManagementService: IExtensionManagementService, + @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService ) { super(id, label); } public run(): TPromise { - const theme = this.themeService.getTheme(); - const style = { - backgroundColor: theme.getColor(SIDE_BAR_BACKGROUND) && theme.getColor(SIDE_BAR_BACKGROUND).toString(), - color: theme.getColor(foreground).toString(), - textLinkColor: theme.getColor(textLinkForeground) && theme.getColor(textLinkForeground).toString(), - inputBackground: theme.getColor(inputBackground) && theme.getColor(inputBackground).toString(), - inputForeground: theme.getColor(inputForeground) && theme.getColor(inputForeground).toString(), - inputBorder: theme.getColor(inputBorder) && theme.getColor(inputBorder).toString(), - inputActiveBorder: theme.getColor(inputActiveOptionBorder) && theme.getColor(inputActiveOptionBorder).toString(), - inputErrorBorder: theme.getColor(inputValidationErrorBorder) && theme.getColor(inputValidationErrorBorder).toString(), - buttonBackground: theme.getColor(buttonBackground) && theme.getColor(buttonBackground).toString(), - buttonForeground: theme.getColor(buttonForeground) && theme.getColor(buttonForeground).toString(), - buttonHoverBackground: theme.getColor(buttonHoverBackground) && theme.getColor(buttonHoverBackground).toString(), - zoomLevel: webFrame.getZoomLevel() - }; - return this.issueService.openReporter(style).then(() => { - return TPromise.as(true); + return this.extensionManagementService.getInstalled(LocalExtensionType.User).then(extensions => { + const enabledExtensions = extensions.filter(extension => this.extensionEnablementService.isEnabled(extension.identifier)); + const theme = this.themeService.getTheme(); + const styles = { + backgroundColor: theme.getColor(SIDE_BAR_BACKGROUND) && theme.getColor(SIDE_BAR_BACKGROUND).toString(), + color: theme.getColor(foreground).toString(), + textLinkColor: theme.getColor(textLinkForeground) && theme.getColor(textLinkForeground).toString(), + inputBackground: theme.getColor(inputBackground) && theme.getColor(inputBackground).toString(), + inputForeground: theme.getColor(inputForeground) && theme.getColor(inputForeground).toString(), + inputBorder: theme.getColor(inputBorder) && theme.getColor(inputBorder).toString(), + inputActiveBorder: theme.getColor(inputActiveOptionBorder) && theme.getColor(inputActiveOptionBorder).toString(), + inputErrorBorder: theme.getColor(inputValidationErrorBorder) && theme.getColor(inputValidationErrorBorder).toString(), + buttonBackground: theme.getColor(buttonBackground) && theme.getColor(buttonBackground).toString(), + buttonForeground: theme.getColor(buttonForeground) && theme.getColor(buttonForeground).toString(), + buttonHoverBackground: theme.getColor(buttonHoverBackground) && theme.getColor(buttonHoverBackground).toString(), + zoomLevel: webFrame.getZoomLevel(), + extensions + }; + const issueReporterData = { + styles, + zoomLevel: webFrame.getZoomLevel(), + enabledExtensions + }; + + return this.issueService.openReporter(issueReporterData).then(() => { + return TPromise.as(true); + }); }); } } diff --git a/src/vs/workbench/electron-browser/bootstrap/index.js b/src/vs/workbench/electron-browser/bootstrap/index.js index 867ed81842e..558e8df307e 100644 --- a/src/vs/workbench/electron-browser/bootstrap/index.js +++ b/src/vs/workbench/electron-browser/bootstrap/index.js @@ -13,6 +13,7 @@ const perf = require('../../../base/common/performance'); perf.mark('renderer/started'); const path = require('path'); +const fs = require('fs'); const electron = require('electron'); const remote = electron.remote; const ipc = electron.ipcRenderer; @@ -66,6 +67,18 @@ function uriFromPath(_path) { return encodeURI('file://' + pathName); } +function readFile(file) { + return new Promise(function(resolve, reject) { + fs.readFile(file, 'utf8', function(err, data) { + if (err) { + reject(err); + return; + } + resolve(data); + }); + }); +} + function registerListeners(enableDeveloperTools) { // Devtools & reload support @@ -124,13 +137,30 @@ function main() { } catch (e) { /*noop*/ } } + if (nlsConfig._resolvedLanguagePackCoreLocation) { + let bundles = Object.create(null); + nlsConfig.loadBundle = function(bundle, language, cb) { + let result = bundles[bundle]; + if (result) { + cb(undefined, result); + return; + } + let bundleFile = path.join(nlsConfig._resolvedLanguagePackCoreLocation, bundle.replace(/\//g, '!') + '.nls.json'); + readFile(bundleFile).then(function (content) { + let json = JSON.parse(content); + bundles[bundle] = json; + cb(undefined, json); + }) + .catch(cb); + }; + } + var locale = nlsConfig.availableLanguages['*'] || 'en'; if (locale === 'zh-tw') { locale = 'zh-Hant'; } else if (locale === 'zh-cn') { locale = 'zh-Hans'; } - window.document.documentElement.setAttribute('lang', locale); const enableDeveloperTools = (process.env['VSCODE_DEV'] || !!configuration.extensionDevelopmentPath) && !configuration.extensionTestsPath; diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 598c69684af..cffb72a71e5 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -363,7 +363,7 @@ export interface IConfig extends IEnvConfig { export interface ICompound { name: string; - configurations: string[]; + configurations: (string | { name: string, folder: string })[]; } export interface IAdapterExecutable { @@ -523,7 +523,7 @@ export interface IDebugService { /** * Adds new breakpoints to the model for the file specified with the uri. Notifies debug adapter of breakpoint changes. */ - addBreakpoints(uri: uri, rawBreakpoints: IRawBreakpoint[]): TPromise; + addBreakpoints(uri: uri, rawBreakpoints: IRawBreakpoint[]): TPromise; /** * Updates the breakpoints. @@ -549,9 +549,9 @@ export interface IDebugService { removeBreakpoints(id?: string): TPromise; /** - * Adds a new no name function breakpoint. The function breakpoint should be renamed once user enters the name. + * Adds a new function breakpoint for the given name. */ - addFunctionBreakpoint(): void; + addFunctionBreakpoint(name?: string): IFunctionBreakpoint; /** * Renames an already existing function breakpoint. diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index d585e6276d8..16dd4a8a7da 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -560,6 +560,7 @@ export class Process implements IProcess { let source = new Source(raw, this.getId()); if (this.sources.has(source.uri.toString())) { source = this.sources.get(source.uri.toString()); + source.raw = raw; } else { this.sources.set(source.uri.toString(), source); } diff --git a/src/vs/workbench/parts/debug/common/debugSource.ts b/src/vs/workbench/parts/debug/common/debugSource.ts index a154158dc82..22a60851431 100644 --- a/src/vs/workbench/parts/debug/common/debugSource.ts +++ b/src/vs/workbench/parts/debug/common/debugSource.ts @@ -19,7 +19,7 @@ export class Source { public readonly uri: uri; public available: boolean; - constructor(public readonly raw: DebugProtocol.Source, sessionId: string) { + constructor(public raw: DebugProtocol.Source, sessionId: string) { if (!raw) { this.raw = { name: UNKNOWN_SOURCE_LABEL }; } @@ -110,4 +110,4 @@ export class Source { processId }; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/debug/electron-browser/callStackView.ts b/src/vs/workbench/parts/debug/electron-browser/callStackView.ts index fd458ff3c8b..123bcb9be6c 100644 --- a/src/vs/workbench/parts/debug/electron-browser/callStackView.ts +++ b/src/vs/workbench/parts/debug/electron-browser/callStackView.ts @@ -38,6 +38,7 @@ export class CallStackView extends TreeViewsViewletPanel { private onCallStackChangeScheduler: RunOnceScheduler; private settings: any; private needsRefresh: boolean; + private ignoreSelectionChangedEvent: boolean; constructor( private options: IViewletViewOptions, @@ -108,8 +109,11 @@ export class CallStackView extends TreeViewsViewletPanel { const fileResultsNavigation = new FileResultsNavigation(this.tree); this.disposables.push(fileResultsNavigation); this.disposables.push(fileResultsNavigation.openFile(e => { - const element = e.element; + if (this.ignoreSelectionChangedEvent) { + return; + } + const element = e.element; if (element instanceof StackFrame) { this.debugService.focusStackFrame(element, element.thread, element.thread.process, true); element.openInEditor(this.editorService, e.editorOptions.preserveFocus, e.sideBySide).done(undefined, errors.onUnexpectedError); @@ -140,8 +144,14 @@ export class CallStackView extends TreeViewsViewletPanel { this.onCallStackChangeScheduler.schedule(); } })); - this.disposables.push(this.debugService.getViewModel().onDidFocusStackFrame(() => - this.updateTreeSelection().done(undefined, errors.onUnexpectedError))); + this.disposables.push(this.debugService.getViewModel().onDidFocusStackFrame(() => { + if (!this.isVisible) { + this.needsRefresh = true; + return; + } + + this.updateTreeSelection().done(undefined, errors.onUnexpectedError); + })); // Schedule the update of the call stack tree if the viewlet is opened after a session started #14684 if (this.debugService.state === State.Stopped) { @@ -158,13 +168,22 @@ export class CallStackView extends TreeViewsViewletPanel { const stackFrame = this.debugService.getViewModel().focusedStackFrame; const thread = this.debugService.getViewModel().focusedThread; const process = this.debugService.getViewModel().focusedProcess; + const updateSelection = (element: IStackFrame | IProcess) => { + this.ignoreSelectionChangedEvent = true; + try { + this.tree.setSelection([element]); + } finally { + this.ignoreSelectionChangedEvent = false; + } + }; + if (!thread) { if (!process) { this.tree.clearSelection(); return TPromise.as(null); } - this.tree.setSelection([process]); + updateSelection(process); return this.tree.reveal(process); } @@ -173,7 +192,7 @@ export class CallStackView extends TreeViewsViewletPanel { return TPromise.as(null); } - this.tree.setSelection([stackFrame]); + updateSelection(stackFrame); return this.tree.reveal(stackFrame); }); } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts index a9a6226e949..65c36f84561 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts @@ -191,7 +191,18 @@ const schema: IJSONSchema = { enum: [], description: nls.localize('useUniqueNames', "Please use unique configuration names.") }, { - type: 'object' + type: 'object', + required: ['name'], + properties: { + name: { + enum: [], + description: nls.localize('app.launch.json.compound.name', "Name of compound. Appears in the launch configuration drop down menu.") + }, + folder: { + enum: [], + description: nls.localize('app.launch.json.compound.folder', "Name of folder in which the compound is located.") + } + } }] }, description: nls.localize('app.launch.json.compounds.configurations', "Names of configurations that will be started as part of this compound.") @@ -331,6 +342,7 @@ export class ConfigurationManager implements IConfigurationManager { this.toDispose.push(this.contextService.onDidChangeWorkspaceFolders(() => { this.initLaunches(); this.selectConfiguration(); + this.setCompoundSchemaValues(); })); this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration('launch')) { @@ -355,8 +367,14 @@ export class ConfigurationManager implements IConfigurationManager { private setCompoundSchemaValues(): void { const compoundConfigurationsSchema = (schema.properties['compounds'].items).properties['configurations']; - (compoundConfigurationsSchema.items).oneOf[0].enum = this.launches.map(l => + const launchNames = this.launches.map(l => l.getConfigurationNames(false)).reduce((first, second) => first.concat(second), []); + (compoundConfigurationsSchema.items).oneOf[0].enum = launchNames; + (compoundConfigurationsSchema.items).oneOf[1].properties.name.enum = launchNames; + + const folderNames = this.contextService.getWorkspace().folders.map(f => f.name); + (compoundConfigurationsSchema.items).oneOf[1].properties.folder.enum = folderNames; + jsonRegistry.registerSchema(launchSchemaId, schema); } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 462d8d630a2..04259534cc6 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -11,7 +11,6 @@ import * as strings from 'vs/base/common/strings'; import { generateUuid } from 'vs/base/common/uuid'; import uri from 'vs/base/common/uri'; import * as platform from 'vs/base/common/platform'; -import { Action } from 'vs/base/common/actions'; import { first, distinct } from 'vs/base/common/arrays'; import { isObject, isUndefinedOrNull } from 'vs/base/common/types'; import * as errors from 'vs/base/common/errors'; @@ -25,7 +24,7 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { FileChangesEvent, FileChangeType, IFileService } from 'vs/platform/files/common/files'; -import { IMessageService, CloseAction } from 'vs/platform/message/common/message'; +import { IMessageService, CloseAction, IChoiceService } from 'vs/platform/message/common/message'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; @@ -37,7 +36,7 @@ import { Model, ExceptionBreakpoint, FunctionBreakpoint, Breakpoint, Expression, import { ViewModel } from 'vs/workbench/parts/debug/common/debugViewModel'; import * as debugactions from 'vs/workbench/parts/debug/browser/debugActions'; import { ConfigurationManager } from 'vs/workbench/parts/debug/electron-browser/debugConfigurationManager'; -import { ToggleMarkersPanelAction } from 'vs/workbench/parts/markers/browser/markersPanelActions'; +import Constants from 'vs/workbench/parts/markers/common/constants'; import { ITaskService, ITaskSummary } from 'vs/workbench/parts/tasks/common/taskService'; import { TaskError } from 'vs/workbench/parts/tasks/common/taskSystem'; import { VIEWLET_ID as EXPLORER_VIEWLET_ID } from 'vs/workbench/parts/files/common/files'; @@ -53,7 +52,6 @@ import { IBroadcastService, IBroadcast } from 'vs/platform/broadcast/electron-br import { IRemoteConsoleLog, parse, getFirstFrame } from 'vs/base/node/console'; import { Source } from 'vs/workbench/parts/debug/common/debugSource'; import { TaskEvent, TaskEventKind } from 'vs/workbench/parts/tasks/common/tasks'; -import { sequence } from 'vs/base/common/async'; const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint'; const DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated'; @@ -90,6 +88,7 @@ export class DebugService implements debug.IDebugService { @IViewletService private viewletService: IViewletService, @IPanelService private panelService: IPanelService, @IMessageService private messageService: IMessageService, + @IChoiceService private choiceService: IChoiceService, @IPartService private partService: IPartService, @IWindowService private windowService: IWindowService, @IBroadcastService private broadcastService: IBroadcastService, @@ -581,11 +580,13 @@ export class DebugService implements debug.IDebugService { return this.sendAllBreakpoints(); } - public addBreakpoints(uri: uri, rawBreakpoints: debug.IRawBreakpoint[]): TPromise { - this.model.addBreakpoints(uri, rawBreakpoints); + public addBreakpoints(uri: uri, rawBreakpoints: debug.IRawBreakpoint[]): TPromise { + const bps = this.model.addBreakpoints(uri, rawBreakpoints); rawBreakpoints.forEach(rbp => aria.status(nls.localize('breakpointAdded', "Added breakpoint, line {0}, file {1}", rbp.lineNumber, uri.fsPath))); - return this.sendBreakpoints(uri); + return this.sendBreakpoints(uri).then(_ => { + return bps; + }); } public updateBreakpoints(uri: uri, data: { [id: string]: DebugProtocol.Breakpoint }): void { @@ -608,9 +609,10 @@ export class DebugService implements debug.IDebugService { return this.sendAllBreakpoints(); } - public addFunctionBreakpoint(): void { - const newFunctionBreakpoint = this.model.addFunctionBreakpoint(''); + public addFunctionBreakpoint(name?: string): debug.IFunctionBreakpoint { + const newFunctionBreakpoint = this.model.addFunctionBreakpoint(name || ''); this.viewModel.setSelectedFunctionBreakpoint(newFunctionBreakpoint); + return newFunctionBreakpoint; } public renameFunctionBreakpoint(id: string, newFunctionName: string): TPromise { @@ -693,15 +695,31 @@ export class DebugService implements debug.IDebugService { "Compound must have \"configurations\" attribute set in order to start multiple configurations."))); } - return sequence(compound.configurations.map(name => () => { + return TPromise.join(compound.configurations.map(configData => { + const name = typeof configData === 'string' ? configData : configData.name; if (name === compound.name) { return TPromise.as(null); } - let rootForName = root; - const launchesContainingName = this.configurationManager.getLaunches().filter(l => !!l.getConfiguration(name)); - if (launchesContainingName && launchesContainingName.length === 1) { - rootForName = launchesContainingName[0].workspace; + let rootForName: IWorkspaceFolder; + if (typeof configData === 'string') { + const launchesContainingName = this.configurationManager.getLaunches().filter(l => !!l.getConfiguration(name)); + if (launchesContainingName.length === 1) { + rootForName = launchesContainingName[0].workspace; + } else if (launchesContainingName.length > 1 && launchesContainingName.indexOf(launch) >= 0) { + // If there are multiple launches containing the configuration give priority to the configuration in the current launch + rootForName = launch.workspace; + } else { + return TPromise.wrapError(new Error(launchesContainingName.length === 0 ? nls.localize('noConfigurationNameInWorkspace', "Could not find launch configuration '{0}' in the workspace.", name) + : nls.localize('multipleConfigurationNamesInWorkspace', "There are multiple launch configurates `{0}` in the workspace. Use folder name to qualify the configuration.", name))); + } + } else if (configData.folder) { + const root = this.contextService.getWorkspace().folders.filter(f => f.name === configData.folder).pop(); + if (root) { + rootForName = root; + } else { + return TPromise.wrapError(new Error(nls.localize('noFolderWithName', "Can not find folder with name '{0}' for configuration '{1}' in compound '{2}'.", configData.folder, configData.name, compound.name))); + } } return this.startDebugging(rootForName, name, noDebug, topCompoundName || compound.name); @@ -775,10 +793,6 @@ export class DebugService implements debug.IDebugService { } this.toDisposeOnSessionEnd.set(sessionId, []); - const debugAnywayAction = new Action('debug.continue', nls.localize('debugAnyway', "Debug Anyway"), null, true, () => { - this.messageService.hideAll(); - return this.doCreateProcess(root, resolvedConfig, sessionId); - }); return this.runPreLaunchTask(sessionId, root, resolvedConfig.preLaunchTask).then((taskSummary: ITaskSummary) => { const errorCount = resolvedConfig.preLaunchTask ? this.markerService.getStatistics().errors : 0; @@ -788,26 +802,32 @@ export class DebugService implements debug.IDebugService { return this.doCreateProcess(root, resolvedConfig, sessionId); } - this.messageService.show(severity.Error, { - message: errorCount > 1 ? nls.localize('preLaunchTaskErrors', "Build errors have been detected during preLaunchTask '{0}'.", resolvedConfig.preLaunchTask) : - errorCount === 1 ? nls.localize('preLaunchTaskError', "Build error has been detected during preLaunchTask '{0}'.", resolvedConfig.preLaunchTask) : - nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", resolvedConfig.preLaunchTask, taskSummary.exitCode), - actions: [ - debugAnywayAction, - this.instantiationService.createInstance(ToggleMarkersPanelAction, ToggleMarkersPanelAction.ID, ToggleMarkersPanelAction.LABEL), - CloseAction - ] + const message = errorCount > 1 ? nls.localize('preLaunchTaskErrors', "Build errors have been detected during preLaunchTask '{0}'.", resolvedConfig.preLaunchTask) : + errorCount === 1 ? nls.localize('preLaunchTaskError', "Build error has been detected during preLaunchTask '{0}'.", resolvedConfig.preLaunchTask) : + nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", resolvedConfig.preLaunchTask, taskSummary.exitCode); + + return this.choiceService.choose(severity.Error, message, [nls.localize('debugAnyway', "Debug Anyway"), nls.localize('showErrors', "Show Errors"), nls.localize('cancel', "Cancel")], 2, true).then(choice => { + switch (choice) { + case 0: + return this.doCreateProcess(root, resolvedConfig, sessionId); + case 1: + return this.panelService.openPanel(Constants.MARKERS_PANEL_ID).then(() => undefined); + default: + return undefined; + } }); - return undefined; }, (err: TaskError) => { - this.messageService.show(err.severity, { - message: err.message, - actions: [ - debugAnywayAction, - this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL), - this.taskService.configureAction(), - CloseAction - ] + return this.choiceService.choose(severity.Error, err.message, [nls.localize('debugAnyway', "Debug Anyway"), debugactions.ConfigureAction.LABEL, this.taskService.configureAction().label, nls.localize('cancel', "Cancel")], 3, true).then(choice => { + switch (choice) { + case 0: + return this.doCreateProcess(root, resolvedConfig, sessionId); + case 1: + return this.configurationManager.selectedLaunch.openConfigFile(false); + case 2: + return this.taskService.configureAction().run(); + default: + return undefined; + } }); }); }, err => { @@ -1026,43 +1046,45 @@ export class DebugService implements debug.IDebugService { } public restartProcess(process: debug.IProcess, restartData?: any): TPromise { - if (process.session.capabilities.supportsRestartRequest) { - return process.session.custom('restart', null); - } - const focusedProcess = this.viewModel.focusedProcess; - const preserveFocus = focusedProcess && process.getId() === focusedProcess.getId(); - - return process.session.disconnect(true).then(() => { - if (strings.equalsIgnoreCase(process.configuration.type, 'extensionHost') && process.session.root) { - return this.broadcastService.broadcast({ - channel: EXTENSION_RELOAD_BROADCAST_CHANNEL, - payload: [process.session.root.uri.fsPath] - }); + return this.textFileService.saveAll().then(() => { + if (process.session.capabilities.supportsRestartRequest) { + return process.session.custom('restart', null); } + const focusedProcess = this.viewModel.focusedProcess; + const preserveFocus = focusedProcess && process.getId() === focusedProcess.getId(); - return new TPromise((c, e) => { - setTimeout(() => { - // Read the configuration again if a launch.json has been changed, if not just use the inmemory configuration - let config = process.configuration; - if (this.launchJsonChanged && this.configurationManager.selectedLaunch) { - this.launchJsonChanged = false; - config = this.configurationManager.selectedLaunch.getConfiguration(process.configuration.name) || config; - // Take the type from the process since the debug extension might overwrite it #21316 - config.type = process.configuration.type; - config.noDebug = process.configuration.noDebug; - } - config.__restart = restartData; - this.startDebugging(process.session.root, config).then(() => c(null), err => e(err)); - }, 300); - }); - }).then(() => { - if (preserveFocus) { - // Restart should preserve the focused process - const restartedProcess = this.model.getProcesses().filter(p => p.configuration.name === process.configuration.name).pop(); - if (restartedProcess && restartedProcess !== this.viewModel.focusedProcess) { - this.focusStackFrame(undefined, undefined, restartedProcess); + return process.session.disconnect(true).then(() => { + if (strings.equalsIgnoreCase(process.configuration.type, 'extensionHost') && process.session.root) { + return this.broadcastService.broadcast({ + channel: EXTENSION_RELOAD_BROADCAST_CHANNEL, + payload: [process.session.root.uri.fsPath] + }); } - } + + return new TPromise((c, e) => { + setTimeout(() => { + // Read the configuration again if a launch.json has been changed, if not just use the inmemory configuration + let config = process.configuration; + if (this.launchJsonChanged && this.configurationManager.selectedLaunch) { + this.launchJsonChanged = false; + config = this.configurationManager.selectedLaunch.getConfiguration(process.configuration.name) || config; + // Take the type from the process since the debug extension might overwrite it #21316 + config.type = process.configuration.type; + config.noDebug = process.configuration.noDebug; + } + config.__restart = restartData; + this.startDebugging(process.session.root, config).then(() => c(null), err => e(err)); + }, 300); + }); + }).then(() => { + if (preserveFocus) { + // Restart should preserve the focused process + const restartedProcess = this.model.getProcesses().filter(p => p.configuration.name === process.configuration.name).pop(); + if (restartedProcess && restartedProcess !== this.viewModel.focusedProcess) { + this.focusStackFrame(undefined, undefined, restartedProcess); + } + } + }); }); } diff --git a/src/vs/workbench/parts/debug/test/common/mockDebug.ts b/src/vs/workbench/parts/debug/test/common/mockDebug.ts index 7d722ef668d..737abebf932 100644 --- a/src/vs/workbench/parts/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/parts/debug/test/common/mockDebug.ts @@ -39,7 +39,7 @@ export class MockDebugService implements debug.IDebugService { public focusStackFrame(focusedStackFrame: debug.IStackFrame): void { } - public addBreakpoints(uri: uri, rawBreakpoints: debug.IRawBreakpoint[]): TPromise { + public addBreakpoints(uri: uri, rawBreakpoints: debug.IRawBreakpoint[]): TPromise { return TPromise.as(null); } @@ -57,7 +57,9 @@ export class MockDebugService implements debug.IDebugService { return TPromise.as(null); } - public addFunctionBreakpoint(): void { } + public addFunctionBreakpoint(): debug.IFunctionBreakpoint { + return null; + } public moveWatchExpression(id: string, position: number): void { } diff --git a/src/vs/workbench/parts/extensions/browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/browser/extensionEditor.ts index dd66df55fde..f101cbd65d6 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionEditor.ts @@ -33,7 +33,7 @@ import { Renderer, DataSource, Controller } from 'vs/workbench/parts/extensions/ import { RatingsWidget, InstallCountWidget } from 'vs/workbench/parts/extensions/browser/extensionsWidgets'; import { EditorOptions } from 'vs/workbench/common/editor'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { CombinedInstallAction, UpdateAction, EnableAction, DisableAction, BuiltinStatusLabelAction, ReloadAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; +import { CombinedInstallAction, UpdateAction, EnableAction, DisableAction, BuiltinStatusLabelAction, ReloadAction, MaliciousStatusLabelAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; import WebView from 'vs/workbench/parts/html/browser/webview'; import { KeybindingIO } from 'vs/workbench/services/keybinding/common/keybindingIO'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -344,6 +344,7 @@ export class ExtensionEditor extends BaseEditor { this.transientDisposables.push(ratings); const builtinStatusAction = this.instantiationService.createInstance(BuiltinStatusLabelAction); + const maliciousStatusAction = this.instantiationService.createInstance(MaliciousStatusLabelAction, true); const installAction = this.instantiationService.createInstance(CombinedInstallAction); const updateAction = this.instantiationService.createInstance(UpdateAction); const enableAction = this.instantiationService.createInstance(EnableAction); @@ -352,14 +353,15 @@ export class ExtensionEditor extends BaseEditor { installAction.extension = extension; builtinStatusAction.extension = extension; + maliciousStatusAction.extension = extension; updateAction.extension = extension; enableAction.extension = extension; disableAction.extension = extension; reloadAction.extension = extension; this.extensionActionBar.clear(); - this.extensionActionBar.push([reloadAction, updateAction, enableAction, disableAction, installAction, builtinStatusAction], { icon: true, label: true }); - this.transientDisposables.push(enableAction, updateAction, reloadAction, disableAction, installAction, builtinStatusAction); + this.extensionActionBar.push([reloadAction, updateAction, enableAction, disableAction, installAction, builtinStatusAction, maliciousStatusAction], { icon: true, label: true }); + this.transientDisposables.push(enableAction, updateAction, reloadAction, disableAction, installAction, builtinStatusAction, maliciousStatusAction); this.navbar.clear(); this.navbar.onChange(this.onNavbarChange.bind(this, extension), this, this.transientDisposables); diff --git a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts index 0b244b693db..84f9afb3ff8 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts @@ -1555,6 +1555,34 @@ export class BuiltinStatusLabelAction extends Action { } } +export class MaliciousStatusLabelAction extends Action { + + private static readonly Class = 'malicious-status'; + + private _extension: IExtension; + get extension(): IExtension { return this._extension; } + set extension(extension: IExtension) { this._extension = extension; this.update(); } + + constructor(long: boolean) { + const tooltip = localize('malicious tooltip', "This extension was reported to be malicious."); + const label = long ? tooltip : localize('malicious', "Malicious"); + super('extensions.install', label, '', false); + this.tooltip = localize('malicious tooltip', "This extension was reported to be malicious."); + } + + private update(): void { + if (this.extension && this.extension.isMalicious) { + this.class = `${MaliciousStatusLabelAction.Class} malicious`; + } else { + this.class = `${MaliciousStatusLabelAction.Class} not-malicious`; + } + } + + run(): TPromise { + return TPromise.as(null); + } +} + export class DisableAllAction extends Action { static readonly ID = 'workbench.extensions.action.disableAll'; diff --git a/src/vs/workbench/parts/extensions/browser/extensionsList.ts b/src/vs/workbench/parts/extensions/browser/extensionsList.ts index 0b588e8353c..fbe2e45ff31 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsList.ts @@ -16,7 +16,7 @@ import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; import { once } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; import { IExtension, IExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/common/extensions'; -import { InstallAction, UpdateAction, BuiltinStatusLabelAction, ManageExtensionAction, ReloadAction, extensionButtonProminentBackground, extensionButtonProminentForeground } from 'vs/workbench/parts/extensions/browser/extensionsActions'; +import { InstallAction, UpdateAction, BuiltinStatusLabelAction, ManageExtensionAction, ReloadAction, extensionButtonProminentBackground, extensionButtonProminentForeground, MaliciousStatusLabelAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { Label, RatingsWidget, InstallCountWidget } from 'vs/workbench/parts/extensions/browser/extensionsWidgets'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; @@ -97,13 +97,14 @@ export class Renderer implements IPagedRenderer { const ratingsWidget = this.instantiationService.createInstance(RatingsWidget, ratings, { small: true }); const builtinStatusAction = this.instantiationService.createInstance(BuiltinStatusLabelAction); + const maliciousStatusAction = this.instantiationService.createInstance(MaliciousStatusLabelAction, false); const installAction = this.instantiationService.createInstance(InstallAction); const updateAction = this.instantiationService.createInstance(UpdateAction); const reloadAction = this.instantiationService.createInstance(ReloadAction); const manageAction = this.instantiationService.createInstance(ManageExtensionAction); - actionbar.push([reloadAction, updateAction, installAction, builtinStatusAction, manageAction], actionOptions); - const disposables = [versionWidget, installCountWidget, ratingsWidget, builtinStatusAction, updateAction, reloadAction, manageAction, actionbar, bookmarkStyler]; + actionbar.push([reloadAction, updateAction, installAction, builtinStatusAction, maliciousStatusAction, manageAction], actionOptions); + const disposables = [versionWidget, installCountWidget, ratingsWidget, builtinStatusAction, maliciousStatusAction, updateAction, reloadAction, manageAction, actionbar, bookmarkStyler]; return { root, element, icon, name, installCount, ratings, author, description, disposables, @@ -113,6 +114,7 @@ export class Renderer implements IPagedRenderer { installCountWidget.extension = extension; ratingsWidget.extension = extension; builtinStatusAction.extension = extension; + maliciousStatusAction.extension = extension; installAction.extension = extension; updateAction.extension = extension; reloadAction.extension = extension; diff --git a/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.ts b/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.ts index e2af2e4e734..cf4aebc302c 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.ts @@ -11,6 +11,7 @@ import { QuickOpenHandler } from 'vs/workbench/browser/quickopen'; import { IExtensionsViewlet, VIEWLET_ID } from 'vs/workbench/parts/extensions/common/extensions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IMessageService, Severity } from 'vs/platform/message/common/message'; class SimpleEntry extends QuickOpenEntry { @@ -75,7 +76,8 @@ export class GalleryExtensionsHandler extends QuickOpenHandler { constructor( @IViewletService private viewletService: IViewletService, @IExtensionGalleryService private galleryService: IExtensionGalleryService, - @IExtensionManagementService private extensionsService: IExtensionManagementService + @IExtensionManagementService private extensionsService: IExtensionManagementService, + @IMessageService private messageService: IMessageService ) { super(); } @@ -97,7 +99,8 @@ export class GalleryExtensionsHandler extends QuickOpenHandler { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => viewlet.search(`@id:${text}`)) - .done(() => this.extensionsService.installFromGallery(galleryExtension)); + .then(() => this.extensionsService.installFromGallery(galleryExtension)) + .done(null, err => this.messageService.show(Severity.Error, err)); }; entries.push(new SimpleEntry(label, action)); diff --git a/src/vs/workbench/parts/extensions/browser/media/extensionActions.css b/src/vs/workbench/parts/extensions/browser/media/extensionActions.css index 8314dddb331..9ff9876d7e5 100644 --- a/src/vs/workbench/parts/extensions/browser/media/extensionActions.css +++ b/src/vs/workbench/parts/extensions/browser/media/extensionActions.css @@ -30,11 +30,13 @@ .monaco-action-bar .action-item.disabled .action-label.extension-action.enable, .monaco-action-bar .action-item.disabled .action-label.extension-action.disable, .monaco-action-bar .action-item.disabled .action-label.extension-action.reload, -.monaco-action-bar .action-item.disabled .action-label.built-in-status.user { +.monaco-action-bar .action-item.disabled .action-label.built-in-status.user, +.monaco-action-bar .action-item.disabled .action-label.malicious-status.not-malicious { display: none; } -.monaco-action-bar .action-item .action-label.built-in-status { +.monaco-action-bar .action-item .action-label.built-in-status +.monaco-action-bar .action-item .action-label.malicious-status { border-radius: 4px; color: inherit; background-color: transparent; @@ -44,7 +46,8 @@ line-height: initial; } -.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.built-in-status { +.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.built-in-status, +.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.malicious-status { font-weight: normal; } diff --git a/src/vs/workbench/parts/extensions/browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/browser/media/extensionEditor.css index 01dd0458f1d..75f9f139f12 100644 --- a/src/vs/workbench/parts/extensions/browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/browser/media/extensionEditor.css @@ -171,6 +171,7 @@ height: calc(100% - 36px); position: relative; overflow: hidden; + user-select: text; } .extension-editor > .body > .content.loading { diff --git a/src/vs/workbench/parts/extensions/common/extensions.ts b/src/vs/workbench/parts/extensions/common/extensions.ts index d90719c48f0..d26c46d117b 100644 --- a/src/vs/workbench/parts/extensions/common/extensions.ts +++ b/src/vs/workbench/parts/extensions/common/extensions.ts @@ -52,6 +52,7 @@ export interface IExtension { getReadme(): TPromise; getChangelog(): TPromise; local?: ILocalExtension; + isMalicious: boolean; } export interface IExtensionDependencies { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionProfileService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionProfileService.ts index 307d628fdd3..7a8e65fd19e 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionProfileService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionProfileService.ts @@ -16,6 +16,7 @@ import { StatusbarAlignment, IStatusbarRegistry, StatusbarItemDescriptor, Extens import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionHostProfileService, ProfileSessionState, RuntimeExtensionsInput } from 'vs/workbench/parts/extensions/electron-browser/runtimeExtensionsEditor'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IMessageService, Severity } from 'vs/platform/message/common/message'; export class ExtensionHostProfileService extends Disposable implements IExtensionHostProfileService { @@ -38,6 +39,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio @IExtensionService private readonly _extensionService: IExtensionService, @IWorkbenchEditorService private readonly _editorService: IWorkbenchEditorService, @IInstantiationService private readonly _instantiationService: IInstantiationService, + @IMessageService private readonly _messageService: IMessageService ) { super(); this._profile = null; @@ -67,6 +69,12 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio if (this._state !== ProfileSessionState.None) { return; } + + if (!this._extensionService.canProfileExtensionHost()) { + this._messageService.show(Severity.Info, nls.localize('noPro', "To profile extensions, launch with `--inspect-extensions=`.")); + return; + } + this._setState(ProfileSessionState.Starting); this._extensionService.startExtensionHostProfile().then((value) => { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index e630ffa559a..82e056f0e3b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -31,7 +31,7 @@ import { flatten, distinct } from 'vs/base/common/arrays'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { guessMimeTypes, MIME_UNKNOWN } from 'vs/base/common/mime'; import { ShowLanguageExtensionsAction } from 'vs/workbench/browser/parts/editor/editorStatus'; -import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; interface IExtensionsContent { recommendations: string[]; @@ -67,7 +67,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe @IMessageService private messageService: IMessageService, @ITelemetryService private telemetryService: ITelemetryService, @IEnvironmentService private environmentService: IEnvironmentService, - @ILifecycleService private lifecycleService: ILifecycleService + @IExtensionService private extensionService: IExtensionService ) { super(); @@ -75,9 +75,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe return; } - this.lifecycleService.when(LifecyclePhase.Eventually).then(() => { - this._suggestFileBasedRecommendations(); - }); + this._suggestFileBasedRecommendations(); this.promptWorkspaceRecommendationsPromise = this._suggestWorkspaceRecommendations(); @@ -263,6 +261,12 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe this._modelService.getModels().forEach(model => this._suggest(model)); } + private getMimeTypes(path: string): TPromise { + return this.extensionService.whenInstalledExtensionsRegistered().then(() => { + return guessMimeTypes(path); + }); + } + private _suggest(model: ITextModel): void { const uri = model.uri; let hasSuggestion = false; @@ -380,10 +384,12 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe }); }); - importantTipsPromise.then(() => { + const mimeTypesPromise = this.getMimeTypes(uri.fsPath); + TPromise.join([importantTipsPromise, mimeTypesPromise]).then(result => { + const fileExtensionSuggestionIgnoreList = JSON.parse(this.storageService.get ('extensionsAssistant/fileExtensionsSuggestionIgnore', StorageScope.GLOBAL, '[]')); - let mimeTypes = guessMimeTypes(uri.fsPath); + const mimeTypes = result[1]; let fileExtension = paths.extname(uri.fsPath); if (fileExtension) { fileExtension = fileExtension.substr(1); // Strip the dot diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index c5e6add7d77..178a39a6886 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -28,7 +28,7 @@ import { OpenExtensionsFolderAction, InstallVSIXAction } from 'vs/workbench/part import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { ExtensionEditor } from 'vs/workbench/parts/extensions/browser/extensionEditor'; -import { StatusUpdater, ExtensionsViewlet } from 'vs/workbench/parts/extensions/electron-browser/extensionsViewlet'; +import { StatusUpdater, ExtensionsViewlet, MaliciousExtensionChecker } from 'vs/workbench/parts/extensions/electron-browser/extensionsViewlet'; import { IQuickOpenRegistry, Extensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import jsonContributionRegistry = require('vs/platform/jsonschemas/common/jsonContributionRegistry'); @@ -52,6 +52,7 @@ registerSingleton(IExtensionHostProfileService, ExtensionHostProfileService); const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Running); +workbenchRegistry.registerWorkbenchContribution(MaliciousExtensionChecker, LifecyclePhase.Eventually); workbenchRegistry.registerWorkbenchContribution(ConfigureRecommendedExtensionsCommandsContributor, LifecyclePhase.Eventually); workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase.Running); workbenchRegistry.registerWorkbenchContribution(BetterMergeDisabled, LifecyclePhase.Running); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index ac4d9aafbc7..59a354f9f39 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -51,6 +51,9 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IContextKeyService, ContextKeyExpr, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { getGalleryExtensionIdFromLocal, getMaliciousExtensionsSet } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { ILogService } from 'vs/platform/log/common/log'; +import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; interface SearchInputEvent extends Event { target: HTMLInputElement; @@ -452,3 +455,49 @@ export class StatusUpdater implements IWorkbenchContribution { dispose(this.badgeHandle); } } + +export class MaliciousExtensionChecker implements IWorkbenchContribution { + + private disposables: IDisposable[]; + + constructor( + @IExtensionManagementService private extensionsManagementService: IExtensionManagementService, + @IInstantiationService private instantiationService: IInstantiationService, + @ILogService private logService: ILogService, + @IMessageService private messageService: IMessageService + ) { + this.loopCheckForMaliciousExtensions(); + } + + private loopCheckForMaliciousExtensions(): void { + this.checkForMaliciousExtensions() + .then(() => TPromise.timeout(1000 * 60 * 5)) // every five minutes + .then(() => this.loopCheckForMaliciousExtensions()); + } + + private checkForMaliciousExtensions(): TPromise { + return this.extensionsManagementService.getExtensionsReport().then(report => { + const maliciousSet = getMaliciousExtensionsSet(report); + + return this.extensionsManagementService.getInstalled(LocalExtensionType.User).then(installed => { + const maliciousExtensions = installed + .filter(e => maliciousSet.has(getGalleryExtensionIdFromLocal(e))); + + if (maliciousExtensions.length) { + return TPromise.join(maliciousExtensions.map(e => this.extensionsManagementService.uninstall(e, true).then(() => { + this.messageService.show(Severity.Warning, { + message: localize('malicious warning', "We have uninstalled '{0}' which was reported to be malicious.", getGalleryExtensionIdFromLocal(e)), + actions: [this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, localize('reloadNow', "Reload Now"))] + }); + }))); + } else { + return TPromise.as(null); + } + }); + }, err => this.logService.error(err)); + } + + dispose(): void { + this.disposables = dispose(this.disposables); + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts index 03694331729..69e6766f25c 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts @@ -234,7 +234,7 @@ export class ExtensionsListView extends ViewsViewletPanel { const languageTag = languageName ? ` tag:"${languageName}"` : ''; // Construct a rich query - return `tag:"__ext_${ext}" tag:"__ext_.${ext}" ${keywords.map(tag => `tag:"${tag}"`).join(' ')}${languageTag}`; + return `tag:"__ext_${ext}" tag:"__ext_.${ext}" ${keywords.map(tag => `tag:"${tag}"`).join(' ')}${languageTag} tag:"${ext}"`; }); if (names.length) { diff --git a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts index 566a87e56c3..23944c6caad 100644 --- a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts @@ -22,7 +22,7 @@ import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, IExtensionManifest, InstallExtensionEvent, DidInstallExtensionEvent, LocalExtensionType, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier, EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getGalleryExtensionIdFromLocal, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { getGalleryExtensionIdFromLocal, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWindowService } from 'vs/platform/windows/common/windows'; @@ -37,8 +37,8 @@ import product from 'vs/platform/node/product'; import { ILogService } from 'vs/platform/log/common/log'; import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress'; -interface IExtensionStateProvider { - (extension: Extension): ExtensionState; +interface IExtensionStateProvider { + (extension: Extension): T; } class Extension implements IExtension { @@ -47,7 +47,7 @@ class Extension implements IExtension { constructor( private galleryService: IExtensionGalleryService, - private stateProvider: IExtensionStateProvider, + private stateProvider: IExtensionStateProvider, public local: ILocalExtension, public gallery: IGalleryExtension, private telemetryService: ITelemetryService @@ -153,6 +153,8 @@ class Extension implements IExtension { return this.stateProvider(this); } + public isMalicious: boolean = false; + get installCount(): number { return this.gallery ? this.gallery.installCount : null; } @@ -321,7 +323,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { private static readonly SyncPeriod = 1000 * 60 * 60 * 12; // 12 hours _serviceBrand: any; - private stateProvider: IExtensionStateProvider; + private stateProvider: IExtensionStateProvider; private installing: IActiveExtension[] = []; private uninstalling: IActiveExtension[] = []; private installed: Extension[] = []; @@ -399,15 +401,19 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } queryGallery(options: IQueryOptions = {}): TPromise> { - return this.galleryService.query(options) - .then(result => mapPager(result, gallery => this.fromGallery(gallery))) - .then(null, err => { - if (/No extension gallery service configured/.test(err.message)) { - return TPromise.as(singlePagePager([])); - } + return this.extensionService.getExtensionsReport().then(report => { + const maliciousSet = getMaliciousExtensionsSet(report); - return TPromise.wrapError>(err); - }); + return this.galleryService.query(options) + .then(result => mapPager(result, gallery => this.fromGallery(gallery, maliciousSet))) + .then(null, err => { + if (/No extension gallery service configured/.test(err.message)) { + return TPromise.as(singlePagePager([])); + } + + return TPromise.wrapError>(err); + }); + }); } loadDependencies(extension: IExtension): TPromise { @@ -415,38 +421,47 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return TPromise.wrap(null); } - return this.galleryService.loadAllDependencies((extension).dependencies.map(id => { id })) - .then(galleryExtensions => galleryExtensions.map(galleryExtension => this.fromGallery(galleryExtension))) - .then(extensions => [...this.local, ...extensions]) - .then(extensions => { - const map = new Map(); - for (const extension of extensions) { - map.set(extension.id, extension); - } - return new ExtensionDependencies(extension, extension.id, map); - }); + return this.extensionService.getExtensionsReport().then(report => { + const maliciousSet = getMaliciousExtensionsSet(report); + + return this.galleryService.loadAllDependencies((extension).dependencies.map(id => { id })) + .then(galleryExtensions => galleryExtensions.map(galleryExtension => this.fromGallery(galleryExtension, maliciousSet))) + .then(extensions => [...this.local, ...extensions]) + .then(extensions => { + const map = new Map(); + for (const extension of extensions) { + map.set(extension.id, extension); + } + return new ExtensionDependencies(extension, extension.id, map); + }); + }); } open(extension: IExtension, sideByside: boolean = false): TPromise { return this.editorService.openEditor(this.instantiationService.createInstance(ExtensionsInput, extension), null, sideByside); } - private fromGallery(gallery: IGalleryExtension): Extension { - const installed = this.getInstalledExtensionMatchingGallery(gallery); + private fromGallery(gallery: IGalleryExtension, maliciousExtensionSet: Set): Extension { + let result = this.getInstalledExtensionMatchingGallery(gallery); - if (installed) { + if (result) { // Loading the compatible version only there is an engine property // Otherwise falling back to old way so that we will not make many roundtrips if (gallery.properties.engine) { this.galleryService.loadCompatibleVersion(gallery) - .then(compatible => compatible ? this.syncLocalWithGalleryExtension(installed, compatible) : null); + .then(compatible => compatible ? this.syncLocalWithGalleryExtension(result, compatible) : null); } else { - this.syncLocalWithGalleryExtension(installed, gallery); + this.syncLocalWithGalleryExtension(result, gallery); } - return installed; + } else { + result = new Extension(this.galleryService, this.stateProvider, null, gallery, this.telemetryService); } - return new Extension(this.galleryService, this.stateProvider, null, gallery, this.telemetryService); + if (maliciousExtensionSet.has(result.id)) { + result.isMalicious = true; + } + + return result; } private getInstalledExtensionMatchingGallery(gallery: IGalleryExtension): Extension { @@ -533,6 +548,10 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return false; } + if (extension.isMalicious) { + return false; + } + return !!(extension as Extension).gallery; } @@ -549,6 +568,10 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return undefined; } + if (extension.isMalicious) { + return TPromise.wrapError(new Error(nls.localize('malicious', "This extension is reported to be malicious."))); + } + const ext = extension as Extension; const gallery = ext.gallery; diff --git a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts index ec79e302d8c..312c16c9b5c 100644 --- a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts @@ -75,6 +75,7 @@ suite('ExtensionsActions Test', () => { setup(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', []); + instantiationService.stubPromise(IExtensionManagementService, 'getExtensionsReport', []); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage()); instantiationService.stub(IExtensionService, { getExtensions: () => TPromise.wrap([]) }); (instantiationService.get(IExtensionEnablementService)).reset(); diff --git a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index 0390501aceb..7c93cf08c8a 100644 --- a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -81,6 +81,7 @@ suite('ExtensionsWorkbenchService Test', () => { setup(() => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', []); + instantiationService.stubPromise(IExtensionManagementService, 'getExtensionsReport', []); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage()); instantiationService.stubPromise(IChoiceService, 'choose', 0); (instantiationService.get(IExtensionEnablementService)).reset(); diff --git a/src/vs/workbench/parts/feedback/electron-browser/feedback.ts b/src/vs/workbench/parts/feedback/electron-browser/feedback.ts index 6d25338079a..8fd4bf78233 100644 --- a/src/vs/workbench/parts/feedback/electron-browser/feedback.ts +++ b/src/vs/workbench/parts/feedback/electron-browser/feedback.ts @@ -171,7 +171,7 @@ export class FeedbackDropdown extends Dropdown { $('div').append($('a').attr('target', '_blank').attr('href', '#').text(nls.localize("submit a bug", "Submit a bug")).attr('tabindex', '0')) .on('click', event => { dom.EventHelper.stop(event); - this.commandService.executeCommand('workbench.action.reportIssues').done(null, errors.onUnexpectedError); + this.commandService.executeCommand('workbench.action.openIssueReporter').done(null, errors.onUnexpectedError); }) .appendTo($contactUsContainer); diff --git a/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts index 0b9c84a41c5..4171d03edc2 100644 --- a/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts @@ -660,6 +660,7 @@ class KeybindingItemRenderer implements IRenderer .keybindings-body > .keybindings-list-container .monaco-list-row:nth-child(even):not(.focused):not(.selected):not(:hover), -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:not(:focus) .monaco-list-row.focused:nth-child(even):not(.selected):not(:hover), -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:not(.focused) .monaco-list-row.focused:nth-child(even):not(.selected):not(:hover) { +.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row.odd:not(.focused):not(.selected):not(:hover), +.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:not(:focus) .monaco-list-row.focused.odd:not(.selected):not(:hover), +.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:not(.focused) .monaco-list-row.focused.odd:not(.selected):not(:hover) { background-color: rgba(130, 130, 130, 0.04); } diff --git a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts index 5f6d1157f43..8d937005e84 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts @@ -9,8 +9,9 @@ import URI from 'vs/base/common/uri'; import { onUnexpectedError, isPromiseCanceledError, getErrorMessage } from 'vs/base/common/errors'; import * as DOM from 'vs/base/browser/dom'; import { Delayer, ThrottledDelayer } from 'vs/base/common/async'; +import * as arrays from 'vs/base/common/arrays'; import { Dimension, Builder } from 'vs/base/browser/builder'; -import { ArrayNavigator, INavigator } from 'vs/base/common/iterator'; +import { ArrayNavigator } from 'vs/base/common/iterator'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { SideBySideEditorInput, EditorOptions, EditorInput } from 'vs/workbench/common/editor'; @@ -24,7 +25,7 @@ import { CodeEditor } from 'vs/editor/browser/codeEditor'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IPreferencesService, ISettingsGroup, ISetting, IFilterResult, IPreferencesSearchService, - CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, ISettingsEditorModel, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, IFilterMetadata, ISearchProvider, ISearchResult + CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, ISettingsEditorModel, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, IFilterMetadata, ISearchProvider, ISearchResult, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING } from 'vs/workbench/parts/preferences/common/preferences'; import { SettingsEditorModel, DefaultSettingsEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -119,7 +120,6 @@ export class PreferencesEditor extends BaseEditor { constructor( @IPreferencesService private preferencesService: IPreferencesService, - @IPreferencesSearchService private preferencesSearchService: IPreferencesSearchService, @ITelemetryService telemetryService: ITelemetryService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IContextKeyService private contextKeyService: IContextKeyService, @@ -155,7 +155,7 @@ export class PreferencesEditor extends BaseEditor { this._register(this.sideBySidePreferencesWidget.onFocus(() => this.lastFocusedWidget = this.sideBySidePreferencesWidget)); this._register(this.sideBySidePreferencesWidget.onDidSettingsTargetChange(target => this.switchSettings(target))); - this.preferencesRenderers = this._register(new PreferencesRenderersController(this.preferencesSearchService, this.telemetryService)); + this.preferencesRenderers = this._register(this.instantiationService.createInstance(PreferencesRenderersController)); this._register(this.preferencesRenderers.onDidFilterResultsCountChange(count => this.showSearchResultsMessage(count))); } @@ -178,6 +178,10 @@ export class PreferencesEditor extends BaseEditor { } } + public editFocusedPreference(): void { + this.preferencesRenderers.editFocusedPreference(); + } + public setInput(newInput: PreferencesEditorInput, options?: EditorOptions): TPromise { this.defaultSettingsEditorContextKey.set(true); const oldInput = this.input; @@ -282,17 +286,20 @@ export class PreferencesEditor extends BaseEditor { }); } - private showSearchResultsMessage(count: number): void { - if (this.searchWidget.getValue()) { - if (count === 0) { - this.searchWidget.showMessage(nls.localize('noSettingsFound', "No Results"), count); - } else if (count === 1) { - this.searchWidget.showMessage(nls.localize('oneSettingFound', "1 Setting Found"), count); + private showSearchResultsMessage(count: IPreferencesCount): void { + const countValue = count.count; + if (count.target) { + this.sideBySidePreferencesWidget.setResultCount(count.target, count.count); + } else if (this.searchWidget.getValue()) { + if (countValue === 0) { + this.searchWidget.showMessage(nls.localize('noSettingsFound', "No Results"), countValue); + } else if (countValue === 1) { + this.searchWidget.showMessage(nls.localize('oneSettingFound', "1 Setting Found"), countValue); } else { - this.searchWidget.showMessage(nls.localize('settingsFound', "{0} Settings Found", count), count); + this.searchWidget.showMessage(nls.localize('settingsFound', "{0} Settings Found", countValue), countValue); } } else { - this.searchWidget.showMessage(nls.localize('totalSettingsMessage', "Total {0} Settings", count), count); + this.searchWidget.showMessage(nls.localize('totalSettingsMessage', "Total {0} Settings", countValue), countValue); } } @@ -323,36 +330,18 @@ export class PreferencesEditor extends BaseEditor { } } -class SettingsNavigator implements INavigator { - - private iterator: ArrayNavigator; - - constructor(settings: ISetting[]) { - this.iterator = new ArrayNavigator(settings); - } +class SettingsNavigator extends ArrayNavigator { public next(): ISetting { - return this.iterator.next() || this.iterator.first(); + return super.next() || super.first(); } public previous(): ISetting { - return this.iterator.previous() || this.iterator.last(); + return super.previous() || super.last(); } - public parent(): ISetting { - return this.iterator.parent(); - } - - public first(): ISetting { - return this.iterator.first(); - } - - public last(): ISetting { - return this.iterator.last(); - } - - public current(): ISetting { - return this.iterator.current(); + public reset(): void { + this.index = this.start - 1; } } @@ -361,6 +350,11 @@ interface IFilterOrSearchResult { metadata: IStringDictionary; } +interface IPreferencesCount { + target?: SettingsTarget; + count: number; +} + class PreferencesRenderersController extends Disposable { private _defaultPreferencesRenderer: IPreferencesRenderer; @@ -371,19 +365,21 @@ class PreferencesRenderersController extends Disposable { private _settingsNavigator: SettingsNavigator; private _remoteFilterInProgress: TPromise; + private _prefsModelsForSearch = new Map(); private _currentLocalSearchProvider: ISearchProvider; private _currentRemoteSearchProvider: ISearchProvider; - private _currentNewExtensionsSearchProvider: ISearchProvider; private _lastQuery: string; private _lastFilterResult: IFilterOrSearchResult; - private _onDidFilterResultsCountChange: Emitter = this._register(new Emitter()); - public onDidFilterResultsCountChange: Event = this._onDidFilterResultsCountChange.event; + private _onDidFilterResultsCountChange: Emitter = this._register(new Emitter()); + public onDidFilterResultsCountChange: Event = this._onDidFilterResultsCountChange.event; constructor( - private preferencesSearchService: IPreferencesSearchService, - private telemetryService: ITelemetryService + @IPreferencesSearchService private preferencesSearchService: IPreferencesSearchService, + @ITelemetryService private telemetryService: ITelemetryService, + @IPreferencesService private preferencesService: IPreferencesService, + @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService ) { super(); } @@ -437,10 +433,8 @@ class PreferencesRenderersController extends Disposable { } this._currentRemoteSearchProvider = (updateCurrentResults && this._currentRemoteSearchProvider) || this.preferencesSearchService.getRemoteSearchProvider(query); - this._currentNewExtensionsSearchProvider = (updateCurrentResults && this._currentNewExtensionsSearchProvider) || this.preferencesSearchService.getRemoteSearchProvider(query, true); - this._remoteFilterInProgress = this.filterOrSearchPreferences(query, this._currentRemoteSearchProvider, 'nlpResult', nls.localize('nlpResult', "Natural Language Results"), 1) - .then(result => this.filterOrSearchPreferences(query, this._currentNewExtensionsSearchProvider, 'newExtensionsResult', nls.localize('newExtensionsResult', "Marketplace Extension Results"), 2)); + this._remoteFilterInProgress = this.filterOrSearchPreferences(query, this._currentRemoteSearchProvider, 'nlpResult', nls.localize('nlpResult', "Natural Language Results"), 1, updateCurrentResults); return this._remoteFilterInProgress.then(() => { this._remoteFilterInProgress = null; @@ -454,16 +448,25 @@ class PreferencesRenderersController extends Disposable { } localFilterPreferences(query: string, updateCurrentResults?: boolean): TPromise { + if (this._settingsNavigator) { + this._settingsNavigator.reset(); + } + this._currentLocalSearchProvider = (updateCurrentResults && this._currentLocalSearchProvider) || this.preferencesSearchService.getLocalSearchProvider(query); - return this.filterOrSearchPreferences(query, this._currentLocalSearchProvider, 'filterResult', nls.localize('filterResult', "Filtered Results"), 0); + return this.filterOrSearchPreferences(query, this._currentLocalSearchProvider, 'filterResult', nls.localize('filterResult', "Filtered Results"), 0, updateCurrentResults); } - private filterOrSearchPreferences(query: string, searchProvider: ISearchProvider, groupId: string, groupLabel: string, groupOrder: number): TPromise { + private filterOrSearchPreferences(query: string, searchProvider: ISearchProvider, groupId: string, groupLabel: string, groupOrder: number, editableContentOnly?: boolean): TPromise { this._lastQuery = query; - const filterPs = [ - this._filterOrSearchPreferences(query, this.defaultPreferencesRenderer, searchProvider, groupId, groupLabel, groupOrder), - this._filterOrSearchPreferences(query, this.editablePreferencesRenderer, searchProvider, groupId, groupLabel, groupOrder)]; + const filterPs = []; + if (!editableContentOnly) { + filterPs.push( + this._filterOrSearchPreferences(query, this.defaultPreferencesRenderer, searchProvider, groupId, groupLabel, groupOrder)); + } + + filterPs.push(this._filterOrSearchPreferences(query, this.editablePreferencesRenderer, searchProvider, groupId, groupLabel, groupOrder), + this.updateSettingsTargetCounts(query, searchProvider, groupId, groupLabel, groupOrder)); return TPromise.join(filterPs).then(results => { const [defaultFilterResult, editableFilterResult] = results; @@ -478,6 +481,50 @@ class PreferencesRenderersController extends Disposable { }); } + private updateSettingsTargetCounts(query: string, searchProvider: ISearchProvider, groupId: string, groupLabel: string, groupOrder: number): TPromise { + const searchPs = [ + this.searchSettingsTarget(searchProvider, ConfigurationTarget.WORKSPACE, groupId, groupLabel, groupOrder), + this.searchSettingsTarget(searchProvider, ConfigurationTarget.USER, groupId, groupLabel, groupOrder) + ]; + + for (const folder of this.workspaceContextService.getWorkspace().folders) { + const folderSettingsResource = this.preferencesService.getFolderSettingsResource(folder.uri); + searchPs.push(this.searchSettingsTarget(searchProvider, folderSettingsResource, groupId, groupLabel, groupOrder)); + } + + + return TPromise.join(searchPs).then(() => { }); + } + + private searchSettingsTarget(provider: ISearchProvider, target: SettingsTarget, groupId: string, groupLabel: string, groupOrder: number): TPromise { + return this.getPreferencesEditorModel(target).then(model => { + return this._filterOrSearchPreferencesModel('', model, provider, groupId, groupLabel, groupOrder); + }).then(result => { + const count = result ? this._flatten(result.filteredGroups).length : 0; + this._onDidFilterResultsCountChange.fire({ target, count }); + }, err => { + if (!isPromiseCanceledError(err)) { + return TPromise.wrapError(err); + } + + return null; + }); + } + + private async getPreferencesEditorModel(target: SettingsTarget): TPromise { + const resource = target === ConfigurationTarget.USER ? this.preferencesService.userSettingsResource : + target === ConfigurationTarget.WORKSPACE ? this.preferencesService.workspaceSettingsResource : + target; + + const targetKey = resource.toString(); + if (!this._prefsModelsForSearch.has(targetKey)) { + const model = this._register(await this.preferencesService.createPreferencesEditorModel(resource)); + this._prefsModelsForSearch.set(targetKey, model); + } + + return this._prefsModelsForSearch.get(targetKey); + } + focusNextPreference(forward: boolean = true) { if (!this._settingsNavigator) { return; @@ -488,45 +535,66 @@ class PreferencesRenderersController extends Disposable { this._focusPreference(setting, this._editablePreferencesRenderer); } - private _filterOrSearchPreferences(filter: string, preferencesRenderer: IPreferencesRenderer, provider: ISearchProvider, groupId: string, groupLabel: string, groupOrder: number): TPromise { - if (preferencesRenderer) { - const model = preferencesRenderer.preferencesModel; - const searchP = provider ? provider.searchModel(model) : TPromise.wrap(null); - return searchP - .then(null, err => { - if (isPromiseCanceledError(err)) { - return TPromise.wrapError(err); - } else { - /* __GDPR__ - "defaultSettings.searchError" : { - "message": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - const message = getErrorMessage(err); - this.telemetryService.publicLog('defaultSettings.searchError', { message }); - return null; - } - }) - .then(searchResult => { - const filterResult = searchResult ? - model.updateResultGroup(groupId, { - id: groupId, - label: groupLabel, - result: searchResult, - order: groupOrder - }) : - model.updateResultGroup(groupId, null); - - if (filterResult) { - filterResult.query = filter; - } - - preferencesRenderer.filterPreferences(filterResult); - return filterResult; - }); + editFocusedPreference(): void { + if (!this._settingsNavigator || !this._settingsNavigator.current()) { + return; } - return TPromise.wrap(null); + const setting = this._settingsNavigator.current(); + const shownInEditableRenderer = this._editablePreferencesRenderer.editPreference(setting); + if (!shownInEditableRenderer) { + this.defaultPreferencesRenderer.editPreference(setting); + } + } + + private _filterOrSearchPreferences(filter: string, preferencesRenderer: IPreferencesRenderer, provider: ISearchProvider, groupId: string, groupLabel: string, groupOrder: number): TPromise { + if (!preferencesRenderer) { + return TPromise.wrap(null); + } + + const model = preferencesRenderer.preferencesModel; + return this._filterOrSearchPreferencesModel(filter, model, provider, groupId, groupLabel, groupOrder).then(filterResult => { + preferencesRenderer.filterPreferences(filterResult); + return filterResult; + }); + } + + private _filterOrSearchPreferencesModel(filter: string, model: ISettingsEditorModel, provider: ISearchProvider, groupId: string, groupLabel: string, groupOrder: number): TPromise { + const searchP = provider ? provider.searchModel(model) : TPromise.wrap(null); + return searchP + .then(null, err => { + if (isPromiseCanceledError(err)) { + return TPromise.wrapError(err); + } else { + /* __GDPR__ + "defaultSettings.searchError" : { + "message": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + const message = getErrorMessage(err).trim(); + if (message) { + // Empty message = any generic network error + this.telemetryService.publicLog('defaultSettings.searchError', { message }); + } + return null; + } + }) + .then(searchResult => { + const filterResult = searchResult ? + model.updateResultGroup(groupId, { + id: groupId, + label: groupLabel, + result: searchResult, + order: groupOrder + }) : + model.updateResultGroup(groupId, null); + + if (filterResult) { + filterResult.query = filter; + } + + return filterResult; + }); } private consolidateAndUpdate(defaultFilterResult: IFilterResult, editableFilterResult: IFilterResult): void { @@ -534,9 +602,24 @@ class PreferencesRenderersController extends Disposable { const editablePreferencesFilteredGroups = editableFilterResult ? editableFilterResult.filteredGroups : this._getAllPreferences(this._editablePreferencesRenderer); const consolidatedSettings = this._consolidateSettings(editablePreferencesFilteredGroups, defaultPreferencesFilteredGroups); - this._settingsNavigator = new SettingsNavigator(this._lastQuery ? consolidatedSettings : []); + // Maintain the current navigation position when updating SettingsNavigator + const current = this._settingsNavigator && this._settingsNavigator.current(); + const navigatorSettings = this._lastQuery ? consolidatedSettings : []; + const currentIndex = current ? + arrays.firstIndex(navigatorSettings, s => s.key === current.key) : + -1; + + this._settingsNavigator = new SettingsNavigator(navigatorSettings, Math.max(currentIndex, 0)); + + if (currentIndex >= 0) { + this._settingsNavigator.next(); + const newCurrent = this._settingsNavigator.current(); + this._focusPreference(newCurrent, this._defaultPreferencesRenderer); + this._focusPreference(newCurrent, this._editablePreferencesRenderer); + } + const totalCount = consolidatedSettings.length; - this._onDidFilterResultsCountChange.fire(totalCount); + this._onDidFilterResultsCountChange.fire({ count: totalCount }); } private _getAllPreferences(preferencesRenderer: IPreferencesRenderer): ISettingsGroup[] { @@ -562,8 +645,8 @@ class PreferencesRenderersController extends Disposable { } private _consolidateSettings(editableSettingsGroups: ISettingsGroup[], defaultSettingsGroups: ISettingsGroup[]): ISetting[] { - const editableSettings = this._flatten(editableSettingsGroups); - const defaultSettings = this._flatten(defaultSettingsGroups).filter(secondarySetting => editableSettings.every(primarySetting => primarySetting.key !== secondarySetting.key)); + const defaultSettings = this._flatten(defaultSettingsGroups); + const editableSettings = this._flatten(editableSettingsGroups).filter(secondarySetting => defaultSettings.every(primarySetting => primarySetting.key !== secondarySetting.key)); return [...defaultSettings, ...editableSettings]; } @@ -685,6 +768,10 @@ class SideBySidePreferencesWidget extends Widget { }); } + public setResultCount(settingsTarget: SettingsTarget, count: number): void { + this.settingsTargetsWidget.setResultCount(settingsTarget, count); + } + public layout(dimension: Dimension): void { this.dimension = dimension; this.sash.setDimenesion(this.dimension); @@ -1165,3 +1252,20 @@ const focusPreviousSearchResultCommand = new FocusPreviousSearchResultCommand({ kbOpts: { primary: KeyMod.Shift | KeyCode.Enter } }); KeybindingsRegistry.registerCommandAndKeybindingRule(focusPreviousSearchResultCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib())); + +class EditFocusedSettingCommand extends SettingsCommand { + + public runCommand(accessor: ServicesAccessor, args: any): void { + const preferencesEditor = this.getPreferencesEditor(accessor); + if (preferencesEditor) { + preferencesEditor.editFocusedPreference(); + } + } + +} +const editFocusedSettingCommand = new EditFocusedSettingCommand({ + id: SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, + precondition: CONTEXT_SETTINGS_SEARCH_FOCUS, + kbOpts: { primary: KeyMod.CtrlCmd | KeyCode.US_DOT } +}); +KeybindingsRegistry.registerCommandAndKeybindingRule(editFocusedSettingCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib())); diff --git a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts index 4a9efa1869d..ebfb9efbaae 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts @@ -9,6 +9,7 @@ import { Delayer } from 'vs/base/common/async'; import * as arrays from 'vs/base/common/arrays'; import * as strings from 'vs/base/common/strings'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Position } from 'vs/editor/common/core/position'; import { IAction } from 'vs/base/common/actions'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import Event, { Emitter } from 'vs/base/common/event'; @@ -36,6 +37,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { ITextModel, IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/model'; import { CodeLensProviderRegistry, CodeLensProvider, ICodeLensSymbol } from 'vs/editor/common/modes'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { getDomNodePagePosition } from 'vs/base/browser/dom'; export interface IPreferencesRenderer extends IDisposable { readonly preferencesModel: IPreferencesEditorModel; @@ -52,6 +54,7 @@ export interface IPreferencesRenderer extends IDisposable { focusPreference(setting: T): void; clearFocus(setting: T): void; filterPreferences(filterResult: IFilterResult): void; + editPreference(setting: T): boolean; } export class UserSettingsRenderer extends Disposable implements IPreferencesRenderer { @@ -186,6 +189,10 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend public clearFocus(setting: ISetting): void { this.settingHighlighter.clear(true); } + + public editPreference(setting: ISetting): boolean { + return this.editSettingActionRenderer.activateOnSetting(setting); + } } export class WorkspaceSettingsRenderer extends UserSettingsRenderer implements IPreferencesRenderer { @@ -311,7 +318,7 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR if (filterResult) { this.filteredMatchesRenderer.render(filterResult, this.preferencesModel.settingsGroups); - this.settingsGroupTitleRenderer.render(filterResult.filteredGroups); + this.settingsGroupTitleRenderer.render(null); this.feedbackWidgetRenderer.render(filterResult); this.settingsHeaderRenderer.render(filterResult); this.settingHighlighter.clear(true); @@ -377,6 +384,10 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR public updatePreference(key: string, value: any, source: ISetting): void { } + + public editPreference(setting: ISetting): boolean { + return this.editSettingActionRenderer.activateOnSetting(setting); + } } export interface HiddenAreasProvider { @@ -407,12 +418,12 @@ export class BracesHidingRenderer extends Disposable implements HiddenAreasProvi } ]; - const hideBraces = group => { + const hideBraces = (group: ISettingsGroup, hideExtraLine?: boolean) => { // Opening curly brace hiddenAreas.push({ startLineNumber: group.range.startLineNumber - 3, startColumn: 1, - endLineNumber: group.range.startLineNumber - 3, + endLineNumber: group.range.startLineNumber - (hideExtraLine ? 1 : 3), endColumn: 1 }); @@ -425,9 +436,9 @@ export class BracesHidingRenderer extends Disposable implements HiddenAreasProvi }); }; - this._settingsGroups.forEach(hideBraces); + this._settingsGroups.forEach(g => hideBraces(g)); if (this._result) { - this._result.filteredGroups.forEach(hideBraces); + this._result.filteredGroups.forEach((g, i) => hideBraces(g, true)); } // Closing square brace @@ -621,7 +632,6 @@ export class FeedbackWidgetRenderer extends Disposable { const result = this._currentResult; const metadata = result.metadata['nlpResult']; // Feedback only on nlpResult set for now - const marketplaceExtensionsResults = result.metadata['newExtensionsResult'] && result.metadata['newExtensionsResult'].scoredResults; const actualResults = metadata ? metadata.scoredResults : {}; const actualResultIds = Object.keys(actualResults); @@ -638,10 +648,14 @@ export class FeedbackWidgetRenderer extends Disposable { }); feedbackQuery['alts'] = []; + const groupCountsText = result.filteredGroups + .map(group => `// ${group.id}: ${group.sections[0].settings.length}`) + .join('\n'); + const contents = FeedbackWidgetRenderer.INSTRUCTION_TEXT + '\n' + JSON.stringify(feedbackQuery, undefined, ' ') + '\n\n' + this.getScoreText(actualResults) + '\n\n' + - this.getScoreText(marketplaceExtensionsResults) + '\n'; + groupCountsText + '\n'; this.editorService.openEditor({ contents, language: 'jsonc' }, /*sideBySide=*/true).then(feedbackEditor => { const sendFeedbackWidget = this._register(this.instantiationService.createInstance(FloatingClickWidget, feedbackEditor.getControl(), 'Send feedback', null)); @@ -1097,6 +1111,32 @@ class EditSettingRenderer extends Disposable { }); } + public activateOnSetting(setting: ISetting): boolean { + const startLine = setting.keyRange.startLineNumber; + const settings = this.getSettings(startLine); + if (!settings.length) { + return false; + } + + this.editPreferenceWidgetForMouseMove.show(startLine, '', settings); + const actions = this.getActions(this.editPreferenceWidgetForMouseMove.preferences[0], this.getConfigurationsMap()[this.editPreferenceWidgetForMouseMove.preferences[0].key]); + this.contextMenuService.showContextMenu({ + getAnchor: () => this.toAbsoluteCoords(new Position(startLine, 1)), + getActions: () => TPromise.wrap(actions) + }); + + return true; + } + + private toAbsoluteCoords(position: Position): { x: number, y: number } { + const positionCoords = this.editor.getScrolledVisiblePosition(position); + const editorCoords = getDomNodePagePosition(this.editor.getDomNode()); + const x = editorCoords.left + positionCoords.left; + const y = editorCoords.top + positionCoords.top + positionCoords.height; + + return { x, y: y + 10 }; + } + private getConfigurationsMap(): { [qualifiedKey: string]: IConfigurationPropertySchema } { return Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); } diff --git a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts index 78cba03e94d..54e0f675b06 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts @@ -281,6 +281,7 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone { export class FolderSettingsActionItem extends BaseActionItem { private _folder: IWorkspaceFolder; + private _count: number; private container: HTMLElement; private anchorElement: HTMLElement; @@ -310,6 +311,11 @@ export class FolderSettingsActionItem extends BaseActionItem { this.update(); } + public setCount(value: number): void { + this._count = value; + this.update(); + } + public render(container: HTMLElement): void { this.builder = $(container); @@ -381,10 +387,18 @@ export class FolderSettingsActionItem extends BaseActionItem { if (this._folder) { this.labelElement.textContent = this._folder.name; this.anchorElement.title = this._folder.name; - this.detailsElement.textContent = this._action.label; + let detailsText = this._action.label; + if (this._count) { + detailsText += ` (${this._count})`; + } + this.detailsElement.textContent = detailsText; DOM.toggleClass(this.dropDownElement, 'hide', workspace.folders.length === 1 || !this._action.checked); } else { - this.labelElement.textContent = this._action.label; + let labelText = this._action.label; + if (this._count) { + labelText += ` (${this._count})`; + } + this.labelElement.textContent = labelText; this.detailsElement.textContent = ''; this.anchorElement.title = this._action.label; DOM.removeClass(this.dropDownElement, 'hide'); @@ -436,6 +450,7 @@ export class SettingsTargetsWidget extends Widget { private userSettings: Action; private workspaceSettings: Action; private folderSettings: FolderSettingsActionItem; + private folderSettingCounts = new Map(); private _settingsTarget: SettingsTarget; @@ -492,6 +507,30 @@ export class SettingsTargetsWidget extends Widget { } } + public setResultCount(settingsTarget: SettingsTarget, count: number): void { + if (settingsTarget === ConfigurationTarget.WORKSPACE) { + let label = localize('workspaceSettings', "Workspace Settings"); + if (count) { + label += ` (${count})`; + } + + this.workspaceSettings.label = label; + } else if (settingsTarget === ConfigurationTarget.USER) { + let label = localize('userSettings', "User Settings"); + if (count) { + label += ` (${count})`; + } + + this.userSettings.label = label; + } else if (settingsTarget instanceof URI) { + this.folderSettingCounts.set(settingsTarget.toString(), count); + + let total = 0; + this.folderSettingCounts.forEach(count => total += count); + this.folderSettings.setCount(total); + } + } + private onWorkbenchStateChanged(): void { this.folderSettings.folder = null; this.update(); diff --git a/src/vs/workbench/parts/preferences/common/preferences.ts b/src/vs/workbench/parts/preferences/common/preferences.ts index 519887d8e01..89ec595b52e 100644 --- a/src/vs/workbench/parts/preferences/common/preferences.ts +++ b/src/vs/workbench/parts/preferences/common/preferences.ts @@ -215,6 +215,7 @@ export const SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS = 'settings.action.cle export const SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING = 'settings.action.focusNextSetting'; export const SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING = 'settings.action.focusPreviousSetting'; export const SETTINGS_EDITOR_COMMAND_FOCUS_FILE = 'settings.action.focusSettingsFile'; +export const SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING = 'settings.action.editFocusedSetting'; export const KEYBINDINGS_EDITOR_COMMAND_SEARCH = 'keybindings.editor.searchKeybindings'; export const KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS = 'keybindings.editor.clearSearchResults'; export const KEYBINDINGS_EDITOR_COMMAND_DEFINE = 'keybindings.editor.defineKeybinding'; diff --git a/src/vs/workbench/parts/preferences/common/preferencesModels.ts b/src/vs/workbench/parts/preferences/common/preferencesModels.ts index af64f644416..f01c87d6a13 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesModels.ts @@ -64,7 +64,7 @@ export abstract class AbstractSettingsModel extends EditorModel { if (groupMatched || settingMatchResult) { filterMatches.push({ - setting: this.copySetting(setting), + setting, matches: settingMatchResult && settingMatchResult.matches, score: settingMatchResult ? settingMatchResult.score : 0 }); @@ -73,22 +73,7 @@ export abstract class AbstractSettingsModel extends EditorModel { } } - return filterMatches - .sort((a, b) => b.score - a.score) - .map(filteredMatch => { - // Fix match ranges to offset from setting start line - return { - setting: filteredMatch.setting, - score: filteredMatch.score, - matches: filteredMatch.matches && filteredMatch.matches.map(match => { - return new Range( - match.startLineNumber - filteredMatch.setting.range.startLineNumber, - match.startColumn, - match.endLineNumber - filteredMatch.setting.range.startLineNumber, - match.endColumn); - }) - }; - }); + return filterMatches.sort((a, b) => b.score - a.score); } public getPreference(key: string): ISetting { @@ -104,17 +89,6 @@ export abstract class AbstractSettingsModel extends EditorModel { return null; } - private copySetting(setting: ISetting): ISetting { - return { - description: setting.description, - key: setting.key, - value: setting.value, - range: setting.range, - overrides: [], - overrideOf: setting.overrideOf - }; - } - protected collectMetadata(groups: ISearchResultGroup[]): IStringDictionary { const metadata = Object.create(null); let hasMetadata = false; @@ -710,6 +684,22 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements } private writeSettingsGroupToBuilder(builder: SettingsContentBuilder, settingsGroup: ISettingsGroup, filterMatches: ISettingMatch[]): IRange[] { + filterMatches = filterMatches + .map(filteredMatch => { + // Fix match ranges to offset from setting start line + return { + setting: filteredMatch.setting, + score: filteredMatch.score, + matches: filteredMatch.matches && filteredMatch.matches.map(match => { + return new Range( + match.startLineNumber - filteredMatch.setting.range.startLineNumber, + match.startColumn, + match.endLineNumber - filteredMatch.setting.range.startLineNumber, + match.endColumn); + }) + }; + }); + builder.pushGroup(settingsGroup); builder.pushLine(','); @@ -731,6 +721,17 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements return fixedMatches; } + private copySetting(setting: ISetting): ISetting { + return { + description: setting.description, + key: setting.key, + value: setting.value, + range: setting.range, + overrides: [], + overrideOf: setting.overrideOf + }; + } + public findValueMatches(filter: string, setting: ISetting): IRange[] { return []; } @@ -756,7 +757,7 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements titleRange: null, sections: [ { - settings: resultGroup.result.filterMatches.map(m => m.setting) + settings: resultGroup.result.filterMatches.map(m => this.copySetting(m.setting)) } ] }; diff --git a/src/vs/workbench/parts/preferences/electron-browser/preferencesSearch.ts b/src/vs/workbench/parts/preferences/electron-browser/preferencesSearch.ts index ac34222b586..5c7d45b1c92 100644 --- a/src/vs/workbench/parts/preferences/electron-browser/preferencesSearch.ts +++ b/src/vs/workbench/parts/preferences/electron-browser/preferencesSearch.ts @@ -69,13 +69,10 @@ export class PreferencesSearchService extends Disposable implements IPreferences } getRemoteSearchProvider(filter: string, newExtensionsOnly = false): ISearchProvider { - const workbenchSettings = this.configurationService.getValue().workbench.settings; - const opts: IRemoteSearchProviderOptions = { filter, newExtensionsOnly, - endpoint: this._endpoint, - usePost: workbenchSettings.useNaturalLanguageSearchPost + endpoint: this._endpoint }; return this.remoteSearchAllowed && this.instantiationService.createInstance(RemoteSearchProvider, opts, this._installedExtensions); @@ -127,10 +124,12 @@ interface IRemoteSearchProviderOptions { filter: string; endpoint: IEndpointDetails; newExtensionsOnly: boolean; - usePost: boolean; } class RemoteSearchProvider implements ISearchProvider { + // Must keep extension filter size under 8kb. 42 extension filters + core buildnum filter puts us there. + private static MAX_EXTENSION_FILTERS = 42; + private _remoteSearchP: TPromise; constructor(private options: IRemoteSearchProviderOptions, private installedExtensions: TPromise, @@ -138,10 +137,9 @@ class RemoteSearchProvider implements ISearchProvider { @IRequestService private requestService: IRequestService, @ILogService private logService: ILogService ) { - this._remoteSearchP = (this.options.newExtensionsOnly && !this.options.usePost) ? TPromise.wrap(null) : - this.options.filter ? - this.getSettingsFromBing(this.options.filter) : - TPromise.wrap(null); + this._remoteSearchP = this.options.filter ? + this.getSettingsFromBing(this.options.filter) : + TPromise.wrap(null); } searchModel(preferencesModel: ISettingsEditorModel): TPromise { @@ -260,7 +258,7 @@ class RemoteSearchProvider implements ISearchProvider { scoredResults[getSettingKey(setting.key, 'core')] || // core setting scoredResults[getSettingKey(setting.key)]; // core setting from original prod endpoint if (remoteSetting && remoteSetting.score >= minScore) { - const settingMatches = new SettingMatches(this.options.filter, setting, false, false, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; + const settingMatches = new SettingMatches(this.options.filter, setting, false, true, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; return { matches: settingMatches, score: remoteSetting.score }; } @@ -284,30 +282,23 @@ class RemoteSearchProvider implements ISearchProvider { url += `${API_VERSION}&${QUERY_TYPE}`; } - if (this.options.usePost) { - const filters = this.options.newExtensionsOnly ? - [`diminish eq 'latest'`] : - await this.getVersionFilters(buildNumber); + const filters = this.options.newExtensionsOnly ? + [`diminish eq 'latest'`] : + await this.getVersionFilters(buildNumber); - const filterStr = encodeURIComponent(filters.join(' or ')); - const body = JSON.stringify({ - query: encodedQuery, - filters: filterStr - }); + const filterStr = filters + .slice(0, RemoteSearchProvider.MAX_EXTENSION_FILTERS) + .join(' or '); - return { - url, - body - }; - } else { - url += `query=${encodedQuery}`; + const body = JSON.stringify({ + query: encodedQuery, + filters: encodeURIComponent(filterStr) + }); - if (buildNumber) { - url += `&build=${buildNumber}`; - } - } - - return TPromise.wrap({ url }); + return { + url, + body + }; } private getVersionFilters(buildNumber?: number): TPromise { diff --git a/src/vs/workbench/parts/search/browser/media/searchviewlet.css b/src/vs/workbench/parts/search/browser/media/searchviewlet.css index 3e747e6c15e..d866df8c809 100644 --- a/src/vs/workbench/parts/search/browser/media/searchviewlet.css +++ b/src/vs/workbench/parts/search/browser/media/searchviewlet.css @@ -310,6 +310,15 @@ background: url('clear-search-results-dark.svg') center center no-repeat; } +.monaco-workbench .search-action.cancel-search { + background: url('stop.svg') center center no-repeat; +} + +.vs-dark .monaco-workbench .search-action.cancel-search, +.hc-black .monaco-workbench .search-action.cancel-search { + background: url('stop-inverse.svg') center center no-repeat; +} + .vs .monaco-workbench .search-viewlet .query-details .file-types .controls > .custom-checkbox.pattern { background: url('pattern.svg') center center no-repeat; } diff --git a/src/vs/workbench/parts/search/browser/media/stop-inverse.svg b/src/vs/workbench/parts/search/browser/media/stop-inverse.svg new file mode 100644 index 00000000000..ef79528e9c8 --- /dev/null +++ b/src/vs/workbench/parts/search/browser/media/stop-inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/search/browser/media/stop.svg b/src/vs/workbench/parts/search/browser/media/stop.svg new file mode 100644 index 00000000000..0b36e84ac92 --- /dev/null +++ b/src/vs/workbench/parts/search/browser/media/stop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/search/browser/searchActions.ts b/src/vs/workbench/parts/search/browser/searchActions.ts index 4145a5cc8b2..ffd61a26620 100644 --- a/src/vs/workbench/parts/search/browser/searchActions.ts +++ b/src/vs/workbench/parts/search/browser/searchActions.ts @@ -379,6 +379,32 @@ export class ClearSearchResultsAction extends SearchAction { } } +export class CancelSearchAction extends SearchAction { + + static ID: string = 'search.action.cancelSearch'; + static LABEL: string = nls.localize('CancelSearchAction.label', "Cancel Search"); + + constructor(id: string, label: string, @IViewletService viewletService: IViewletService) { + super(id, label, viewletService); + this.class = 'search-action cancel-search'; + this.update(); + } + + update(): void { + const searchViewlet = this.getSearchViewlet(); + this.enabled = searchViewlet && searchViewlet.isSearching(); + } + + public run(): TPromise { + const searchViewlet = this.getSearchViewlet(); + if (searchViewlet) { + searchViewlet.cancelSearch(); + } + + return TPromise.as(null); + } +} + export class FocusNextSearchResultAction extends Action { public static readonly ID = 'search.action.focusNextSearchResult'; public static readonly LABEL = nls.localize('FocusNextSearchResult.label', "Focus Next Search Result"); diff --git a/src/vs/workbench/parts/search/browser/searchViewlet.ts b/src/vs/workbench/parts/search/browser/searchViewlet.ts index a7e14a96539..eacdc0b2496 100644 --- a/src/vs/workbench/parts/search/browser/searchViewlet.ts +++ b/src/vs/workbench/parts/search/browser/searchViewlet.ts @@ -45,7 +45,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { PatternInputWidget, ExcludePatternInputWidget } from 'vs/workbench/parts/search/browser/patternInputWidget'; import { SearchRenderer, SearchDataSource, SearchSorter, SearchAccessibilityProvider, SearchFilter } from 'vs/workbench/parts/search/browser/searchResultsView'; import { SearchWidget, ISearchWidgetOptions } from 'vs/workbench/parts/search/browser/searchWidget'; -import { RefreshAction, CollapseDeepestExpandedLevelAction, ClearSearchResultsAction, SearchAction } from 'vs/workbench/parts/search/browser/searchActions'; +import { RefreshAction, CollapseDeepestExpandedLevelAction, ClearSearchResultsAction, SearchAction, CancelSearchAction } from 'vs/workbench/parts/search/browser/searchActions'; import { IReplaceService } from 'vs/workbench/parts/search/common/replace'; import Severity from 'vs/base/common/severity'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; @@ -81,6 +81,7 @@ export class SearchViewlet extends Viewlet { private folderMatchFocused: IContextKey; private matchFocused: IContextKey; private searchSubmitted: boolean; + private searching: boolean; private actions: SearchAction[] = []; private tree: ITree; @@ -785,6 +786,10 @@ export class SearchViewlet extends Viewlet { return this.searchSubmitted; } + public isSearching(): boolean { + return this.searching; + } + public hasSearchResults(): boolean { return !this.viewModel.searchResult.isEmpty(); } @@ -1066,11 +1071,17 @@ export class SearchViewlet extends Viewlet { this.progressService.show(progressTotal); this.searchWidget.searchInput.clearMessage(); + this.searching = true; + setTimeout(() => { + if (this.searching) { + this.changeActionAtPosition(0, this.instantiationService.createInstance(CancelSearchAction, CancelSearchAction.ID, CancelSearchAction.LABEL)); + } + }, 2000); this.showEmptyStage(); - let isDone = false; let onComplete = (completed?: ISearchComplete) => { - isDone = true; + this.searching = false; + this.changeActionAtPosition(0, this.instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL)); // Complete up to 100% as needed if (completed && !query.useRipgrep) { @@ -1201,7 +1212,8 @@ export class SearchViewlet extends Viewlet { if (errors.isPromiseCanceledError(e)) { onComplete(null); } else { - isDone = true; + this.searching = false; + this.changeActionAtPosition(0, this.instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL)); progressRunner.done(); this.searchWidget.searchInput.showMessage({ content: e.message, type: MessageType.ERROR }); this.viewModel.searchResult.clear(); @@ -1223,7 +1235,7 @@ export class SearchViewlet extends Viewlet { // Handle UI updates in an interval to show frequent progress and results let uiRefreshHandle = setInterval(() => { - if (isDone) { + if (!this.searching) { window.clearInterval(uiRefreshHandle); return; } @@ -1424,6 +1436,11 @@ export class SearchViewlet extends Viewlet { return this.actions; } + private changeActionAtPosition(index: number, newAction: SearchAction): void { + this.actions.splice(index, 1, newAction); + this.updateTitleArea(); + } + public shutdown(): void { const isRegex = this.searchWidget.searchInput.getRegex(); const isWholeWords = this.searchWidget.searchInput.getWholeWords(); diff --git a/src/vs/workbench/parts/tasks/common/tasks.ts b/src/vs/workbench/parts/tasks/common/tasks.ts index 1aebf6b4018..4d29f195584 100644 --- a/src/vs/workbench/parts/tasks/common/tasks.ts +++ b/src/vs/workbench/parts/tasks/common/tasks.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import URI from 'vs/base/common/uri'; +import { UriComponents } from 'vs/base/common/uri'; import * as Types from 'vs/base/common/types'; import { IJSONSchemaMap } from 'vs/base/common/jsonSchema'; import * as Objects from 'vs/base/common/objects'; @@ -246,7 +246,7 @@ export interface ExtensionTaskSource { } export interface ExtensionTaskSourceTransfer { - __workspaceFolder: URI; + __workspaceFolder: UriComponents; } export interface InMemoryTaskSource { diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts index 99e9d1d4b49..918ca090df4 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts @@ -193,7 +193,7 @@ configurationRegistry.registerConfiguration({ 'default': false }, 'terminal.integrated.enableBell': { - 'description': nls.localize('terminal.integrated.enableBell', "Whether the terminal bell is enabled on not."), + 'description': nls.localize('terminal.integrated.enableBell', "Whether the terminal bell is enabled or not."), 'type': 'boolean', 'default': false }, diff --git a/src/vs/workbench/services/configurationResolver/electron-browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/electron-browser/configurationResolverService.ts index 1a98e4493eb..99b29ec0e45 100644 --- a/src/vs/workbench/services/configurationResolver/electron-browser/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/electron-browser/configurationResolverService.ts @@ -12,7 +12,7 @@ import { IConfigurationResolverService } from 'vs/workbench/services/configurati import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { toResource } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; @@ -20,92 +20,111 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { relative } from 'path'; import { IProcessEnvironment, isWindows } from 'vs/base/common/platform'; -export class ConfigurationResolverService implements IConfigurationResolverService { - _serviceBrand: any; - private _execPath: string; - private _lastWorkspaceFolder: IWorkspaceFolder; +class VariableResolver { + static VARIABLE_REGEXP = /\$\{(.*?)\}/g; + static ENV_PREFIX = 'env:'; + static CONFIG_PREFIX = 'config:'; + private envVariables: IProcessEnvironment; constructor( envVariables: IProcessEnvironment, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IEnvironmentService environmentService: IEnvironmentService, - @IConfigurationService private configurationService: IConfigurationService, - @ICommandService private commandService: ICommandService, + private configurationService: IConfigurationService, + private editorService: IWorkbenchEditorService, + private environmentService: IEnvironmentService, + private workspaceContextService: IWorkspaceContextService ) { - this._execPath = environmentService.execPath; - Object.keys(envVariables).forEach(key => { - const name = isWindows ? key.toLowerCase() : key; - this[`env:${name}`] = envVariables[key]; + if (isWindows) { + this.envVariables = Object.create(null); + Object.keys(envVariables).forEach(key => { + this.envVariables[key.toLowerCase()] = envVariables[key]; + }); + } else { + this.envVariables = envVariables; + } + } + + resolve(context: IWorkspaceFolder, value: string): string { + const filePath = this.getFilePath(); + return value.replace(VariableResolver.VARIABLE_REGEXP, (match: string, variable: string) => { + const parts = variable.split(':'); + let sufix: string; + if (parts && parts.length > 1) { + variable = parts[0]; + sufix = parts[1]; + } + + switch (variable) { + case 'env': { + if (sufix) { + if (isWindows) { + sufix = sufix.toLowerCase(); + } + + const env = this.envVariables[sufix]; + if (types.isString(env)) { + return env; + } + } + } + case 'config': { + if (sufix) { + const config = this.configurationService.getValue(sufix, context ? { resource: context.uri } : undefined); + if (!types.isUndefinedOrNull(config) && !types.isObject(config)) { + return config; + } + } + } + default: { + if (sufix) { + const folder = this.workspaceContextService.getWorkspace().folders.filter(f => f.name === sufix).pop(); + if (folder) { + context = folder; + } + } + + switch (variable) { + case 'workspaceRoot': + case 'workspaceFolder': + return context ? context.uri.fsPath : match; + case 'cwd': + return context ? context.uri.fsPath : process.cwd(); + case 'workspaceRootFolderName': + case 'workspaceFolderBasename': + return context ? paths.basename(context.uri.fsPath) : match; + case 'lineNumber': + return this.getLineNumber() || match; + case 'selectedText': + return this.getSelectedText() || match; + case 'file': + return filePath || match; + case 'relativeFile': + return context ? paths.normalize(relative(context.uri.fsPath, filePath)) : filePath || match; + case 'fileDirname': + return filePath ? paths.dirname(filePath) : match; + case 'fileExtname': + return filePath ? paths.extname(filePath) : match; + case 'fileBasename': + return filePath ? paths.basename(filePath) : match; + case 'fileBasenameNoExtension': { + if (!filePath) { + return match; + } + + const basename = paths.basename(filePath); + return basename.slice(0, basename.length - paths.extname(basename).length); + } + case 'execPath': + return this.environmentService.execPath; + + default: + return match; + } + } + } }); } - private get execPath(): string { - return this._execPath; - } - - private get cwd(): string { - if (this.workspaceRoot) { - return this.workspaceRoot; - } else { - return process.cwd(); - } - } - - private get workspaceRoot(): string { - return this._lastWorkspaceFolder ? this._lastWorkspaceFolder.uri.fsPath : undefined; - } - - private get workspaceFolder(): string { - return this.workspaceRoot; - } - - private get workspaceRootFolderName(): string { - return this.workspaceFolderBasename; - } - - private get workspaceFolderBasename(): string { - return this.workspaceRoot ? paths.basename(this.workspaceRoot) : ''; - } - - private get file(): string { - return this.getFilePath(); - } - - private get relativeFile(): string { - return (this.workspaceRoot) ? paths.normalize(relative(this.workspaceRoot, this.file)) : this.file; - } - - private get fileBasename(): string { - return paths.basename(this.getFilePath()); - } - - private get fileBasenameNoExtension(): string { - const basename = this.fileBasename; - return basename.slice(0, basename.length - paths.extname(basename).length); - } - - private get fileDirname(): string { - return paths.dirname(this.getFilePath()); - } - - private get fileExtname(): string { - return paths.extname(this.getFilePath()); - } - - private get lineNumber(): string { - const activeEditor = this.editorService.getActiveEditor(); - if (activeEditor) { - const editorControl = (activeEditor.getControl()); - if (editorControl) { - const lineNumber = editorControl.getSelection().positionLineNumber; - return String(lineNumber); - } - } - - return ''; - } - - private get selectedText(): string { + private getSelectedText(): string { const activeEditor = this.editorService.getActiveEditor(); if (activeEditor) { const editorControl = (activeEditor.getControl()); @@ -118,7 +137,7 @@ export class ConfigurationResolverService implements IConfigurationResolverServi } } - return ''; + return undefined; } private getFilePath(): string { @@ -126,126 +145,77 @@ export class ConfigurationResolverService implements IConfigurationResolverServi if (input instanceof DiffEditorInput) { input = input.modifiedInput; } - if (!input) { - return ''; - } const fileResource = toResource(input, { filter: 'file' }); if (!fileResource) { - return ''; + return undefined; } + return paths.normalize(fileResource.fsPath, true); } + private getLineNumber(): string { + const activeEditor = this.editorService.getActiveEditor(); + if (activeEditor) { + const editorControl = (activeEditor.getControl()); + if (editorControl) { + const lineNumber = editorControl.getSelection().positionLineNumber; + return String(lineNumber); + } + } + + return undefined; + } +} + +export class ConfigurationResolverService implements IConfigurationResolverService { + _serviceBrand: any; + private resolver: VariableResolver; + + constructor( + envVariables: IProcessEnvironment, + @IWorkbenchEditorService editorService: IWorkbenchEditorService, + @IEnvironmentService environmentService: IEnvironmentService, + @IConfigurationService configurationService: IConfigurationService, + @ICommandService private commandService: ICommandService, + @IWorkspaceContextService workspaceContextService: IWorkspaceContextService + ) { + this.resolver = new VariableResolver(envVariables, configurationService, editorService, environmentService, workspaceContextService); + } + public resolve(root: IWorkspaceFolder, value: string): string; public resolve(root: IWorkspaceFolder, value: string[]): string[]; public resolve(root: IWorkspaceFolder, value: IStringDictionary): IStringDictionary; public resolve(root: IWorkspaceFolder, value: any): any { - try { - this._lastWorkspaceFolder = root; - if (types.isString(value)) { - return this.resolveString(root, value); - } else if (types.isArray(value)) { - return this.resolveArray(root, value); - } else if (types.isObject(value)) { - return this.resolveLiteral(root, value); - } - return value; - } finally { - this._lastWorkspaceFolder = undefined; + if (types.isString(value)) { + return this.resolver.resolve(root, value); + } else if (types.isArray(value)) { + return value.map(s => this.resolver.resolve(root, s)); + } else if (types.isObject(value)) { + let result: IStringDictionary | string[]> = Object.create(null); + Object.keys(value).forEach(key => { + result[key] = this.resolve(root, value[key]); + }); + + return result; } + return value; } - public resolveAny(root: IWorkspaceFolder, value: T): T; public resolveAny(root: IWorkspaceFolder, value: any): any { - try { - this._lastWorkspaceFolder = root; - if (types.isString(value)) { - return this.resolveString(root, value); - } else if (types.isArray(value)) { - return this.resolveAnyArray(root, value); - } else if (types.isObject(value)) { - return this.resolveAnyLiteral(root, value); - } - return value; - } finally { - this._lastWorkspaceFolder = undefined; + if (types.isString(value)) { + return this.resolver.resolve(root, value); + } else if (types.isArray(value)) { + return value.map(s => this.resolveAny(root, s)); + } else if (types.isObject(value)) { + let result: IStringDictionary | string[]> = Object.create(null); + Object.keys(value).forEach(key => { + result[key] = this.resolveAny(root, value[key]); + }); + + return result; } - } - - private resolveString(root: IWorkspaceFolder, value: string): string { - let regexp = /\$\{(.*?)\}/g; - const originalValue = value; - const resolvedString = value.replace(regexp, (match: string, name: string) => { - const key = (isWindows && match.indexOf('env:') > 0) ? name.toLowerCase() : name; - let newValue = (this)[key]; - if (types.isString(newValue)) { - return newValue; - } else { - return match && match.indexOf('env:') > 0 ? '' : match; - } - }); - - return this.resolveConfigVariable(root, resolvedString, originalValue); - } - - private resolveConfigVariable(root: IWorkspaceFolder, value: string, originalValue: string): string { - const replacer = (match: string, name: string) => { - let config = this.configurationService.getValue({ resource: root.uri }); - let newValue: any; - try { - const keys: string[] = name.split('.'); - if (!keys || keys.length <= 0) { - return ''; - } - while (keys.length > 1) { - const key = keys.shift(); - if (!config || !config.hasOwnProperty(key)) { - return ''; - } - config = config[key]; - } - newValue = config && config.hasOwnProperty(keys[0]) ? config[keys[0]] : ''; - } catch (e) { - return ''; - } - if (types.isString(newValue)) { - // Prevent infinite recursion and also support nested references (or tokens) - return newValue === originalValue ? '' : this.resolveString(root, newValue); - } else { - return this.resolve(root, newValue) + ''; - } - }; - - return value.replace(/\$\{config:(.+?)\}/g, replacer); - } - - private resolveLiteral(root: IWorkspaceFolder, values: IStringDictionary | string[]>): IStringDictionary | string[]> { - let result: IStringDictionary | string[]> = Object.create(null); - Object.keys(values).forEach(key => { - let value = values[key]; - result[key] = this.resolve(root, value); - }); - return result; - } - - private resolveAnyLiteral(root: IWorkspaceFolder, values: T): T; - private resolveAnyLiteral(root: IWorkspaceFolder, values: any): any { - let result: IStringDictionary | string[]> = Object.create(null); - Object.keys(values).forEach(key => { - let value = values[key]; - result[key] = this.resolveAny(root, value); - }); - return result; - } - - private resolveArray(root: IWorkspaceFolder, value: string[]): string[] { - return value.map(s => this.resolveString(root, s)); - } - - private resolveAnyArray(root: IWorkspaceFolder, value: T[]): T[]; - private resolveAnyArray(root: IWorkspaceFolder, value: any[]): any[] { - return value.map(s => this.resolveAny(root, s)); + return value; } /** @@ -258,7 +228,7 @@ export class ConfigurationResolverService implements IConfigurationResolverServi // We need a map from interactive variables to keys because we only want to trigger an command once per key - // even though it might occur multiple times in configuration #7026. - const interactiveVariablesToSubstitutes: { [interactiveVariable: string]: { object: any, key: string }[] } = {}; + const interactiveVariablesToSubstitutes: { [interactiveVariable: string]: { object: any, key: string }[] } = Object.create(null); const findInteractiveVariables = (object: any) => { Object.keys(object).forEach(key => { if (object[key] && typeof object[key] === 'object') { diff --git a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts index b77215ea758..fd97b00746e 100644 --- a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts @@ -12,7 +12,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { TestEnvironmentService, TestEditorService } from 'vs/workbench/test/workbenchTestServices'; +import { TestEnvironmentService, TestEditorService, TestContextService } from 'vs/workbench/test/workbenchTestServices'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; suite('Configuration Resolver Service', () => { @@ -22,7 +22,6 @@ suite('Configuration Resolver Service', () => { let editorService: TestEditorService; let workspace: IWorkspaceFolder; - setup(() => { mockCommandService = new MockCommandService(); editorService = new TestEditorService(); @@ -32,14 +31,13 @@ suite('Configuration Resolver Service', () => { index: 0, toResource: () => null }; - configurationResolverService = new ConfigurationResolverService(envVariables, editorService, TestEnvironmentService, new TestConfigurationService(), mockCommandService); + configurationResolverService = new ConfigurationResolverService(envVariables, editorService, TestEnvironmentService, new TestConfigurationService(), mockCommandService, new TestContextService()); }); teardown(() => { configurationResolverService = null; }); - test('substitute one', () => { if (platform.isWindows) { assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceFolder} xyz'), 'abc \\VSCode\\workspaceLocation xyz'); @@ -88,7 +86,7 @@ suite('Configuration Resolver Service', () => { if (platform.isWindows) { assert.strictEqual(configurationResolverService.resolve(workspace, '${env:key1} - ${env:Key1}'), 'Value for key1 - Value for key1'); } else { - assert.strictEqual(configurationResolverService.resolve(workspace, '${env:key1} - ${env:Key1}'), 'Value for key1 - '); + assert.strictEqual(configurationResolverService.resolve(workspace, '${env:key1} - ${env:Key1}'), 'Value for key1 - ${env:Key1}'); } }); @@ -105,7 +103,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); + let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService()); assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} xyz'), 'abc foo xyz'); }); @@ -122,52 +120,10 @@ suite('Configuration Resolver Service', () => { } }); - let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); + let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService()); assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo bar xyz'); }); - test('substitute nested configuration variables', () => { - let configurationService: IConfigurationService; - configurationService = new MockConfigurationService({ - editor: { - fontFamily: 'foo ${workspaceFolder} ${config:terminal.integrated.fontFamily}' - }, - terminal: { - integrated: { - fontFamily: 'bar' - } - } - }); - - let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); - if (platform.isWindows) { - assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo \\VSCode\\workspaceLocation bar bar xyz'); - } else { - assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo /VSCode/workspaceLocation bar bar xyz'); - } - }); - - test('substitute accidental self referenced configuration variables', () => { - let configurationService: IConfigurationService; - configurationService = new MockConfigurationService({ - editor: { - fontFamily: 'foo ${workspaceFolder} ${config:terminal.integrated.fontFamily} ${config:editor.fontFamily}' - }, - terminal: { - integrated: { - fontFamily: 'bar' - } - } - }); - - let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); - if (platform.isWindows) { - assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo \\VSCode\\workspaceLocation bar bar xyz'); - } else { - assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo /VSCode/workspaceLocation bar bar xyz'); - } - }); - test('substitute one env variable and a configuration variable', () => { let configurationService: IConfigurationService; configurationService = new MockConfigurationService({ @@ -181,7 +137,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); + let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService()); if (platform.isWindows) { assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${workspaceFolder} ${env:key1} xyz'), 'abc foo \\VSCode\\workspaceLocation Value for key1 xyz'); } else { @@ -202,7 +158,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); + let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService()); if (platform.isWindows) { assert.strictEqual(service.resolve(workspace, '${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} ${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), 'foo bar \\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for key1 - Value for key2'); } else { @@ -236,7 +192,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); + let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService()); assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:editor.lineNumbers} ${config:editor.insertSpaces} xyz'), 'abc foo 123 false xyz'); }); @@ -248,32 +204,21 @@ suite('Configuration Resolver Service', () => { } }); - let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); - assert.strictEqual(service.resolve(workspace, 'abc ${config:editor[\'abc\'.substr(0)]} xyz'), 'abc xyz'); + let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService()); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor[\'abc\'.substr(0)]} xyz'), 'abc ${config:editor[\'abc\'.substr(0)]} xyz'); }); - test('uses empty string as fallback', () => { + test('uses original variable as fallback', () => { let configurationService: IConfigurationService; configurationService = new MockConfigurationService({ editor: {} }); - let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); - assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.abc} xyz'), 'abc xyz'); - assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.abc.def} xyz'), 'abc xyz'); - assert.strictEqual(service.resolve(workspace, 'abc ${config:panel} xyz'), 'abc xyz'); - assert.strictEqual(service.resolve(workspace, 'abc ${config:panel.abc} xyz'), 'abc xyz'); - }); - - test('is restricted to own properties', () => { - let configurationService: IConfigurationService; - configurationService = new MockConfigurationService({ - editor: {} - }); - - let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); - assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.__proto__} xyz'), 'abc xyz'); - assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.toString} xyz'), 'abc xyz'); + let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService()); + assert.strictEqual(service.resolve(workspace, 'abc ${invalidVariable} xyz'), 'abc ${invalidVariable} xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${env:invalidVariable} xyz'), 'abc ${env:invalidVariable} xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.abc.def} xyz'), 'abc ${config:editor.abc.def} xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:panel.abc} xyz'), 'abc ${config:panel.abc} xyz'); }); test('configuration variables with invalid accessor', () => { @@ -284,10 +229,10 @@ suite('Configuration Resolver Service', () => { } }); - let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); + let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService, new TestContextService()); assert.strictEqual(service.resolve(workspace, 'abc ${config:} xyz'), 'abc ${config:} xyz'); - assert.strictEqual(service.resolve(workspace, 'abc ${config:editor..fontFamily} xyz'), 'abc xyz'); - assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.none.none2} xyz'), 'abc xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor..fontFamily} xyz'), 'abc ${config:editor..fontFamily} xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.none.none2} xyz'), 'abc ${config:editor.none.none2} xyz'); }); test('interactive variable simple', () => { @@ -362,7 +307,20 @@ class MockConfigurationService implements IConfigurationService { public constructor(private configuration: any = {}) { } public inspect(key: string, overrides?: IConfigurationOverrides): any { return { value: getConfigurationValue(this.getValue(), key), default: getConfigurationValue(this.getValue(), key), user: getConfigurationValue(this.getValue(), key), workspaceFolder: void 0, folder: void 0 }; } public keys() { return { default: [], user: [], workspace: [], workspaceFolder: [] }; } - public getValue(): any { return this.configuration; } + public getValue(): any; + public getValue(value: string): any; + public getValue(value?: any): any { + if (!value) { + return this.configuration; + } + const valuePath = (value).split('.'); + let object = this.configuration; + while (valuePath.length && object) { + object = object[valuePath.shift()]; + } + + return object; + } public updateValue(): TPromise { return null; } public getConfigurationData(): any { return null; } public onDidChangeConfiguration() { return { dispose() { } }; } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index ee35a4980f5..cb7cb3d37fd 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -276,6 +276,8 @@ export class ExtensionHostProcessWorker { let startPort = 9333; if (typeof this._environmentService.debugExtensionHost.port === 'number') { startPort = expected = this._environmentService.debugExtensionHost.port; + } else { + return TPromise.as({ expected: undefined, actual: 0 }); } return new TPromise((c, e) => { return findFreePort(startPort, 10 /* try 10 ports */, 5000 /* try up to 5 seconds */).then(port => { diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts index 2b77e490063..0877a0df48a 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts @@ -7,15 +7,8 @@ import { IExtensionService, IExtensionDescription, ProfileSession, IExtensionHostProfile, ProfileSegmentId } from 'vs/platform/extensions/common/extensions'; import { TPromise } from 'vs/base/common/winjs.base'; -import { localize } from 'vs/nls'; import { TernarySearchTree } from 'vs/base/common/map'; import { realpathSync } from 'vs/base/node/extfs'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IStatusbarService, StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar'; -import { writeFile } from 'vs/base/node/pfs'; -import * as path from 'path'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { setTimeout } from 'timers'; import { Profile, ProfileNode } from 'v8-inspect-profiler'; export class ExtensionHostProfiler { @@ -128,27 +121,3 @@ export class ExtensionHostProfiler { }; } } - - -CommandsRegistry.registerCommand('exthost.profile.start', async accessor => { - const statusbarService = accessor.get(IStatusbarService); - const extensionService = accessor.get(IExtensionService); - const environmentService = accessor.get(IEnvironmentService); - - const handle = statusbarService.addEntry({ text: localize('message', "$(zap) Profiling Extension Host...") }, StatusbarAlignment.LEFT); - - extensionService.startExtensionHostProfile().then(session => { - setTimeout(() => { - session.stop().then(result => { - result.getAggregatedTimes().forEach((val, index) => { - console.log(`${index} : ${Math.round(val / 1000)} ms`); - }); - let profilePath = path.join(environmentService.userHome, 'extHostProfile.cpuprofile'); - console.log(`Saving profile at ${profilePath}`); - return writeFile(profilePath, JSON.stringify(result.data)); - }).then(() => { - handle.dispose(); - }); - }, 5000); - }); -}); diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 4d51f56bd85..1f32a1e5386 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -370,6 +370,10 @@ export class ExtensionService extends Disposable implements IExtensionService { return result; } + public canProfileExtensionHost(): boolean { + return this._extensionHostProcessWorker && Boolean(this._extensionHostProcessWorker.getInspectPort()); + } + public startExtensionHostProfile(): TPromise { if (this._extensionHostProcessWorker) { let port = this._extensionHostProcessWorker.getInspectPort(); diff --git a/src/vs/workbench/services/extensions/node/proxyIdentifier.ts b/src/vs/workbench/services/extensions/node/proxyIdentifier.ts index 5d2c7484abd..3447bd4255f 100644 --- a/src/vs/workbench/services/extensions/node/proxyIdentifier.ts +++ b/src/vs/workbench/services/extensions/node/proxyIdentifier.ts @@ -27,29 +27,22 @@ export class ProxyIdentifier { public readonly isMain: boolean; public readonly id: string; - public readonly isFancy: boolean; - constructor(isMain: boolean, id: string, isFancy: boolean) { + constructor(isMain: boolean, id: string) { this.isMain = isMain; this.id = id; - this.isFancy = isFancy; } } -export const enum ProxyType { - NativeJSON = 0, - CustomMarshaller = 1 -} - /** * Using `isFancy` indicates that arguments or results of type `URI` or `RegExp` * will be serialized/deserialized automatically, but this has a performance cost, * as each argument/result must be visited. */ -export function createMainContextProxyIdentifier(identifier: string, type: ProxyType = ProxyType.NativeJSON): ProxyIdentifier { - return new ProxyIdentifier(true, 'm' + identifier, type === ProxyType.CustomMarshaller); +export function createMainContextProxyIdentifier(identifier: string): ProxyIdentifier { + return new ProxyIdentifier(true, 'm' + identifier); } -export function createExtHostContextProxyIdentifier(identifier: string, type: ProxyType = ProxyType.NativeJSON): ProxyIdentifier { - return new ProxyIdentifier(false, 'e' + identifier, type === ProxyType.CustomMarshaller); +export function createExtHostContextProxyIdentifier(identifier: string): ProxyIdentifier { + return new ProxyIdentifier(false, 'e' + identifier); } diff --git a/src/vs/workbench/services/extensions/node/rpcProtocol.ts b/src/vs/workbench/services/extensions/node/rpcProtocol.ts index d738ab50737..2e1ae6d2ee8 100644 --- a/src/vs/workbench/services/extensions/node/rpcProtocol.ts +++ b/src/vs/workbench/services/extensions/node/rpcProtocol.ts @@ -5,7 +5,6 @@ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; -import * as marshalling from 'vs/base/common/marshalling'; import * as errors from 'vs/base/common/errors'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { LazyPromise } from 'vs/workbench/services/extensions/node/lazyPromise'; @@ -46,17 +45,17 @@ export class RPCProtocol implements IRPCProtocol { public getProxy(identifier: ProxyIdentifier): T { if (!this._proxies[identifier.id]) { - this._proxies[identifier.id] = this._createProxy(identifier.id, identifier.isFancy); + this._proxies[identifier.id] = this._createProxy(identifier.id); } return this._proxies[identifier.id]; } - private _createProxy(proxyId: string, isFancy: boolean): T { + private _createProxy(proxyId: string): T { let handler = { get: (target, name: string) => { if (!target[name] && name.charCodeAt(0) === CharCode.DollarSign) { target[name] = (...myArgs: any[]) => { - return this._remoteCall(proxyId, name, myArgs, isFancy); + return this._remoteCall(proxyId, name, myArgs); }; } return target[name]; @@ -90,38 +89,27 @@ export class RPCProtocol implements IRPCProtocol { case MessageType.Request: this._receiveRequest(msg); break; - case MessageType.FancyRequest: - this._receiveRequest(marshalling.revive(msg, 0)); - break; case MessageType.Cancel: this._receiveCancel(msg); break; case MessageType.Reply: this._receiveReply(msg); break; - case MessageType.FancyReply: - this._receiveReply(marshalling.revive(msg, 0)); - break; case MessageType.ReplyErr: this._receiveReplyErr(msg); break; } } - private _receiveRequest(msg: RequestMessage | FancyRequestMessage): void { + private _receiveRequest(msg: RequestMessage): void { const callId = msg.id; const proxyId = msg.proxyId; - const isFancy = (msg.type === MessageType.FancyRequest); // a fancy request gets a fancy reply this._invokedHandlers[callId] = this._invokeHandler(proxyId, msg.method, msg.args); this._invokedHandlers[callId].then((r) => { delete this._invokedHandlers[callId]; - if (isFancy) { - this._multiplexor.send(MessageFactory.fancyReplyOK(callId, r)); - } else { - this._multiplexor.send(MessageFactory.replyOK(callId, r)); - } + this._multiplexor.send(MessageFactory.replyOK(callId, r)); }, (err) => { delete this._invokedHandlers[callId]; this._multiplexor.send(MessageFactory.replyErr(callId, err)); @@ -135,7 +123,7 @@ export class RPCProtocol implements IRPCProtocol { } } - private _receiveReply(msg: ReplyMessage | FancyReplyMessage): void { + private _receiveReply(msg: ReplyMessage): void { const callId = msg.id; if (!this._pendingRPCReplies.hasOwnProperty(callId)) { return; @@ -186,7 +174,7 @@ export class RPCProtocol implements IRPCProtocol { return method.apply(actor, args); } - private _remoteCall(proxyId: string, methodName: string, args: any[], isFancy: boolean): TPromise { + private _remoteCall(proxyId: string, methodName: string, args: any[]): TPromise { if (this._isDisposed) { return TPromise.wrapError(errors.canceled()); } @@ -197,13 +185,7 @@ export class RPCProtocol implements IRPCProtocol { }); this._pendingRPCReplies[callId] = result; - - if (isFancy) { - this._multiplexor.send(MessageFactory.fancyRequest(callId, proxyId, methodName, args)); - } else { - this._multiplexor.send(MessageFactory.request(callId, proxyId, methodName, args)); - } - + this._multiplexor.send(MessageFactory.request(callId, proxyId, methodName, args)); return result; } } @@ -256,10 +238,6 @@ class MessageFactory { return `{"type":${MessageType.Request},"id":"${req}","proxyId":"${rpcId}","method":"${method}","args":${JSON.stringify(args)}}`; } - public static fancyRequest(req: string, rpcId: string, method: string, args: any[]): string { - return `{"type":${MessageType.FancyRequest},"id":"${req}","proxyId":"${rpcId}","method":"${method}","args":${marshalling.stringify(args)}}`; - } - public static replyOK(req: string, res: any): string { if (typeof res === 'undefined') { return `{"type":${MessageType.Reply},"id":"${req}"}`; @@ -267,13 +245,6 @@ class MessageFactory { return `{"type":${MessageType.Reply},"id":"${req}","res":${JSON.stringify(res)}}`; } - public static fancyReplyOK(req: string, res: any): string { - if (typeof res === 'undefined') { - return `{"type":${MessageType.Reply},"id":"${req}"}`; - } - return `{"type":${MessageType.FancyReply},"id":"${req}","res":${marshalling.stringify(res)}}`; - } - public static replyErr(req: string, err: any): string { if (err instanceof Error) { return `{"type":${MessageType.ReplyErr},"id":"${req}","err":${JSON.stringify(errors.transformErrorForSerialization(err))}}`; @@ -284,11 +255,9 @@ class MessageFactory { const enum MessageType { Request = 1, - FancyRequest = 2, - Cancel = 3, - Reply = 4, - FancyReply = 5, - ReplyErr = 6 + Cancel = 2, + Reply = 3, + ReplyErr = 4 } class RequestMessage { @@ -298,13 +267,6 @@ class RequestMessage { method: string; args: any[]; } -class FancyRequestMessage { - type: MessageType.FancyRequest; - id: string; - proxyId: string; - method: string; - args: any[]; -} class CancelMessage { type: MessageType.Cancel; id: string; @@ -314,15 +276,10 @@ class ReplyMessage { id: string; res: any; } -class FancyReplyMessage { - type: MessageType.FancyReply; - id: string; - res: any; -} class ReplyErrMessage { type: MessageType.ReplyErr; id: string; err: errors.SerializedError; } -type RPCMessage = RequestMessage | FancyRequestMessage | CancelMessage | ReplyMessage | FancyReplyMessage | ReplyErrMessage; +type RPCMessage = RequestMessage | CancelMessage | ReplyMessage | ReplyErrMessage; diff --git a/src/vs/workbench/services/message/browser/messageList.ts b/src/vs/workbench/services/message/browser/messageList.ts index 76db707f70b..25819ba5062 100644 --- a/src/vs/workbench/services/message/browser/messageList.ts +++ b/src/vs/workbench/services/message/browser/messageList.ts @@ -191,7 +191,7 @@ export class MessageList { private doShowMessage(id: IMessageWithAction, message: string, severity: Severity, onHide: () => void): () => void; private doShowMessage(id: any, message: string, severity: Severity, onHide: () => void): () => void { const actions = (id).actions; - const source = (id).source; + const source = (id).source || 'vscode'; // Telemetry (TODO@Ben remove me later) /* __GDPR__ diff --git a/src/vs/workbench/services/timer/common/timerService.ts b/src/vs/workbench/services/timer/common/timerService.ts index f6ca71866cb..bee527e3878 100644 --- a/src/vs/workbench/services/timer/common/timerService.ts +++ b/src/vs/workbench/services/timer/common/timerService.ts @@ -66,6 +66,7 @@ export interface IStartupMetrics { ellapsedEditorRestore: number; ellapsedWorkbench: number; ellapsedTimersToTimersComputed: number; + ellapsedNlsGeneration: number; }; platform: string; release: string; diff --git a/src/vs/workbench/services/timer/node/timerService.ts b/src/vs/workbench/services/timer/node/timerService.ts index 7a49b00ba65..1de3ba8f6cc 100644 --- a/src/vs/workbench/services/timer/node/timerService.ts +++ b/src/vs/workbench/services/timer/node/timerService.ts @@ -70,6 +70,9 @@ export class TimerService implements ITimerService { // ignore, be on the safe side with these hardware method calls } + let nlsStart = perf.getEntry('mark', 'nlsGeneration:start'); + let nlsEnd = perf.getEntry('mark', 'nlsGeneration:end'); + let nlsTime = nlsStart && nlsEnd ? nlsEnd.startTime - nlsStart.startTime : 0; this._startupMetrics = { version: 1, ellapsed: perf.getEntry('mark', 'didStartWorkbench').startTime - start, @@ -81,7 +84,8 @@ export class TimerService implements ITimerService { ellapsedViewletRestore: perf.getDuration('willRestoreViewlet', 'didRestoreViewlet'), ellapsedWorkbench: perf.getDuration('willStartWorkbench', 'didStartWorkbench'), ellapsedWindowLoadToRequire: perf.getEntry('mark', 'willLoadWorkbenchMain').startTime - this.windowLoad, - ellapsedTimersToTimersComputed: Date.now() - now + ellapsedTimersToTimersComputed: Date.now() - now, + ellapsedNlsGeneration: nlsTime }, platform, release, diff --git a/src/vs/workbench/test/electron-browser/api/testRPCProtocol.ts b/src/vs/workbench/test/electron-browser/api/testRPCProtocol.ts index f2effd9e861..12a3f397b04 100644 --- a/src/vs/workbench/test/electron-browser/api/testRPCProtocol.ts +++ b/src/vs/workbench/test/electron-browser/api/testRPCProtocol.ts @@ -8,7 +8,6 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { ProxyIdentifier, IRPCProtocol } from 'vs/workbench/services/extensions/node/proxyIdentifier'; import { CharCode } from 'vs/base/common/charCode'; -import * as marshalling from 'vs/base/common/marshalling'; export function SingleProxyRPCProtocol(thing: any): IRPCProtocol { return { @@ -70,17 +69,17 @@ export class TestRPCProtocol implements IRPCProtocol { public getProxy(identifier: ProxyIdentifier): T { if (!this._proxies[identifier.id]) { - this._proxies[identifier.id] = this._createProxy(identifier.id, identifier.isFancy); + this._proxies[identifier.id] = this._createProxy(identifier.id); } return this._proxies[identifier.id]; } - private _createProxy(proxyId: string, isFancy: boolean): T { + private _createProxy(proxyId: string): T { let handler = { get: (target, name: string) => { if (!target[name] && name.charCodeAt(0) === CharCode.DollarSign) { target[name] = (...myArgs: any[]) => { - return this._remoteCall(proxyId, name, myArgs, isFancy); + return this._remoteCall(proxyId, name, myArgs); }; } return target[name]; @@ -94,7 +93,7 @@ export class TestRPCProtocol implements IRPCProtocol { return value; } - protected _remoteCall(proxyId: string, path: string, args: any[], isFancy: boolean): TPromise { + protected _remoteCall(proxyId: string, path: string, args: any[]): TPromise { this._callCount++; return new TPromise((c) => { @@ -102,7 +101,7 @@ export class TestRPCProtocol implements IRPCProtocol { }).then(() => { const instance = this._locals[proxyId]; // pretend the args went over the wire... (invoke .toJSON on objects...) - const wireArgs = simulateWireTransfer(args, isFancy); + const wireArgs = simulateWireTransfer(args); let p: Thenable; try { let result = (instance[path]).apply(instance, wireArgs); @@ -114,7 +113,7 @@ export class TestRPCProtocol implements IRPCProtocol { return p.then(result => { this._callCount--; // pretend the result went over the wire... (invoke .toJSON on objects...) - const wireResult = simulateWireTransfer(result, isFancy); + const wireResult = simulateWireTransfer(result); return wireResult; }, err => { this._callCount--; @@ -128,13 +127,9 @@ export class TestRPCProtocol implements IRPCProtocol { } } -function simulateWireTransfer(obj: T, isFancy: boolean): T { +function simulateWireTransfer(obj: T): T { if (!obj) { return obj; } - return ( - isFancy - ? marshalling.parse(marshalling.stringify(obj)) - : JSON.parse(JSON.stringify(obj)) - ); + return JSON.parse(JSON.stringify(obj)); } diff --git a/yarn.lock b/yarn.lock index 71dafbf80d3..fd95983bc13 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5781,21 +5781,21 @@ vscode-fsevents@0.3.8: dependencies: nan "^2.3.0" -vscode-nls-dev@^2.0.1: - version "2.1.5" - resolved "https://registry.yarnpkg.com/vscode-nls-dev/-/vscode-nls-dev-2.1.5.tgz#19faa3b18a7f302201039a4c967bbd22fa12844d" +vscode-nls-dev@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/vscode-nls-dev/-/vscode-nls-dev-3.0.3.tgz#9728541449576559ae7bf2cff4869edaeca7e2e1" dependencies: - clone "^1.0.2" - event-stream "^3.3.2" - glob "^6.0.4" - gulp-util "^3.0.7" - iconv-lite "^0.4.15" + clone "^2.1.1" + event-stream "^3.3.4" + glob "^7.1.2" + gulp-util "^3.0.8" + iconv-lite "^0.4.19" is "^3.2.1" - source-map "^0.5.3" - typescript "^2.0.3" - vinyl "^1.1.1" - xml2js "^0.4.17" - yargs "^3.32.0" + source-map "^0.6.1" + typescript "^2.6.2" + vinyl "^2.1.0" + xml2js "^0.4.19" + yargs "^10.1.1" vscode-ripgrep@^0.7.1-patch.0: version "0.7.1-patch.0" @@ -5808,9 +5808,9 @@ vscode-textmate@^3.2.0: fast-plist "^0.1.2" oniguruma "^6.0.1" -vscode-xterm@3.1.0-beta10: - version "3.1.0-beta10" - resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.1.0-beta10.tgz#274ab2f41c0417f477c4fe4488788a8be740784e" +vscode-xterm@3.1.0-beta11: + version "3.1.0-beta11" + resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.1.0-beta11.tgz#a6cfa957a6cac3bcc574da0433a2aa58654f2d8f" vso-node-api@^6.1.2-preview: version "6.1.2-preview"