diff --git a/.github/classifier.yml b/.github/classifier.yml index c2666691dc8..17b6dc14613 100644 --- a/.github/classifier.yml +++ b/.github/classifier.yml @@ -6,7 +6,7 @@ accessibility: [], api: [], css-less-sass: [], - debug: [ isidorn ], + debug: [ weinand ], editor: [], editor-brackets: [], editor-clipboard: [], diff --git a/.github/new_release.yml b/.github/new_release.yml index 902078aa79c..e54d1a8aba0 100644 --- a/.github/new_release.yml +++ b/.github/new_release.yml @@ -1,5 +1,5 @@ { newReleaseLabel: 'new release', newReleases: ['1.17.2'], - perform: true + perform: false } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 363bb9bcd4e..341a454f1ab 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,7 +14,7 @@ "**/node_modules": true, "**/bower_components": true, ".build/**": true, - "out*/**": true, + "out/**": true, "i18n/**": true, "extensions/**/out/**": true, "test/smoke/out/**": true diff --git a/README.md b/README.md index b0a86b728ae..5ea45fe3c75 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ please see the document [How to Contribute](https://github.com/Microsoft/vscode/ * [The development workflow, including debugging and running tests](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#development-workflow) * [Coding Guidelines](https://github.com/Microsoft/vscode/wiki/Coding-Guidelines) * [Submitting pull requests](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#pull-requests) +* [Contributing to translations](https://aka.ms/vscodeloc) Please see also our [Code of Conduct](CODE_OF_CONDUCT.md). diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index b14398194a1..f46ff276e72 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -236,7 +236,7 @@ const hygiene = exports.hygiene = (some, options) => { this.emit('data', file); }); - const result = vfs.src(some || all, { base: '.', follow: true }) + const result = vfs.src(some || all, { base: '.', follow: true, allowEmpty: true }) .pipe(filter(f => !f.stat.isDirectory())) .pipe(filter(eolFilter)) .pipe(options.skipEOL ? es.through() : eol) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index beb618c5195..80b69305b74 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -45,7 +45,7 @@ const nodeModules = ['electron', 'original-fs'] // Build const builtInExtensions = [ - { name: 'ms-vscode.node-debug', version: '1.18.1' }, + { name: 'ms-vscode.node-debug', version: '1.18.2' }, { name: 'ms-vscode.node-debug2', version: '1.18.3' } ]; @@ -209,6 +209,7 @@ function computeChecksum(filename) { return hash; } +const buildNumber = getBuildNumber(); function packageTask(platform, arch, opts) { opts = opts || {}; @@ -275,7 +276,7 @@ function packageTask(platform, arch, opts) { const date = new Date().toISOString(); const productJsonStream = gulp.src(['product.json'], { base: '.' }) - .pipe(json({ commit, date, checksums })); + .pipe(json({ commit, date, checksums, buildNumber })); const license = gulp.src(['LICENSES.chromium.html', 'LICENSE.txt', 'ThirdPartyNotices.txt', 'licenses/**'], { base: '.' }); @@ -460,15 +461,80 @@ gulp.task('upload-vscode-configuration', ['generate-vscode-configuration'], () = return; } + if (!buildNumber) { + console.error('Failed to compute build number'); + return; + } + return gulp.src(allConfigDetailsPath) .pipe(azure.upload({ account: process.env.AZURE_STORAGE_ACCOUNT, key: process.env.AZURE_STORAGE_ACCESS_KEY, container: 'configuration', - prefix: `${versionStringToNumber(packageJson.version)}/${commit}/` + prefix: `${buildNumber}/${commit}/` })); }); +function getBuildNumber() { + const previous = getPreviousVersion(packageJson.version); + if (!previous) { + return 0; + } + + try { + const out = cp.execSync(`git rev-list ${previous}..HEAD --count`); + const count = parseInt(out.toString()); + return versionStringToNumber(packageJson.version) * 1e4 + count; + } catch (e) { + console.error('Could not determine build number: ' + e.toString()); + return 0; + } +} + +/** + * Given 1.17.2, return 1.17.1 + * 1.18.0 => 1.17.2. + * 2.0.0 => 1.18.0 (or the highest 1.x) + */ +function getPreviousVersion(versionStr) { + function tagExists(tagName) { + try { + cp.execSync(`git rev-parse ${tagName}`); + return true; + } catch (e) { + return false; + } + } + + function getLastTagFromBase(semverArr, componentToTest) { + const baseVersion = semverArr.join('.'); + if (!tagExists(baseVersion)) { + console.error('Failed to find tag for base version, ' + baseVersion); + return null; + } + + let goodTag; + do { + goodTag = semverArr.join('.'); + semverArr[componentToTest]++; + } while (tagExists(semverArr.join('.'))); + + return goodTag; + } + + const semverArr = versionStr.split('.'); + if (semverArr[2] > 0) { + semverArr[2]--; + return semverArr.join('.'); + } else if (semverArr[1] > 0) { + semverArr[1]--; + return getLastTagFromBase(semverArr, 2); + } else { + semverArr[0]--; + return getLastTagFromBase(semverArr, 1); + } +} + function versionStringToNumber(versionStr) { const semverRegex = /(\d+)\.(\d+)\.(\d+)/; const match = versionStr.match(semverRegex); @@ -476,7 +542,7 @@ function versionStringToNumber(versionStr) { return 0; } - return parseInt(match[1], 10) * 10000 + parseInt(match[2], 10) * 100 + parseInt(match[3], 10); + return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10); } gulp.task('generate-vscode-configuration', () => { diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 9325369a2a5..9aafba7dc49 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -186,6 +186,10 @@ "name": "vs/workbench/services/textMate", "project": "vscode-workbench" }, + { + "name": "vs/workbench/services/workspace", + "project": "vscode-workbench" + }, { "name": "setup_messages", "project": "vscode-workbench" diff --git a/build/npm/update-all-grammars.js b/build/npm/update-all-grammars.js index cfea912c3b1..9f85530caf5 100644 --- a/build/npm/update-all-grammars.js +++ b/build/npm/update-all-grammars.js @@ -54,7 +54,7 @@ const extensions = [ 'scss', 'shaderlab', 'shellscript', - // 'sql', customized, PRs pending + 'sql', 'swift', 'typescript', 'vb', diff --git a/extensions/bat/language-configuration.json b/extensions/bat/language-configuration.json index 8b1695d8ec2..2fb5445a34a 100644 --- a/extensions/bat/language-configuration.json +++ b/extensions/bat/language-configuration.json @@ -18,5 +18,11 @@ ["[", "]"], ["(", ")"], ["\"", "\""] - ] -} \ No newline at end of file + ], + "folding": { + "markers": { + "start": "^\\s*(::\\s*|REM\\s+)#region", + "end": "^\\s*(::\\s*|REM\\s+)#endregion" + } + } +} diff --git a/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json b/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json index 68e1bc4e83b..d7bb723d231 100644 --- a/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json +++ b/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/atom/language-coffee-script/commit/8873cbc4e2f3b790603cbe7102d60f41fc82f726", + "version": "https://github.com/atom/language-coffee-script/commit/3f0b6b0e28d64cd6d5a720bf7a25c969be636e7b", "scopeName": "source.coffee", "name": "CoffeeScript", "fileTypes": [ @@ -47,7 +47,7 @@ "name": "punctuation.definition.string.end.coffee" } }, - "name": "string.quoted.heredoc.coffee", + "name": "string.quoted.single.heredoc.coffee", "patterns": [ { "captures": { @@ -143,7 +143,7 @@ { "begin": "///", "end": "(///)[gimuy]*", - "name": "string.regexp.coffee", + "name": "string.regexp.multiline.coffee", "beginCaptures": { "0": { "name": "punctuation.definition.string.begin.coffee" diff --git a/extensions/coffeescript/test/colorize-results/test-regex_coffee.json b/extensions/coffeescript/test/colorize-results/test-regex_coffee.json index 445fab1f1c2..ad11ba9d687 100644 --- a/extensions/coffeescript/test/colorize-results/test-regex_coffee.json +++ b/extensions/coffeescript/test/colorize-results/test-regex_coffee.json @@ -430,7 +430,7 @@ }, { "c": "///", - "t": "source.coffee string.regexp.coffee punctuation.definition.string.begin.coffee", + "t": "source.coffee string.regexp.multiline.coffee punctuation.definition.string.begin.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -441,7 +441,7 @@ }, { "c": " ", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -452,7 +452,7 @@ }, { "c": "#{", - "t": "source.coffee string.regexp.coffee source.coffee.embedded.source punctuation.section.embedded.coffee", + "t": "source.coffee string.regexp.multiline.coffee source.coffee.embedded.source punctuation.section.embedded.coffee", "r": { "dark_plus": "punctuation.section.embedded: #569CD6", "light_plus": "punctuation.section.embedded: #0000FF", @@ -463,7 +463,7 @@ }, { "c": "name", - "t": "source.coffee string.regexp.coffee source.coffee.embedded.source", + "t": "source.coffee string.regexp.multiline.coffee source.coffee.embedded.source", "r": { "dark_plus": "source.coffee.embedded: #9CDCFE", "light_plus": "source.coffee.embedded: #FF0000", @@ -474,7 +474,7 @@ }, { "c": "}", - "t": "source.coffee string.regexp.coffee source.coffee.embedded.source punctuation.section.embedded.coffee", + "t": "source.coffee string.regexp.multiline.coffee source.coffee.embedded.source punctuation.section.embedded.coffee", "r": { "dark_plus": "punctuation.section.embedded: #569CD6", "light_plus": "punctuation.section.embedded: #0000FF", @@ -485,7 +485,7 @@ }, { "c": "fancyRegExp = ", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -496,7 +496,7 @@ }, { "c": "///", - "t": "source.coffee string.regexp.coffee punctuation.definition.string.end.coffee", + "t": "source.coffee string.regexp.multiline.coffee punctuation.definition.string.end.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -716,7 +716,7 @@ }, { "c": "///", - "t": "source.coffee string.regexp.coffee punctuation.definition.string.begin.coffee", + "t": "source.coffee string.regexp.multiline.coffee punctuation.definition.string.begin.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", diff --git a/extensions/coffeescript/test/colorize-results/test_coffee.json b/extensions/coffeescript/test/colorize-results/test_coffee.json index 88ebb45da86..026517ea2c4 100644 --- a/extensions/coffeescript/test/colorize-results/test_coffee.json +++ b/extensions/coffeescript/test/colorize-results/test_coffee.json @@ -1354,7 +1354,7 @@ }, { "c": "///", - "t": "source.coffee string.regexp.coffee punctuation.definition.string.begin.coffee", + "t": "source.coffee string.regexp.multiline.coffee punctuation.definition.string.begin.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1365,7 +1365,7 @@ }, { "c": "\t", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1376,7 +1376,7 @@ }, { "c": "(", - "t": "source.coffee string.regexp.coffee meta.group.regexp punctuation.definition.group.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp punctuation.definition.group.regexp", "r": { "dark_plus": "punctuation.definition.group.regexp: #CE9178", "light_plus": "punctuation.definition.group.regexp: #D16969", @@ -1387,7 +1387,7 @@ }, { "c": "\\d", - "t": "source.coffee string.regexp.coffee meta.group.regexp constant.character.character-class.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp constant.character.character-class.regexp", "r": { "dark_plus": "constant.character.character-class.regexp: #D16969", "light_plus": "constant.character.character-class.regexp: #811F3F", @@ -1398,7 +1398,7 @@ }, { "c": "+", - "t": "source.coffee string.regexp.coffee meta.group.regexp keyword.operator.quantifier.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp keyword.operator.quantifier.regexp", "r": { "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", "light_plus": "keyword.operator.quantifier.regexp: #000000", @@ -1409,7 +1409,7 @@ }, { "c": ")", - "t": "source.coffee string.regexp.coffee meta.group.regexp punctuation.definition.group.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp punctuation.definition.group.regexp", "r": { "dark_plus": "punctuation.definition.group.regexp: #CE9178", "light_plus": "punctuation.definition.group.regexp: #D16969", @@ -1420,7 +1420,7 @@ }, { "c": "\t", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1431,7 +1431,7 @@ }, { "c": "#", - "t": "source.coffee string.regexp.coffee comment.line.number-sign.coffee punctuation.definition.comment.coffee", + "t": "source.coffee string.regexp.multiline.coffee comment.line.number-sign.coffee punctuation.definition.comment.coffee", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1442,7 +1442,7 @@ }, { "c": " numbers", - "t": "source.coffee string.regexp.coffee comment.line.number-sign.coffee", + "t": "source.coffee string.regexp.multiline.coffee comment.line.number-sign.coffee", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1453,7 +1453,7 @@ }, { "c": "\t", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1464,7 +1464,7 @@ }, { "c": "(", - "t": "source.coffee string.regexp.coffee meta.group.regexp punctuation.definition.group.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp punctuation.definition.group.regexp", "r": { "dark_plus": "punctuation.definition.group.regexp: #CE9178", "light_plus": "punctuation.definition.group.regexp: #D16969", @@ -1475,7 +1475,7 @@ }, { "c": "\\w", - "t": "source.coffee string.regexp.coffee meta.group.regexp constant.character.character-class.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp constant.character.character-class.regexp", "r": { "dark_plus": "constant.character.character-class.regexp: #D16969", "light_plus": "constant.character.character-class.regexp: #811F3F", @@ -1486,7 +1486,7 @@ }, { "c": "*", - "t": "source.coffee string.regexp.coffee meta.group.regexp keyword.operator.quantifier.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp keyword.operator.quantifier.regexp", "r": { "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", "light_plus": "keyword.operator.quantifier.regexp: #000000", @@ -1497,7 +1497,7 @@ }, { "c": ")", - "t": "source.coffee string.regexp.coffee meta.group.regexp punctuation.definition.group.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp punctuation.definition.group.regexp", "r": { "dark_plus": "punctuation.definition.group.regexp: #CE9178", "light_plus": "punctuation.definition.group.regexp: #D16969", @@ -1508,7 +1508,7 @@ }, { "c": "\t", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1519,7 +1519,7 @@ }, { "c": "#", - "t": "source.coffee string.regexp.coffee comment.line.number-sign.coffee punctuation.definition.comment.coffee", + "t": "source.coffee string.regexp.multiline.coffee comment.line.number-sign.coffee punctuation.definition.comment.coffee", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1530,7 +1530,7 @@ }, { "c": " letters", - "t": "source.coffee string.regexp.coffee comment.line.number-sign.coffee", + "t": "source.coffee string.regexp.multiline.coffee comment.line.number-sign.coffee", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1541,7 +1541,7 @@ }, { "c": "\t", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1552,7 +1552,7 @@ }, { "c": "$", - "t": "source.coffee string.regexp.coffee keyword.control.anchor.regexp", + "t": "source.coffee string.regexp.multiline.coffee keyword.control.anchor.regexp", "r": { "dark_plus": "keyword.control.anchor.regexp: #DCDCAA", "light_plus": "keyword.control.anchor.regexp: #FF0000", @@ -1563,7 +1563,7 @@ }, { "c": "\t\t", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1574,7 +1574,7 @@ }, { "c": "#", - "t": "source.coffee string.regexp.coffee comment.line.number-sign.coffee punctuation.definition.comment.coffee", + "t": "source.coffee string.regexp.multiline.coffee comment.line.number-sign.coffee punctuation.definition.comment.coffee", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1585,7 +1585,7 @@ }, { "c": " the end", - "t": "source.coffee string.regexp.coffee comment.line.number-sign.coffee", + "t": "source.coffee string.regexp.multiline.coffee comment.line.number-sign.coffee", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1596,7 +1596,7 @@ }, { "c": "///", - "t": "source.coffee string.regexp.coffee punctuation.definition.string.end.coffee", + "t": "source.coffee string.regexp.multiline.coffee punctuation.definition.string.end.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", diff --git a/extensions/cpp/syntaxes/c.json b/extensions/cpp/syntaxes/c.json index d02d09bdaeb..d5143bd4901 100644 --- a/extensions/cpp/syntaxes/c.json +++ b/extensions/cpp/syntaxes/c.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/atom/language-c/commit/0a57fd7ee32bd14e3ee8291434263d744a8ecf1e", + "version": "https://github.com/atom/language-c/commit/9c0c5f202741a5647025db8d5df5fefba47b036c", "scopeName": "source.c", "fileTypes": [ "c", diff --git a/extensions/cpp/test/colorize-fixtures/test-23850.cpp b/extensions/cpp/test/colorize-fixtures/test-23850.cpp new file mode 100644 index 00000000000..00e503a204c --- /dev/null +++ b/extensions/cpp/test/colorize-fixtures/test-23850.cpp @@ -0,0 +1,3 @@ +#ifndef _UCRT +#define _UCRT +#endif \ No newline at end of file diff --git a/extensions/cpp/test/colorize-results/test-23850_cpp.json b/extensions/cpp/test/colorize-results/test-23850_cpp.json new file mode 100644 index 00000000000..bbb5237498f --- /dev/null +++ b/extensions/cpp/test/colorize-results/test-23850_cpp.json @@ -0,0 +1,112 @@ +[ + { + "c": "#", + "t": "source.cpp meta.preprocessor.c keyword.control.directive.conditional.c punctuation.definition.directive.c", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": "ifndef", + "t": "source.cpp meta.preprocessor.c keyword.control.directive.conditional.c", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": " ", + "t": "source.cpp meta.preprocessor.c", + "r": { + "dark_plus": "meta.preprocessor: #569CD6", + "light_plus": "meta.preprocessor: #0000FF", + "dark_vs": "meta.preprocessor: #569CD6", + "light_vs": "meta.preprocessor: #0000FF", + "hc_black": "meta.preprocessor: #569CD6" + } + }, + { + "c": "_UCRT", + "t": "source.cpp meta.preprocessor.c entity.name.function.preprocessor.c", + "r": { + "dark_plus": "entity.name.function: #DCDCAA", + "light_plus": "entity.name.function: #795E26", + "dark_vs": "meta.preprocessor: #569CD6", + "light_vs": "meta.preprocessor: #0000FF", + "hc_black": "entity.name.function: #DCDCAA" + } + }, + { + "c": "#", + "t": "source.cpp meta.preprocessor.macro.c keyword.control.directive.define.c punctuation.definition.directive.c", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": "define", + "t": "source.cpp meta.preprocessor.macro.c keyword.control.directive.define.c", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": " ", + "t": "source.cpp meta.preprocessor.macro.c", + "r": { + "dark_plus": "meta.preprocessor: #569CD6", + "light_plus": "meta.preprocessor: #0000FF", + "dark_vs": "meta.preprocessor: #569CD6", + "light_vs": "meta.preprocessor: #0000FF", + "hc_black": "meta.preprocessor: #569CD6" + } + }, + { + "c": "_UCRT", + "t": "source.cpp meta.preprocessor.macro.c entity.name.function.preprocessor.c", + "r": { + "dark_plus": "entity.name.function: #DCDCAA", + "light_plus": "entity.name.function: #795E26", + "dark_vs": "meta.preprocessor: #569CD6", + "light_vs": "meta.preprocessor: #0000FF", + "hc_black": "entity.name.function: #DCDCAA" + } + }, + { + "c": "#", + "t": "source.cpp meta.preprocessor.c keyword.control.directive.conditional.c punctuation.definition.directive.c", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": "endif", + "t": "source.cpp meta.preprocessor.c keyword.control.directive.conditional.c", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + } +] \ No newline at end of file diff --git a/extensions/css/syntaxes/css.tmLanguage.json b/extensions/css/syntaxes/css.tmLanguage.json index 01f4730c4b5..95caf371210 100644 --- a/extensions/css/syntaxes/css.tmLanguage.json +++ b/extensions/css/syntaxes/css.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/atom/language-css/commit/2bc6abb2ee58b063f80999fa805d90d2f542da22", + "version": "https://github.com/atom/language-css/commit/ec289867164a34fce48a69776b7f8dc380e3dc37", "scopeName": "source.css", "name": "CSS", "fileTypes": [ @@ -1343,7 +1343,7 @@ "property-keywords": { "patterns": [ { - "match": "(?xi) (?,\\s*\\w+(?:\\.\\w+)*)*)(?=\\s*=(?!=))", "captures": { "1": { "patterns": [ @@ -242,7 +242,7 @@ "name": "invalid.illegal.identifier.go" }, { - "match": "\\w+(?:\\.\\w+)?", + "match": "\\w+(?:\\.\\w+)*", "name": "variable.other.assignment.go", "captures": { "0": { @@ -627,7 +627,7 @@ } }, { - "match": "(\\w+(?:,\\s*\\w+)*)(\\s+(\\[(\\d*|\\.\\.\\.)\\])*\\*?\\w+(?:\\.\\w+)?\\s*[^=].*)", + "match": "(\\w+(?:,\\s*\\w+)*)(\\s+(\\[(\\d*|\\.\\.\\.)\\])*\\*?(<-)?\\w+(?:\\.\\w+)?\\s*[^=].*)", "captures": { "1": { "patterns": [ diff --git a/extensions/java/syntaxes/java.tmLanguage.json b/extensions/java/syntaxes/java.tmLanguage.json index 28495a497cc..abc5ee65bb1 100644 --- a/extensions/java/syntaxes/java.tmLanguage.json +++ b/extensions/java/syntaxes/java.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/atom/language-java/commit/4eb3d906f572ef1999b7ebf0708c841d36b32f0b", + "version": "https://github.com/atom/language-java/commit/26b83893bf071f291481c924051462e17d2f77cd", "scopeName": "source.java", "name": "Java", "fileTypes": [ @@ -121,18 +121,21 @@ "annotations": { "patterns": [ { - "begin": "(@[^ (]+)(\\()", + "begin": "((@)[^\\s(]+)(\\()", "beginCaptures": { "1": { "name": "storage.type.annotation.java" }, "2": { + "name": "punctuation.definition.annotation.java" + }, + "3": { "name": "punctuation.definition.annotation-arguments.begin.bracket.round.java" } }, - "end": "(\\))", + "end": "\\)", "endCaptures": { - "1": { + "0": { "name": "punctuation.definition.annotation-arguments.end.bracket.round.java" } }, @@ -155,8 +158,25 @@ ] }, { - "match": "@\\w*", - "name": "storage.type.annotation.java" + "match": "(@)(interface)\\s+(\\w*)|((@)\\w*)", + "name": "meta.declaration.annotation.java", + "captures": { + "1": { + "name": "punctuation.definition.annotation.java" + }, + "2": { + "name": "storage.modifier.java" + }, + "3": { + "name": "storage.type.annotation.java" + }, + "4": { + "name": "storage.type.annotation.java" + }, + "5": { + "name": "punctuation.definition.annotation.java" + } + } } ] }, @@ -224,7 +244,7 @@ ] }, "class": { - "begin": "(?=\\w?[\\w\\s]*(?:class|(?:@)?interface|enum)\\s+\\w+)", + "begin": "(?=\\w?[\\w\\s]*(?:class|(?(\\w+\\.)*[A-Z]+\\w*) # e.g. `javax.ws.rs.Response`, or `String`\n )\n (\n <[\\w<>,?\\s]*> # HashMap\n |\n (\\[\\])* # int[][]\n )?\n \\s+\n [A-Za-z_$][\\w$]* # At least one identifier after space\n ([\\w\\[\\],$][\\w\\[\\],\\s]*)? # possibly primitive array or additional identifiers\n \\s*(=|;)\n)", + "begin": "(?x)\n(?=\n (\n (void|boolean|byte|char|short|int|float|long|double)\n |\n (?>(\\w+\\.)*[A-Z]+\\w*) # e.g. `javax.ws.rs.Response`, or `String`\n )\n (\n <[\\w<>,?\\s]*> # HashMap\n )?\n (\n (\\[\\])* # int[][]\n )?\n \\s+\n [A-Za-z_$][\\w$]* # At least one identifier after space\n ([\\w\\[\\],$][\\w\\[\\],\\s]*)? # possibly primitive array or additional identifiers\n \\s*(=|;)\n)", "end": "(?=;)", "name": "meta.definition.variable.java", "patterns": [ diff --git a/extensions/java/test/colorize-results/basic_java.json b/extensions/java/test/colorize-results/basic_java.json index 0622a9209cc..1ef3a8ff324 100644 --- a/extensions/java/test/colorize-results/basic_java.json +++ b/extensions/java/test/colorize-results/basic_java.json @@ -1056,7 +1056,18 @@ } }, { - "c": "@SuppressWarnings", + "c": "@", + "t": "source.java meta.class.java meta.class.body.java meta.declaration.annotation.java storage.type.annotation.java punctuation.definition.annotation.java", + "r": { + "dark_plus": "storage.type.annotation.java: #4EC9B0", + "light_plus": "storage.type.annotation.java: #267F99", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type.annotation.java: #4EC9B0" + } + }, + { + "c": "SuppressWarnings", "t": "source.java meta.class.java meta.class.body.java meta.declaration.annotation.java storage.type.annotation.java", "r": { "dark_plus": "storage.type.annotation.java: #4EC9B0", @@ -1848,8 +1859,19 @@ } }, { - "c": "@Test", - "t": "source.java meta.class.java meta.class.body.java storage.type.annotation.java", + "c": "@", + "t": "source.java meta.class.java meta.class.body.java meta.declaration.annotation.java storage.type.annotation.java punctuation.definition.annotation.java", + "r": { + "dark_plus": "storage.type.annotation.java: #4EC9B0", + "light_plus": "storage.type.annotation.java: #267F99", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type.annotation.java: #4EC9B0" + } + }, + { + "c": "Test", + "t": "source.java meta.class.java meta.class.body.java meta.declaration.annotation.java storage.type.annotation.java", "r": { "dark_plus": "storage.type.annotation.java: #4EC9B0", "light_plus": "storage.type.annotation.java: #267F99", diff --git a/extensions/markdown/package.json b/extensions/markdown/package.json index 5cb34c4c662..5c7f6d8c0ed 100644 --- a/extensions/markdown/package.json +++ b/extensions/markdown/package.json @@ -177,6 +177,10 @@ { "command": "markdown.showPreviewSecuritySelector", "when": "editorLangId == markdown" + }, + { + "command": "markdown.showPreviewSecuritySelector", + "when": "resourceScheme == markdown" } ] }, diff --git a/extensions/package.json b/extensions/package.json index 1e3f4a31a5d..c2911d05072 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "^2.6.1-insiders.20171019" + "typescript": "2.6.1-insiders.20171019" }, "scripts": { "postinstall": "node ./postinstall" diff --git a/extensions/php/language-configuration.json b/extensions/php/language-configuration.json index 0b35ccae67d..8172fcd09e5 100644 --- a/extensions/php/language-configuration.json +++ b/extensions/php/language-configuration.json @@ -26,5 +26,11 @@ "indentationRules": { "increaseIndentPattern": "({(?!.+}).*|\\(|\\[|((else(\\s)?)?if|else|for(each)?|while|switch).*:)\\s*(/[/*].*)?$", "decreaseIndentPattern": "^(.*\\*\\/)?\\s*((\\})|(\\)+[;,])|(\\][;,])|\\b(else:)|\\b((end(if|for(each)?|while|switch));))" + }, + "folding": { + "markers": { + "start": "^\\s*(#|\/\/)region\\b", + "end": "^\\s*(#|\/\/)endregion\\b" + } } } \ No newline at end of file diff --git a/extensions/php/syntaxes/php.tmLanguage.json b/extensions/php/syntaxes/php.tmLanguage.json index 5a49ff84c7c..aa0446b8af1 100644 --- a/extensions/php/syntaxes/php.tmLanguage.json +++ b/extensions/php/syntaxes/php.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/atom/language-php/commit/8f56c3d5a59fb26e028a8b02c697920c73214fca", + "version": "https://github.com/atom/language-php/commit/71231bfb975ac56d9c13c5b4cda21c081ebbc6ee", "scopeName": "text.html.php", "name": "PHP", "fileTypes": [ @@ -20,7 +20,8 @@ "php5", "phpt", "phtml", - "profile" + "profile", + "theme" ], "firstLineMatch": "(?x)\n# Hashbang\n^\\#!.*(?:\\s|\\/)\n php\\d?\n(?:$|\\s)\n|\n# Modeline\n(?i:\n # Emacs\n -\\*-(?:\\s*(?=[^:;\\s]+\\s*-\\*-)|(?:.*?[;\\s]|(?<=-\\*-))mode\\s*:\\s*)\n php\n (?=[\\s;]|(?]?\\d+|m)?|\\sex)(?=:(?=\\s*set?\\s[^\\n:]+:)|:(?!\\s*set?\\s))(?:(?:\\s|\\s*:\\s*)\\w*(?:\\s*=(?:[^\\n\\\\\\s]|\\\\.)*)?)*[\\s:](?:filetype|ft|syntax)\\s*=\n (?:php|phtml)\n (?=\\s|:|$)\n)", "foldingStartMarker": "(/\\*|\\{\\s*$|<<))", - "beginCaptures": { - "0": { - "name": "punctuation.whitespace.embedded.leading.php" - } - }, - "end": "(?!\\G)(\\s*$\\n)?", - "endCaptures": { - "0": { - "name": "punctuation.whitespace.embedded.trailing.php" - } - }, - "patterns": [ - { - "begin": "<\\?(?i:php|=)?", - "beginCaptures": { - "0": { - "name": "punctuation.section.embedded.begin.php" - } - }, - "contentName": "source.php", - "end": "(\\?)>", - "endCaptures": { - "0": { - "name": "punctuation.section.embedded.end.php" - }, - "1": { - "name": "source.php" - } - }, - "name": "meta.embedded.block.php", - "patterns": [ - { - "include": "#language" - } - ] - } - ] - }, { "begin": "<\\?(?i:php|=)?(?![^?]*\\?>)", "beginCaptures": { @@ -2556,7 +2517,7 @@ "scope-resolution": { "patterns": [ { - "match": "(?i)\\b([a-z_\\x{7f}-\\x{ff}][a-z0-9_\\x{7f}-\\x{ff}]*)(?=\\s*::)", + "match": "(?i)([a-z_\\x{7f}-\\x{ff}\\\\][a-z0-9_\\x{7f}-\\x{ff}\\\\]*)(?=\\s*::)", "captures": { "1": { "patterns": [ diff --git a/extensions/php/test/colorize-results/issue-28354_php.json b/extensions/php/test/colorize-results/issue-28354_php.json index 553ade314b5..ec02263f54e 100644 --- a/extensions/php/test/colorize-results/issue-28354_php.json +++ b/extensions/php/test/colorize-results/issue-28354_php.json @@ -56,7 +56,7 @@ }, { "c": " ", - "t": "text.html.php meta.embedded.block.html source.js punctuation.whitespace.embedded.leading.php", + "t": "text.html.php meta.embedded.block.html source.js", "r": { "dark_plus": "meta.embedded: #D4D4D4", "light_plus": "meta.embedded: #000000", diff --git a/extensions/powershell/syntaxes/PowershellSyntax.tmLanguage b/extensions/powershell/syntaxes/PowershellSyntax.tmLanguage index 5a8c8f24ce3..1ad8b5e38b5 100644 --- a/extensions/powershell/syntaxes/PowershellSyntax.tmLanguage +++ b/extensions/powershell/syntaxes/PowershellSyntax.tmLanguage @@ -45,7 +45,7 @@ begin - (?<![\\-])# + (?<![`\\-])# end $ name diff --git a/extensions/r/syntaxes/r.tmLanguage.json b/extensions/r/syntaxes/r.tmLanguage.json index 38d7ae112e3..38ce48074cb 100644 --- a/extensions/r/syntaxes/r.tmLanguage.json +++ b/extensions/r/syntaxes/r.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/Ikuyadeu/vscode-R/commit/0ad8c770ea3836b15bc121fff4161a794d3deeaa", + "version": "https://github.com/Ikuyadeu/vscode-R/commit/b3ef459a3999160d97ea28f4754fda810417f99f", "fileTypes": [ "R", "r", @@ -178,11 +178,15 @@ "name": "keyword.operator.arithmetic.r" }, { - "match": "(=|<-|<<-|->|->>)", + "match": "==", + "name": "keyword.operator.comarison.r" + }, + { + "match": "(:=|<-|<<-|->|->>)", "name": "keyword.operator.assignment.r" }, { - "match": "(==|!=|<>|<|>|<=|>=)", + "match": "(!=|<>|<|>|<=|>=|%in%)", "name": "keyword.operator.comparison.r" }, { @@ -190,7 +194,7 @@ "name": "keyword.operator.logical.r" }, { - "match": "(%in%|:=|%between%|%chin%|%like%|%\\+%|%\\+replace%|%:%|%do%|%dopar%|%>%|%<>%|%T>%|%\\$%)", + "match": "(%between%|%chin%|%like%|%\\+%|%\\+replace%|%:%|%do%|%dopar%|%>%|%<>%|%T>%|%\\$%)", "name": "keyword.operator.other.r" }, { @@ -337,7 +341,7 @@ "function-declarations": { "patterns": [ { - "begin": "^\\s*([a-zA-Z0-9._:]*)\\s*(<", + "end": "(?", "patterns": [ { "include": "#block_comment" diff --git a/extensions/scss/syntaxes/scss.json b/extensions/scss/syntaxes/scss.json index aff662ec96b..520c09e515d 100644 --- a/extensions/scss/syntaxes/scss.json +++ b/extensions/scss/syntaxes/scss.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/atom/language-sass/commit/229a9c9c2c025dc0514f2550819876fc1bb5df57", + "version": "https://github.com/atom/language-sass/commit/d47701c2d389c5e657b8c51a34d90691e4bac3ea", "scopeName": "source.css.scss", "name": "SCSS", "fileTypes": [ @@ -33,6 +33,9 @@ { "include": "#rules" }, + { + "include": "#selectors" + }, { "include": "#property_list" }, @@ -492,6 +495,9 @@ }, { "include": "#rules" + }, + { + "include": "#selectors" } ] } @@ -1155,7 +1161,7 @@ "properties": { "patterns": [ { - "begin": "(? - - - - fileTypes - - sql - ddl - dml - dsql - psql - - keyEquivalent - ^~S - name - SQL - patterns - - - include - #comments - - - captures - - 1 - - name - keyword.other.create.sql - - 2 - - name - keyword.other.sql - - 5 - - name - entity.name.function.sql - - - match - (?i:^\s*(create(?:\s+or\s+replace)?)\s+(aggregate|conversion|database|domain|function|group|(unique\s+)?index|language|operator class|operator|rule|schema|sequence|table|tablespace|trigger|type|user|view)\s+)(['"`]?)(\w+)\4 - name - meta.create.sql - - - captures - - 1 - - name - keyword.other.create.sql - - 2 - - name - keyword.other.sql - - - match - (?i:^\s*(drop)\s+(aggregate|conversion|database|domain|function|group|index|language|operator class|operator|rule|schema|sequence|table|tablespace|trigger|type|user|view)) - name - meta.drop.sql - - - captures - - 1 - - name - keyword.other.create.sql - - 2 - - name - keyword.other.table.sql - - 3 - - name - entity.name.function.sql - - 4 - - name - keyword.other.cascade.sql - - - match - (?i:\s*(drop)\s+(table)\s+(\w+)(\s+cascade)?\b) - name - meta.drop.sql - - - captures - - 1 - - name - keyword.other.create.sql - - 2 - - name - keyword.other.table.sql - - - match - (?i:^\s*(alter)\s+(aggregate|conversion|database|domain|function|group|index|language|operator class|operator|rule|schema|sequence|table|tablespace|trigger|type|user|view)\s+) - name - meta.alter.sql - - - captures - - 1 - - name - storage.type.sql - - 10 - - name - constant.numeric.sql - - 11 - - name - storage.type.sql - - 12 - - name - storage.type.sql - - 13 - - name - storage.type.sql - - 14 - - name - constant.numeric.sql - - 15 - - name - storage.type.sql - - 2 - - name - storage.type.sql - - 3 - - name - constant.numeric.sql - - 4 - - name - storage.type.sql - - 5 - - name - constant.numeric.sql - - 6 - - name - storage.type.sql - - 7 - - name - constant.numeric.sql - - 8 - - name - constant.numeric.sql - - 9 - - name - storage.type.sql - - - match - (?xi) - - # normal stuff, capture 1 - \b(bigint|bigserial|bit|boolean|box|bytea|cidr|circle|date|double\sprecision|inet|int|integer|line|lseg|macaddr|money|oid|path|point|polygon|real|serial|smallint|sysdate|text)\b - - # numeric suffix, capture 2 + 3i - |\b(bit\svarying|character\s(?:varying)?|tinyint|var\schar|float|interval)\((\d+)\) - - # optional numeric suffix, capture 4 + 5i - |\b(char|number|varchar\d?)\b(?:\((\d+)\))? - - # special case, capture 6 + 7i + 8i - |\b(numeric|decimal)\b(?:\((\d+),(\d+)\))? - - # special case, captures 9, 10i, 11 - |\b(times?)\b(?:\((\d+)\))?(\swith(?:out)?\stime\szone\b)? - - # special case, captures 12, 13, 14i, 15 - |\b(timestamp)(?:(s|tz))?\b(?:\((\d+)\))?(\s(with|without)\stime\szone\b)? - - - - - match - (?i:\b((?:primary|foreign)\s+key|references|on\sdelete(\s+cascade)?|check|constraint)\b) - name - storage.modifier.sql - - - match - \b\d+\b - name - constant.numeric.sql - - - match - (?i:\b(select(\s+distinct)?|insert\s+(ignore\s+)?into|update|delete|from|declare|set|where|group\sby|or|like|and|union(\s+all)?|having|order\sby|limit|(inner|cross)\s+join|join|straight_join|(left|right)(\s+outer)?\s+join|natural(\s+(left|right)(\s+outer)?)?\s+join)\b) - name - keyword.other.DML.sql - - - match - (?i:\b(on|((is\s+)?not\s+)?null)\b) - name - keyword.other.DDL.create.II.sql - - - match - (?i:\b(values|go|use|into|exec|execute|openquery)\b) - name - keyword.other.DML.II.sql - - - match - (?i:\b(begin(\s+work)?|start\s+transaction|commit(\s+work)?|rollback(\s+work)?)\b) - name - keyword.other.LUW.sql - - - match - (?i:\b(grant(\swith\sgrant\soption)?|revoke)\b) - name - keyword.other.authorization.sql - - - match - (?i:\bin\b) - name - keyword.other.data-integrity.sql - - - match - (?i:^\s*(comment\s+on\s+(table|column|aggregate|constraint|database|domain|function|index|operator|rule|schema|sequence|trigger|type|view))\s+.*?\s+(is)\s+) - name - keyword.other.object-comments.sql - - - match - (?i)\bAS\b - name - keyword.other.alias.sql - - - match - (?i)\b(DESC|ASC)\b - name - keyword.other.order.sql - - - match - \* - name - keyword.operator.star.sql - - - match - [!<>]?=|<>|<|> - name - keyword.operator.comparison.sql - - - match - -|\+|/ - name - keyword.operator.math.sql - - - match - \|\| - name - keyword.operator.concatenator.sql - - - comment - List of SQL99 built-in functions from http://www.oreilly.com/catalog/sqlnut/chapter/ch04.html - match - (?i)\b(CURRENT_(DATE|TIME(STAMP)?|USER)|(SESSION|SYSTEM)_USER)\b - name - support.function.scalar.sql - - - comment - List of SQL99 built-in functions from http://www.oreilly.com/catalog/sqlnut/chapter/ch04.html - match - (?i)\b(AVG|COUNT|MIN|MAX|SUM)(?=\s*\() - name - support.function.aggregate.sql - - - match - (?i)\b(CONCATENATE|CONVERT|LOWER|SUBSTRING|TRANSLATE|TRIM|UPPER)\b - name - support.function.string.sql - - - captures - - 1 - - name - constant.other.database-name.sql - - 2 - - name - constant.other.table-name.sql - - - match - (\w+?)\.(\w+) - - - include - #strings - - - include - #regexps - - - captures - - 1 - - name - punctuation.section.scope.begin.sql - - 2 - - name - punctuation.section.scope.end.sql - - - comment - Allow for special ↩ behavior - match - (\()(\)) - name - meta.block.sql - - - repository - - comments - - patterns - - - begin - (^[ \t]+)?(?=--) - beginCaptures - - 1 - - name - punctuation.whitespace.comment.leading.sql - - - end - (?!\G) - patterns - - - begin - -- - beginCaptures - - 0 - - name - punctuation.definition.comment.sql - - - end - \n - name - comment.line.double-dash.sql - - - - - begin - (^[ \t]+)?(?=#) - beginCaptures - - 1 - - name - punctuation.whitespace.comment.leading.sql - - - end - (?!\G) - patterns - - - begin - # - beginCaptures - - 0 - - name - punctuation.definition.comment.sql - - - end - \n - name - comment.line.number-sign.sql - - - - - begin - /\* - captures - - 0 - - name - punctuation.definition.comment.sql - - - end - \*/ - name - comment.block.c - - - - regexps - - patterns - - - begin - /(?=\S.*/) - beginCaptures - - 0 - - name - punctuation.definition.string.begin.sql - - - end - / - endCaptures - - 0 - - name - punctuation.definition.string.end.sql - - - name - string.regexp.sql - patterns - - - include - #string_interpolation - - - match - \\/ - name - constant.character.escape.slash.sql - - - - - begin - %r\{ - beginCaptures - - 0 - - name - punctuation.definition.string.begin.sql - - - comment - We should probably handle nested bracket pairs!?! -- Allan - end - \} - endCaptures - - 0 - - name - punctuation.definition.string.end.sql - - - name - string.regexp.modr.sql - patterns - - - include - #string_interpolation - - - - - - string_escape - - match - \\. - name - constant.character.escape.sql - - string_interpolation - - captures - - 1 - - name - punctuation.definition.string.begin.sql - - 3 - - name - punctuation.definition.string.end.sql - - - match - (#\{)([^\}]*)(\}) - name - string.interpolated.sql - - strings - - patterns - - - captures - - 1 - - name - punctuation.definition.string.begin.sql - - 2 - - name - punctuation.definition.string.end.sql - - - comment - this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines. - match - (')[^'\\]*(') - name - string.quoted.single.sql - - - begin - ' - beginCaptures - - 0 - - name - punctuation.definition.string.begin.sql - - - end - ' - endCaptures - - 0 - - name - punctuation.definition.string.end.sql - - - name - string.quoted.single.sql - patterns - - - include - #string_escape - - - - - captures - - 1 - - name - punctuation.definition.string.begin.sql - - 2 - - name - punctuation.definition.string.end.sql - - - comment - this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines. - match - (`)[^`\\]*(`) - name - string.quoted.other.backtick.sql - - - begin - ` - beginCaptures - - 0 - - name - punctuation.definition.string.begin.sql - - - end - ` - endCaptures - - 0 - - name - punctuation.definition.string.end.sql - - - name - string.quoted.other.backtick.sql - patterns - - - include - #string_escape - - - - - captures - - 1 - - name - punctuation.definition.string.begin.sql - - 2 - - name - punctuation.definition.string.end.sql - - - comment - this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines. - match - (")[^"#]*(") - name - string.quoted.double.sql - - - begin - " - beginCaptures - - 0 - - name - punctuation.definition.string.begin.sql - - - end - " - endCaptures - - 0 - - name - punctuation.definition.string.end.sql - - - name - string.quoted.double.sql - patterns - - - include - #string_interpolation - - - - - begin - %\{ - beginCaptures - - 0 - - name - punctuation.definition.string.begin.sql - - - end - \} - endCaptures - - 0 - - name - punctuation.definition.string.end.sql - - - name - string.other.quoted.brackets.sql - patterns - - - include - #string_interpolation - - - - - - - scopeName - source.sql - uuid - C49120AC-6ECC-11D9-ACC8-000D93589AF6 - - diff --git a/extensions/sql/syntaxes/sql.tmLanguage.json b/extensions/sql/syntaxes/sql.tmLanguage.json new file mode 100644 index 00000000000..033fc63c97f --- /dev/null +++ b/extensions/sql/syntaxes/sql.tmLanguage.json @@ -0,0 +1,472 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/Microsoft/vscode-mssql/blob/master/syntaxes/SQL.plist", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": "https://github.com/Microsoft/vscode-mssql/commit/cfc8b65ed6daf8252b0cbfd5611aadbd49353bca", + "fileTypes": [ + "sql", + "ddl", + "dml" + ], + "keyEquivalent": "^~S", + "name": "SQL", + "patterns": [ + { + "match": "\\b(?i)(abort|abort_after_wait|absent|absolute|accent_sensitivity|acceptable_cursopt|acp|action|activation|address|admin|aes_128|aes_192|aes_256|affinity|after|aggregate|algorithm|all_constraints|all_errormsgs|all_indexes|all_levels|all_results|allow_connections|allow_dup_row|allow_encrypted_value_modifications|allow_page_locks|allow_row_locks|allow_snapshot_isolation|altercolumn|always|anonymous|ansi_defaults|ansi_null_default|ansi_null_dflt_off|ansi_null_dflt_on|ansi_nulls|ansi_padding|ansi_warnings|appdomain|append|application|apply|arithabort|arithignore|assembly|asymmetric|asynchronous_commit|at|atan2|atomic|attach|attach_force_rebuild_log|attach_rebuild_log|audit|auth_realm|authentication|auto|auto_cleanup|auto_close|auto_create_statistics|auto_shrink|auto_update_statistics|auto_update_statistics_async|automated_backup_preference |automatic|autopilot|availability|availability_mode|backup_priority|base64|basic|batches|batchsize|before|bigint|binary|binding|bit|block|blocksize|bmk|broker|broker_instance|bucket_count|buffer|buffercount|bulk_logged|by|call|caller|card|case|cast|catalog|catch|cert|certificate|change_retention|change_tracking|change_tracking_context|changes|char|character|character_set|check_expiration|check_policy|checkconstraints|checkindex|checkpoint|cleanup_policy|clear|clear_port|codepage|collection|column_encryption_key|column_master_key|columnstore|columnstore_archive|colv_80_to_100|colv_100_to_80|commit_differential_base|committed|compatibility_level|compress_all_row_groups|compression|compression_delay|concat_null_yields_null|concatenate|configuration|connect|continue_after_error|contract|contract_name|control|conversation|conversation_group_id|conversation_handle|copy|copy_only|count_rows|counter|create|credential|cross|cryptographic|cryptographic_provider|cube|cursor_close_on_commit|cursor_default|data|data_compression|data_flush_interval_seconds|data_mirroring|data_purity|data_source|database|database_name|database_snapshot|datafiletype|date_correlation_optimization|date|datefirst|dateformat|date_format|datetime|datetime2|datetimeoffset|days|db_chaining|dbid|dbidexec|dbo_only|deadlock_priority|dec|decimal|declare|decrypt|decrypt_a|decryption|default_database|default_language|default_logon_domain|default_schema|definition|delay|delayed_durability|delimitedtext|density_vector|dependent|des|description|desired_state|desx|differential|digest|disable|disable_broker|disable_def_cnst_chk|disabled|disk|distribution|drop|drop_existing|dts_buffers|dump|durability|dynamic|edition|elements|emergency|empty|enable|enable_broker|enabled|encoding|encrypted|encrypted_value|encryption|encryption_type|end|endpoint|endpoint_url|enhancedintegrity|entry|error_broker_conversations|errorfile|estimateonly|event|exec|executable|exists|expand|expiredate|expiry_date|explicit|external_access|failover|failover_mode|failure_condition_level|fast|fast_forward|fastfirstrow|federated_service_account|field_terminator|fieldterminator|file|filelistonly|filegroup|filename|filestream|filestream_log|filestream_on|filetable|file_format|filter|fips_flagger|fire_triggers|first|firstrow|float|flush_interval_seconds|fmtonly|following|force|force_failover_allow_data_loss|force_service_allow_data_loss|forced|forceplan|formatfile|format_options|format_type|formsof|forward_only|free_cursors|free_exec_context|fullscan|fulltext|fulltextall|fulltextkey|function|generated|get|geography|geometry|global|go|governor|guid|hadoop|hardening|hash|hashed|header_limit|headeronly|health_check_timeout|hidden|hierarchyid|histogram|histogram_steps|hits_cursors|hits_exec_context|hours|http|identity_value|if|ifnull|ignore_constraints|ignore_dup_key|ignore_dup_row|ignore_triggers|image|immediate|implicit_transactions|include|include_null_values|inflectional|init|initiator|insensitive|insert|instead|int|integer|integrated|intermediate|interval_length_minutes|into|inuse_cursors|inuse_exec_context|io|is|isabout|iso_week|isolation|job_tracker_location|json|keep|keep_nulls|keep_replication|keepdefaults|keepfixed|keepidentity|keepnulls|kerberos|key|key_path|key_source|key_store_provider_name|keyset|kilobytes_per_batch|labelonly|langid|language|last|lastrow|legacy_cardinality_estimation|length|level|lifetime|lineage_80_to_100|lineage_100_to_80|listener_ip|listener_port|load|loadhistory|lob_compaction|local|local_service_name|locate|location|lock_escalation|lock_timeout|lockres|login|login_type|loop|manual|mark_in_use_for_removal|masked|master|max_queue_readers|max_duration|max_outstanding_io_per_volume|maxdop|maxerrors|maxlength|maxtransfersize|max_plans_per_query|max_storage_size_mb|mediadescription|medianame|mediapassword|memogroup|memory_optimized|merge|message|message_forward_size|message_forwarding|microsecond|millisecond|minutes|mirror_address|misses_cursors|misses_exec_context|mixed|modify|money|move|multi_user|must_change|name|namespace|nanosecond|native|native_compilation|nchar|ncharacter|never|new_account|new_broker|newname|next|no|no_browsetable|no_checksum|no_compression|no_infomsgs|no_triggers|no_truncate|nocount|noexec|noexpand|noformat|noinit|nolock|nonatomic|nondurable|none|norecompute|norecovery|noreset|norewind|noskip|not|notification|nounload|now|nowait|ntext|ntlm|numeric|numeric_roundabort|nvarchar|object|objid|oem|offline|old_account|online|operation_mode|openjson|optimistic|option|orc|out|outer|output|over|override|owner|ownership|pad_index|page|page_checksum|page_verify|pagecount|paglock|param|parameter_sniffing|parameter_type_expansion|parameterization|parquet|parseonly|partial|partition|partner|password|path|pause|percentage|permission_set|persisted|period|physical_only|plan_forcing_mode|policy|pool|population|ports|preceding|precision|predicate|presume_abort|primary|primary_role|print|prior|priority |priority_level|private|procedure_name|profile|provider|query_capture_mode|query_governor_cost_limit|query_optimizer_hotfixes|query_store|queue|quoted_identifier|range|raw|rcfile|rc2|rc4|rc4_128|rdbms|read_committed_snapshot|read|read_only|read_write|readcommitted|readcommittedlock|readonly|readpast|readuncommitted|readwrite|real|rebuild|receive|recmodel_70backcomp|recompile|recovery|recursive|recursive_triggers|redo_queue|reject_sample_value|reject_type|reject_value|relative|remote|remote_data_archive|remote_proc_transactions|remote_service_name|remove|removed_cursors|removed_exec_context|reorganize|repeat|repeatable|repeatableread|replica|replicated|replnick_100_to_80|replnickarray_80_to_100|replnickarray_100_to_80|required|required_cursopt|resample|reset|resource|resource_manager_location|restart|restore|restricted_user|resume|retaindays|retention|return|rewind|rewindonly|returns|robust|role|rollup|root|round_robin|route|row|rowdump|rowlock|row_terminator|rows|rows_per_batch|rowsets_only|rowterminator|rowversion|rsa_1024|rsa_2048|rsa_3072|rsa_4096|rsa_512|safe|safety|sample|schemabinding|scoped|scroll|scroll_locks|sddl|secexpr|secondary|secondary_only|secondary_role|secret|security|securityaudit|selective|self|send|sent|sequence|serde_method|serializable|server|service|service_broker|service_name|service_objective|session_timeout|session|sessions|seterror|setopts|sets|shard_map_manager|shard_map_name|sharded|shared_memory|show_statistics|showplan_all|showplan_text|showplan_xml|showplan_xml_with_recompile|shrinkdb|sid|signature|simple|single_blob|single_clob|single_nclob|single_user|singleton|site|size_based_cleanup_mode|skip|smalldatetime|smallint|smallmoney|snapshot|snapshot_import|snapshotrestorephase|soap|softnuma|sort_in_tempdb|sorted_data|sorted_data_reorg|spatial|sql|sql_bigint|sql_binary|sql_bit|sql_char|sql_date|sql_decimal|sql_double|sql_float|sql_guid|sql_handle|sql_longvarbinary|sql_longvarchar|sql_numeric|sql_real|sql_smallint|sql_time|sql_timestamp|sql_tinyint|sql_tsi_day|sql_tsi_frac_second|sql_tsi_hour|sql_tsi_minute|sql_tsi_month|sql_tsi_quarter|sql_tsi_second|sql_tsi_week|sql_tsi_year|sql_type_date|sql_type_time|sql_type_timestamp|sql_varbinary|sql_varchar|sql_variant|sql_wchar|sql_wlongvarchar|ssl|ssl_port|standard|standby|start|start_date|started|stat_header|state|statement|static|statistics|statistics_incremental|statistics_norecompute|statistics_only|statman|stats_stream|status|stop|stop_on_error|stopat|stopatmark|stopbeforemark|stoplist|stopped|string_delimiter|subject|supplemental_logging|supported|suspend|symmetric|synchronous_commit|synonym|sysname|system|system_time|system_versioning|table|tableresults|tablock|tablockx|take|tape|target|target_index|target_partition|tcp|temporal_history_retention|text|textimage_on|then|thesaurus|throw|time|timeout|timestamp|tinyint|to|top|torn_page_detection|track_columns_updated|tran|transaction|transfer|triple_des|triple_des_3key|trustworthy|try|tsql|type|type_desc|type_warning|tzoffset|uid|unbounded|uncommitted|uniqueidentifier|unlimited|unload|unlock|unsafe|updlock|url|use|useplan|useroptions|use_type_default|using|utcdatetime|valid_xml|validation|value|values|varbinary|varchar|verbose|verifyonly|version|view_metadata|virtual_device|visiblity|webmethod|weekday|weight|well_formed_xml|when|widechar|widechar_ansi|widenative|windows|with|within|witness|without|without_array_wrapper|workload|wsdl|xact_abort|xlock|xml|xmlschema|xquery|xsinil|zone)\\b", + "name": "keyword.other.sql" + }, + { + "include": "#comments" + }, + { + "captures": { + "1": { + "name": "keyword.other.create.sql" + }, + "2": { + "name": "keyword.other.sql" + }, + "5": { + "name": "entity.name.function.sql" + } + }, + "match": "(?i:^\\s*(create(?:\\s+or\\s+replace)?)\\s+(aggregate|conversion|database|domain|function|group|(unique\\s+)?index|language|operator class|operator|rule|schema|sequence|table|tablespace|trigger|type|user|view)\\s+)(['\"`]?)(\\w+)\\4", + "name": "meta.create.sql" + }, + { + "captures": { + "1": { + "name": "keyword.other.create.sql" + }, + "2": { + "name": "keyword.other.sql" + } + }, + "match": "(?i:^\\s*(drop)\\s+(aggregate|conversion|database|domain|function|group|index|language|operator class|operator|rule|schema|sequence|table|tablespace|trigger|type|user|view))", + "name": "meta.drop.sql" + }, + { + "captures": { + "1": { + "name": "keyword.other.create.sql" + }, + "2": { + "name": "keyword.other.table.sql" + }, + "3": { + "name": "entity.name.function.sql" + }, + "4": { + "name": "keyword.other.cascade.sql" + } + }, + "match": "(?i:\\s*(drop)\\s+(table)\\s+(\\w+)(\\s+cascade)?\\b)", + "name": "meta.drop.sql" + }, + { + "captures": { + "1": { + "name": "keyword.other.create.sql" + }, + "2": { + "name": "keyword.other.table.sql" + } + }, + "match": "(?i:^\\s*(alter)\\s+(aggregate|conversion|database|domain|function|group|index|language|operator class|operator|rule|schema|sequence|table|tablespace|trigger|type|user|view)\\s+)", + "name": "meta.alter.sql" + }, + { + "captures": { + "1": { + "name": "storage.type.sql" + }, + "2": { + "name": "storage.type.sql" + }, + "3": { + "name": "constant.numeric.sql" + }, + "4": { + "name": "storage.type.sql" + }, + "5": { + "name": "constant.numeric.sql" + }, + "6": { + "name": "storage.type.sql" + }, + "7": { + "name": "constant.numeric.sql" + }, + "8": { + "name": "constant.numeric.sql" + }, + "9": { + "name": "storage.type.sql" + }, + "10": { + "name": "constant.numeric.sql" + }, + "11": { + "name": "storage.type.sql" + }, + "12": { + "name": "storage.type.sql" + }, + "13": { + "name": "storage.type.sql" + }, + "14": { + "name": "constant.numeric.sql" + }, + "15": { + "name": "storage.type.sql" + } + }, + "match": "(?xi)\n\n\t\t\t\t# normal stuff, capture 1\n\t\t\t\t \\b(bigint|bigserial|bit|boolean|box|bytea|cidr|circle|date|double\\sprecision|inet|int|integer|line|lseg|macaddr|money|oid|path|point|polygon|real|serial|smallint|sysdate|text)\\b\n\n\t\t\t\t# numeric suffix, capture 2 + 3i\n\t\t\t\t|\\b(bit\\svarying|character\\s(?:varying)?|tinyint|var\\schar|float|interval)\\((\\d+)\\)\n\n\t\t\t\t# optional numeric suffix, capture 4 + 5i\n\t\t\t\t|\\b(char|number|varchar\\d?)\\b(?:\\((\\d+)\\))?\n\n\t\t\t\t# special case, capture 6 + 7i + 8i\n\t\t\t\t|\\b(numeric|decimal)\\b(?:\\((\\d+),(\\d+)\\))?\n\n\t\t\t\t# special case, captures 9, 10i, 11\n\t\t\t\t|\\b(times?)\\b(?:\\((\\d+)\\))?(\\swith(?:out)?\\stime\\szone\\b)?\n\n\t\t\t\t# special case, captures 12, 13, 14i, 15\n\t\t\t\t|\\b(timestamp)(?:(s|tz))?\\b(?:\\((\\d+)\\))?(\\s(with|without)\\stime\\szone\\b)?\n\n\t\t\t" + }, + { + "match": "(?i:\\b((?:primary|foreign)\\s+key|references|on\\sdelete(\\s+cascade)?|check|constraint)\\b)", + "name": "storage.modifier.sql" + }, + { + "match": "\\b\\d+\\b", + "name": "constant.numeric.sql" + }, + { + "match": "(?i:\\b(select(\\s+distinct)?|insert\\s+(ignore\\s+)?into|update|delete|from|set|where|group\\sby|or|like|and|union(\\s+all)?|having|order\\sby|limit|(inner|cross)\\s+join|join|straight_join|(left|right)(\\s+outer)?\\s+join|natural(\\s+(left|right)(\\s+outer)?)?\\s+join)\\b)", + "name": "keyword.other.DML.sql" + }, + { + "match": "(?i:\\b(on|off|((is\\s+)?not\\s+)?null)\\b)", + "name": "keyword.other.DDL.create.II.sql" + }, + { + "match": "(?i:\\bvalues\\b)", + "name": "keyword.other.DML.II.sql" + }, + { + "match": "(?i:\\b(begin(\\s+work)?|start\\s+transaction|commit(\\s+work)?|rollback(\\s+work)?)\\b)", + "name": "keyword.other.LUW.sql" + }, + { + "match": "(?i:\\b(grant(\\swith\\sgrant\\soption)?|revoke)\\b)", + "name": "keyword.other.authorization.sql" + }, + { + "match": "(?i:\\bin\\b)", + "name": "keyword.other.data-integrity.sql" + }, + { + "match": "(?i:^\\s*(comment\\s+on\\s+(table|column|aggregate|constraint|database|domain|function|index|operator|rule|schema|sequence|trigger|type|view))\\s+.*?\\s+(is)\\s+)", + "name": "keyword.other.object-comments.sql" + }, + { + "match": "(?i)\\bAS\\b", + "name": "keyword.other.alias.sql" + }, + { + "match": "(?i)\\b(DESC|ASC)\\b", + "name": "keyword.other.order.sql" + }, + { + "match": "\\*", + "name": "keyword.operator.star.sql" + }, + { + "match": "[!<>]?=|<>|<|>", + "name": "keyword.operator.comparison.sql" + }, + { + "match": "-|\\+|/", + "name": "keyword.operator.math.sql" + }, + { + "match": "\\|\\|", + "name": "keyword.operator.concatenator.sql" + }, + { + "comment": "List of SQL99 built-in functions from http://www.oreilly.com/catalog/sqlnut/chapter/ch04.html", + "match": "(?i)\\b(CURRENT_(DATE|TIME(STAMP)?|USER)|(SESSION|SYSTEM)_USER)\\b", + "name": "support.function.scalar.sql" + }, + { + "comment": "List of SQL99 built-in functions from http://www.oreilly.com/catalog/sqlnut/chapter/ch04.html", + "match": "(?i)\\b(AVG|COUNT|MIN|MAX|SUM)(?=\\s*\\()", + "name": "support.function.aggregate.sql" + }, + { + "match": "(?i)\\b(CONCATENATE|CONVERT|LOWER|SUBSTRING|TRANSLATE|TRIM|UPPER)\\b", + "name": "support.function.string.sql" + }, + { + "captures": { + "1": { + "name": "constant.other.database-name.sql" + }, + "2": { + "name": "constant.other.table-name.sql" + } + }, + "match": "(\\w+?)\\.(\\w+)" + }, + { + "include": "#strings" + }, + { + "include": "#regexps" + }, + { + "captures": { + "1": { + "name": "punctuation.section.scope.begin.sql" + }, + "2": { + "name": "punctuation.section.scope.end.sql" + } + }, + "comment": "Allow for special ↩ behavior", + "match": "(\\()(\\))", + "name": "meta.block.sql" + } + ], + "repository": { + "comments": { + "patterns": [ + { + "begin": "(^[ \\t]+)?(?=--)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.sql" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "--", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.sql" + } + }, + "end": "\\n", + "name": "comment.line.double-dash.sql" + } + ] + }, + { + "begin": "(^[ \\t]+)?(?=#)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.sql" + } + }, + "end": "(?!\\G)", + "patterns": [] + }, + { + "begin": "/\\*", + "captures": { + "0": { + "name": "punctuation.definition.comment.sql" + } + }, + "end": "\\*/", + "name": "comment.block.c" + } + ] + }, + "regexps": { + "patterns": [ + { + "begin": "/(?=\\S.*/)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.sql" + } + }, + "end": "/", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.sql" + } + }, + "name": "string.regexp.sql", + "patterns": [ + { + "include": "#string_interpolation" + }, + { + "match": "\\\\/", + "name": "constant.character.escape.slash.sql" + } + ] + }, + { + "begin": "%r\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.sql" + } + }, + "comment": "We should probably handle nested bracket pairs!?! -- Allan", + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.sql" + } + }, + "name": "string.regexp.modr.sql", + "patterns": [ + { + "include": "#string_interpolation" + } + ] + } + ] + }, + "string_escape": { + "match": "\\\\.", + "name": "constant.character.escape.sql" + }, + "string_interpolation": { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.sql" + }, + "3": { + "name": "punctuation.definition.string.end.sql" + } + }, + "match": "(#\\{)([^\\}]*)(\\})", + "name": "string.interpolated.sql" + }, + "strings": { + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.sql" + }, + "2": { + "name": "punctuation.definition.string.end.sql" + } + }, + "comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.", + "match": "(')[^']*(')", + "name": "string.quoted.single.sql" + }, + { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.sql" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.sql" + } + }, + "name": "string.quoted.single.sql", + "patterns": [ + { + "include": "#string_escape" + } + ] + }, + { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.sql" + }, + "2": { + "name": "punctuation.definition.string.end.sql" + } + }, + "comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.", + "match": "(`)[^`\\\\]*(`)", + "name": "string.quoted.other.backtick.sql" + }, + { + "begin": "`", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.sql" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.sql" + } + }, + "name": "string.quoted.other.backtick.sql", + "patterns": [ + { + "include": "#string_escape" + } + ] + }, + { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.sql" + }, + "2": { + "name": "punctuation.definition.string.end.sql" + } + }, + "comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.", + "match": "(\")[^\"#]*(\")", + "name": "string.quoted.double.sql" + }, + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.sql" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.sql" + } + }, + "name": "string.quoted.double.sql", + "patterns": [ + { + "include": "#string_interpolation" + } + ] + }, + { + "begin": "%\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.sql" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.sql" + } + }, + "name": "string.other.quoted.brackets.sql", + "patterns": [ + { + "include": "#string_interpolation" + } + ] + } + ] + } + }, + "scopeName": "source.sql", + "uuid": "C49120AC-6ECC-11D9-ACC8-000D93589AF6" +} \ No newline at end of file diff --git a/extensions/sql/test/colorize-results/test_sql.json b/extensions/sql/test/colorize-results/test_sql.json index 7b133d4de64..a44b31e2461 100644 --- a/extensions/sql/test/colorize-results/test_sql.json +++ b/extensions/sql/test/colorize-results/test_sql.json @@ -1,7 +1,7 @@ [ { "c": "CREATE", - "t": "source.sql meta.create.sql keyword.other.create.sql", + "t": "source.sql keyword.other.sql", "r": { "dark_plus": "keyword: #569CD6", "light_plus": "keyword: #0000FF", @@ -11,51 +11,7 @@ } }, { - "c": " ", - "t": "source.sql meta.create.sql", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "VIEW", - "t": "source.sql meta.create.sql keyword.other.sql", - "r": { - "dark_plus": "keyword: #569CD6", - "light_plus": "keyword: #0000FF", - "dark_vs": "keyword: #569CD6", - "light_vs": "keyword: #0000FF", - "hc_black": "keyword: #569CD6" - } - }, - { - "c": " ", - "t": "source.sql meta.create.sql", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "METRIC_STATS", - "t": "source.sql meta.create.sql entity.name.function.sql", - "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "entity.name.function: #DCDCAA" - } - }, - { - "c": " (ID, MONTH, TEMP_C, RAIN_C) ", + "c": " VIEW METRIC_STATS (ID, MONTH, TEMP_C, RAIN_C) ", "t": "source.sql", "r": { "dark_plus": "default: #D4D4D4", diff --git a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json index 398853e9988..e090cc5f213 100644 --- a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json +++ b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json @@ -52,7 +52,10 @@ } }, { - "scope": ["meta.embedded", "source.groovy.embedded"], + "scope": [ + "meta.embedded", + "source.groovy.embedded" + ], "settings": { "background": "#1e1e1e", "foreground": "#C5C8C6" @@ -62,7 +65,7 @@ "name": "Comment", "scope": "comment", "settings": { - "fontStyle": "\n ", + "fontStyle": "", "foreground": "#9A9B99" } }, @@ -70,7 +73,7 @@ "name": "String", "scope": "string", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9AA83A" } }, @@ -78,7 +81,7 @@ "name": "String Embedded Source", "scope": "string source", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D08442" } }, @@ -86,7 +89,7 @@ "name": "Number", "scope": "constant.numeric", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -94,7 +97,7 @@ "name": "Built-in constant", "scope": "constant.language", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#408080" } }, @@ -102,7 +105,7 @@ "name": "User-defined constant", "scope": "constant.character, constant.other", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#8080FF", "background": "#1e1e1e" } @@ -111,7 +114,7 @@ "name": "Keyword", "scope": "keyword", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -119,7 +122,7 @@ "name": "Support", "scope": "support", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#C7444A" } }, @@ -127,7 +130,7 @@ "name": "Storage", "scope": "storage", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -135,7 +138,7 @@ "name": "Class name", "scope": "entity.name.class, entity.name.type", "settings": { - "fontStyle": "\n \t\t\t \t", + "fontStyle": "", "foreground": "#9B0000", "background": "#1E1E1E" } @@ -144,7 +147,7 @@ "name": "Inherited class", "scope": "entity.other.inherited-class", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#C7444A" } }, @@ -152,7 +155,7 @@ "name": "Function name", "scope": "entity.name.function", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#CE6700" } }, @@ -160,7 +163,7 @@ "name": "Function argument", "scope": "variable.parameter", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -168,7 +171,7 @@ "name": "Tag name", "scope": "entity.name.tag", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -176,7 +179,7 @@ "name": "Tag attribute", "scope": "entity.other.attribute-name", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -184,7 +187,7 @@ "name": "Library function", "scope": "support.function", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -192,7 +195,7 @@ "name": "Keyword", "scope": "keyword", "settings": { - "fontStyle": "\n \t\t\t\t", + "fontStyle": "", "foreground": "#676867" } }, @@ -200,7 +203,7 @@ "name": "Class Variable", "scope": "variable.other, variable.js, punctuation.separator.variable", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -208,7 +211,7 @@ "name": "Language Constant", "scope": "constant.language", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#FF0080" } }, @@ -216,7 +219,7 @@ "name": "Meta Brace", "scope": "punctuation.section.embedded -(source string source punctuation.section.embedded), meta.brace.erb.html", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#008200" } }, @@ -224,7 +227,7 @@ "name": "Invalid", "scope": "invalid", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#FF0B00" } }, @@ -232,7 +235,7 @@ "name": "Normal Variable", "scope": "variable.other.php, variable.other.normal", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -240,7 +243,7 @@ "name": "Function Object", "scope": "meta.function-call.object", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -248,7 +251,7 @@ "name": "Function Call Variable", "scope": "variable.other.property", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -256,7 +259,7 @@ "name": "Keyword Control", "scope": "keyword.control", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -264,7 +267,7 @@ "name": "Tag", "scope": "meta.tag", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D0B344" } }, @@ -272,7 +275,7 @@ "name": "Tag Name", "scope": "entity.name.tag", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -280,7 +283,7 @@ "name": "Doctype", "scope": "meta.doctype, meta.tag.sgml-declaration.doctype, meta.tag.sgml.doctype", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9AA83A" } }, @@ -288,7 +291,7 @@ "name": "Tag Inline Source", "scope": "meta.tag.inline source, text.html.php.source", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9AA83A" } }, @@ -296,7 +299,7 @@ "name": "Tag Other", "scope": "meta.tag.other, entity.name.tag.style, entity.name.tag.script, meta.tag.block.script, source.js.embedded punctuation.definition.tag.html, source.css.embedded punctuation.definition.tag.html", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -304,7 +307,7 @@ "name": "Tag Attribute", "scope": "entity.other.attribute-name, meta.tag punctuation.definition.string", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D0B344" } }, @@ -312,7 +315,7 @@ "name": "Tag Value", "scope": "meta.tag string -source -punctuation, text source text meta.tag string -punctuation", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -320,7 +323,7 @@ "name": "Meta Brace", "scope": "punctuation.section.embedded -(source string source punctuation.section.embedded), meta.brace.erb.html", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D0B344" } }, @@ -335,7 +338,7 @@ "name": "HTML String", "scope": "string.quoted.double.html, punctuation.definition.string.begin.html, punctuation.definition.string.end.html", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9AA83A" } }, @@ -343,7 +346,7 @@ "name": "HTML Tags", "scope": "punctuation.definition.tag.html, punctuation.definition.tag.begin, punctuation.definition.tag.end", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -351,7 +354,7 @@ "name": "CSS ID", "scope": "meta.selector.css entity.other.attribute-name.id", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -359,7 +362,7 @@ "name": "CSS Property Name", "scope": "support.type.property-name.css", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#676867" } }, @@ -367,7 +370,7 @@ "name": "CSS Property Value", "scope": "meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#C7444A" } }, @@ -401,7 +404,7 @@ "name": "PHP Function Call", "scope": "meta.function-call.object.php", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D0B344" } }, @@ -423,7 +426,7 @@ "name": "PHP Punctuation Embedded", "scope": "punctuation.section.embedded.begin.php, punctuation.section.embedded.end.php", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D08442" } }, @@ -431,7 +434,7 @@ "name": "Ruby Symbol", "scope": "constant.other.symbol.ruby", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9AA83A" } }, @@ -439,7 +442,7 @@ "name": "Ruby Variable", "scope": "variable.language.ruby", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D0B344" } }, @@ -447,7 +450,7 @@ "name": "Ruby Special Method", "scope": "keyword.other.special-method.ruby", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D9B700" } }, @@ -455,7 +458,8 @@ "name": "Ruby Embedded Source", "scope": [ "punctuation.section.embedded.begin.ruby", - "punctuation.section.embedded.end.ruby"], + "punctuation.section.embedded.end.ruby" + ], "settings": { "foreground": "#D08442" } @@ -464,7 +468,7 @@ "name": "SQL", "scope": "keyword.other.DML.sql", "settings": { - "fontStyle": "\n \t\t\t\t", + "fontStyle": "", "foreground": "#D0B344" } }, diff --git a/extensions/theme-monokai/themes/monokai-color-theme.json b/extensions/theme-monokai/themes/monokai-color-theme.json index a0b2897f19d..a1324d9ee01 100644 --- a/extensions/theme-monokai/themes/monokai-color-theme.json +++ b/extensions/theme-monokai/themes/monokai-color-theme.json @@ -19,7 +19,7 @@ "editor.foreground": "#f8f8f2", "selection.background": "#ccccc7", "editor.selectionHighlightBackground": "#665044cc", - "editor.selectionBackground": "#334444cc", + "editor.selectionBackground": "#334444cc", "editor.lineHighlightBackground": "#3e3d32", "editorCursor.foreground": "#f8f8f0", "editorWhitespace.foreground": "#464741", @@ -73,22 +73,22 @@ "peekViewResult.selectionBackground": "#414339", "peekViewResult.matchHighlightBackground": "#75715E", "peekViewEditor.matchHighlightBackground": "#75715E", - "terminal.ansiBlack": "#333333", - "terminal.ansiRed": "#C4265E", // the bright color with ~75% transparent on the background - "terminal.ansiGreen": "#86B42B", - "terminal.ansiYellow": "#B3B42B", - "terminal.ansiBlue": "#6A7EC8", - "terminal.ansiMagenta": "#8C6BC8", - "terminal.ansiCyan": "#56ADBC", - "terminal.ansiWhite": "#e3e3dd", - "terminal.ansiBrightBlack": "#666666", - "terminal.ansiBrightRed": "#f92672", - "terminal.ansiBrightGreen": "#A6E22E", - "terminal.ansiBrightYellow": "#e2e22e", // hue shifted #A6E22E - "terminal.ansiBrightBlue": "#819aff", // hue shifted #AE81FF - "terminal.ansiBrightMagenta": "#AE81FF", - "terminal.ansiBrightCyan": "#66D9EF", - "terminal.ansiBrightWhite": "#f8f8f2" + "terminal.ansiBlack": "#333333", + "terminal.ansiRed": "#C4265E", // the bright color with ~75% transparent on the background + "terminal.ansiGreen": "#86B42B", + "terminal.ansiYellow": "#B3B42B", + "terminal.ansiBlue": "#6A7EC8", + "terminal.ansiMagenta": "#8C6BC8", + "terminal.ansiCyan": "#56ADBC", + "terminal.ansiWhite": "#e3e3dd", + "terminal.ansiBrightBlack": "#666666", + "terminal.ansiBrightRed": "#f92672", + "terminal.ansiBrightGreen": "#A6E22E", + "terminal.ansiBrightYellow": "#e2e22e", // hue shifted #A6E22E + "terminal.ansiBrightBlue": "#819aff", // hue shifted #AE81FF + "terminal.ansiBrightMagenta": "#AE81FF", + "terminal.ansiBrightCyan": "#66D9EF", + "terminal.ansiBrightWhite": "#f8f8f2" }, "tokenColors": [ { @@ -98,7 +98,10 @@ } }, { - "scope": ["meta.embedded", "source.groovy.embedded"], + "scope": [ + "meta.embedded", + "source.groovy.embedded" + ], "settings": { "background": "#272822", "foreground": "#F8F8F2" @@ -408,4 +411,4 @@ } } ] -} +} \ No newline at end of file diff --git a/extensions/theme-quietlight/themes/quietlight-color-theme.json b/extensions/theme-quietlight/themes/quietlight-color-theme.json index 9fd5ad62cee..fc9e8f7db2c 100644 --- a/extensions/theme-quietlight/themes/quietlight-color-theme.json +++ b/extensions/theme-quietlight/themes/quietlight-color-theme.json @@ -8,7 +8,10 @@ } }, { - "scope": ["meta.embedded", "source.groovy.embedded"], + "scope": [ + "meta.embedded", + "source.groovy.embedded" + ], "settings": { "background": "#F5F5F5", "foreground": "#333333" @@ -491,8 +494,8 @@ "statusBar.background": "#705697", "statusBar.noFolderBackground": "#705697", "statusBar.debuggingBackground": "#705697", - "activityBar.background": "#EDEDF5", - "activityBar.foreground": "#705697", + "activityBar.background": "#EDEDF5", + "activityBar.foreground": "#705697", "activityBarBadge.background": "#705697", "titleBar.activeBackground": "#c4b7d7", "button.background": "#705697", diff --git a/extensions/theme-red/themes/Red-color-theme.json b/extensions/theme-red/themes/Red-color-theme.json index df3b63b3792..6c964e506d5 100644 --- a/extensions/theme-red/themes/Red-color-theme.json +++ b/extensions/theme-red/themes/Red-color-theme.json @@ -69,7 +69,10 @@ } }, { - "scope": ["meta.embedded", "source.groovy.embedded"], + "scope": [ + "meta.embedded", + "source.groovy.embedded" + ], "settings": { "background": "#390000", "foreground": "#F8F8F8" diff --git a/extensions/typescript/src/features/codeActionProvider.ts b/extensions/typescript/src/features/codeActionProvider.ts index 32f50fef59f..80773371264 100644 --- a/extensions/typescript/src/features/codeActionProvider.ts +++ b/extensions/typescript/src/features/codeActionProvider.ts @@ -3,12 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, workspace, WorkspaceEdit } from 'vscode'; +import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -import { tsTextSpanToVsRange, vsRangeToTsFileRange } from '../utils/convert'; +import { vsRangeToTsFileRange } from '../utils/convert'; import FormattingConfigurationManager from './formattingConfigurationManager'; +import { applyCodeAction } from '../utils/codeAction'; interface NumberSet { [key: number]: boolean; @@ -55,7 +56,7 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider errorCodes: Array.from(supportedActions) }; const response = await this.client.execute('getCodeFixes', args, token); - return (response.body || []).map(action => this.getCommandForAction(action)); + return (response.body || []).map(action => this.getCommandForAction(action, file)); } private get supportedCodeActions(): Thenable { @@ -72,31 +73,22 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider return this._supportedCodeActions; } - private getSupportedActionsForContext(context: CodeActionContext): Thenable> { - return this.supportedCodeActions.then(supportedActions => - new Set(context.diagnostics - .map(diagnostic => +diagnostic.code) - .filter(code => supportedActions[code]))); + private async getSupportedActionsForContext(context: CodeActionContext): Promise> { + const supportedActions = await this.supportedCodeActions; + return new Set(context.diagnostics + .map(diagnostic => +diagnostic.code) + .filter(code => supportedActions[code])); } - private getCommandForAction(action: Proto.CodeAction): Command { + private getCommandForAction(action: Proto.CodeAction, file: string): Command { return { title: action.description, command: this.commandId, - arguments: [action] + arguments: [action, file] }; } - private async onCodeAction(action: Proto.CodeAction): Promise { - const workspaceEdit = new WorkspaceEdit(); - for (const change of action.changes) { - for (const textChange of change.textChanges) { - workspaceEdit.replace(this.client.asUrl(change.fileName), - tsTextSpanToVsRange(textChange), - textChange.newText); - } - } - - return workspace.applyEdit(workspaceEdit); + private onCodeAction(action: Proto.CodeAction, file: string): Promise { + return applyCodeAction(this.client, action, file); } } \ No newline at end of file diff --git a/extensions/typescript/src/features/completionItemProvider.ts b/extensions/typescript/src/features/completionItemProvider.ts index f4e46e19cee..2036add07d1 100644 --- a/extensions/typescript/src/features/completionItemProvider.ts +++ b/extensions/typescript/src/features/completionItemProvider.ts @@ -3,17 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CompletionItem, TextDocument, Position, CompletionItemKind, CompletionItemProvider, CancellationToken, TextEdit, Range, SnippetString, workspace, ProviderResult, CompletionContext } from 'vscode'; +import { CompletionItem, TextDocument, Position, CompletionItemKind, CompletionItemProvider, CancellationToken, TextEdit, Range, SnippetString, workspace, ProviderResult, CompletionContext, commands } from 'vscode'; import { ITypescriptServiceClient } from '../typescriptService'; import TypingsStatus from '../utils/typingsStatus'; import * as PConst from '../protocol.const'; -import { CompletionEntry, CompletionsRequestArgs, CompletionDetailsRequestArgs, CompletionEntryDetails } from '../protocol'; +import { CompletionEntry, CompletionsRequestArgs, CompletionDetailsRequestArgs, CompletionEntryDetails, CodeAction } from '../protocol'; import * as Previewer from './previewer'; import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; import * as nls from 'vscode-nls'; +import { applyCodeAction } from '../utils/codeAction'; let localize = nls.loadMessageBundle(); class MyCompletionItem extends CompletionItem { @@ -132,6 +133,7 @@ namespace Configuration { } export default class TypeScriptCompletionItemProvider implements CompletionItemProvider { + private readonly commandId: string; private config: Configuration = { useCodeSnippetsOnMethodSuggest: false, @@ -141,8 +143,12 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP constructor( private client: ITypescriptServiceClient, + mode: string, private typingsStatus: TypingsStatus - ) { } + ) { + this.commandId = `_typescript.applyCompletionCodeAction.${mode}`; + commands.registerCommand(this.commandId, this.applyCompletionCodeAction, this); + } public updateConfiguration(): void { // Use shared setting for js and ts @@ -277,9 +283,16 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP } const detail = details[0]; item.detail = Previewer.plain(detail.displayParts); - item.documentation = Previewer.markdownDocumentation(detail.documentation, detail.tags); + if (detail.codeActions && detail.codeActions.length) { + item.command = { + title: '', + command: this.commandId, + arguments: [filepath, detail.codeActions] + }; + } + if (detail && this.config.useCodeSnippetsOnMethodSuggest && (item.kind === CompletionItemKind.Function || item.kind === CompletionItemKind.Method)) { return this.isValidFunctionCompletionContext(filepath, item.position).then(shouldCompleteFunction => { if (shouldCompleteFunction) { @@ -341,4 +354,13 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP return new SnippetString(codeSnippet); } + + private async applyCompletionCodeAction(file: string, codeActions: CodeAction[]): Promise { + for (const action of codeActions) { + if (!(await applyCodeAction(this.client, action, file))) { + return false; + } + } + return true; + } } diff --git a/extensions/typescript/src/features/refactorProvider.ts b/extensions/typescript/src/features/refactorProvider.ts index a17533f4b4b..8b5094ce228 100644 --- a/extensions/typescript/src/features/refactorProvider.ts +++ b/extensions/typescript/src/features/refactorProvider.ts @@ -52,6 +52,11 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { const actions: Command[] = []; for (const info of response.body) { + // Workaround for https://github.com/Microsoft/TypeScript/issues/19378 + if (info.name.startsWith('Install missing ')) { + continue; + } + if (info.inlineable === false) { actions.push({ title: info.description, diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index 99e6f08e734..b7f99cb8024 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -239,7 +239,7 @@ class LanguageProvider { const selector = this.description.modeIds; const config = workspace.getConfiguration(this.id); - const completionItemProvider = new (await import('./features/completionItemProvider')).default(client, this.typingsStatus); + const completionItemProvider = new (await import('./features/completionItemProvider')).default(client, this.description.id, this.typingsStatus); completionItemProvider.updateConfiguration(); this.toUpdateOnConfigurationChanged.push(completionItemProvider); this.disposables.push(languages.registerCompletionItemProvider(selector, completionItemProvider, '.', '"', '\'', '/', '@')); diff --git a/extensions/typescript/src/typescriptService.ts b/extensions/typescript/src/typescriptService.ts index bf4067894ef..bf367883cb5 100644 --- a/extensions/typescript/src/typescriptService.ts +++ b/extensions/typescript/src/typescriptService.ts @@ -66,6 +66,7 @@ export interface ITypescriptServiceClient { execute(command: 'docCommentTemplate', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise; execute(command: 'getApplicableRefactors', args: Proto.GetApplicableRefactorsRequestArgs, token?: CancellationToken): Promise; execute(command: 'getEditsForRefactor', args: Proto.GetEditsForRefactorRequestArgs, token?: CancellationToken): Promise; + execute(command: 'applyCodeActionCommand', args: Proto.ApplyCodeActionCommandRequestArgs, token?: CancellationToken): Promise; // execute(command: 'compileOnSaveAffectedFileList', args: Proto.CompileOnSaveEmitFileRequestArgs, token?: CancellationToken): Promise; // execute(command: 'compileOnSaveEmitFile', args: Proto.CompileOnSaveEmitFileRequestArgs, token?: CancellationToken): Promise; execute(command: string, args: any, expectedResult: boolean | CancellationToken, token?: CancellationToken): Promise; diff --git a/extensions/typescript/src/typescriptServiceClient.ts b/extensions/typescript/src/typescriptServiceClient.ts index 8163808609d..3224a1f64b5 100644 --- a/extensions/typescript/src/typescriptServiceClient.ts +++ b/extensions/typescript/src/typescriptServiceClient.ts @@ -231,6 +231,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient if (this.servicePromise) { this.servicePromise = this.servicePromise.then(cp => { if (cp) { + this.info('Killing TS Server'); this.isRestarting = true; cp.kill(); } @@ -401,7 +402,10 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient this.logTelemetry('error', { message: err.message }); return; } + + this.info('Started TSServer'); this.lastStart = Date.now(); + childProcess.on('error', (err: Error) => { this.lastError = err; this.error('TSServer errored with error.', err); @@ -416,7 +420,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient }); childProcess.on('exit', (code: any) => { if (code === null || typeof code === 'undefined') { - this.info(`TSServer exited`); + this.info('TSServer exited'); } else { this.error(`TSServer exited with code: ${code}`); /* __GDPR__ diff --git a/extensions/typescript/src/utils/codeAction.ts b/extensions/typescript/src/utils/codeAction.ts new file mode 100644 index 00000000000..c975a4ef9f2 --- /dev/null +++ b/extensions/typescript/src/utils/codeAction.ts @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { WorkspaceEdit, workspace } from 'vscode'; +import * as Proto from '../protocol'; +import { tsTextSpanToVsRange } from './convert'; +import { ITypescriptServiceClient } from '../typescriptService'; + + +export async function applyCodeAction( + client: ITypescriptServiceClient, + action: Proto.CodeAction, + file: string +): Promise { + if (action.changes && action.changes.length) { + const workspaceEdit = new WorkspaceEdit(); + for (const change of action.changes) { + for (const textChange of change.textChanges) { + workspaceEdit.replace(client.asUrl(change.fileName), + tsTextSpanToVsRange(textChange), + textChange.newText); + } + } + + if (!(await workspace.applyEdit(workspaceEdit))) { + return false; + } + } + + if (action.commands && action.commands.length) { + for (const command of action.commands) { + const response = await client.execute('applyCodeActionCommand', { file, command }); + if (!response || !response.body) { + return false; + } + } + } + return true; +} \ No newline at end of file diff --git a/extensions/typescript/syntaxes/Readme.md b/extensions/typescript/syntaxes/Readme.md index d45fc854245..3e1cf32a0e2 100644 --- a/extensions/typescript/syntaxes/Readme.md +++ b/extensions/typescript/syntaxes/Readme.md @@ -7,10 +7,10 @@ To update to the latest version: Migration notes and todos: - differentiate variable and function declarations from references - - I suggest we use a new scope segment 'function-call' to sigmal a function references, and 'definition' to the declaration. Alternative is to use 'support.function' everywhere. + - I suggest we use a new scope segment 'function-call' to signal a function reference, and 'definition' to the declaration. An alternative is to use 'support.function' everywhere. - I suggest we use a new scope segment 'definition' to the variable declarations. Haven't yet found a scope for references that other grammars use. - rename scope to return.type to return-type, which is already used in other grammars - rename entity.name.class to entity.name.type.class which is used in all other grammars I've seen -- do we really want to have the list of all the 'library' types (Math, Dom...). It adds a lot of size to the grammar, lots of special rules and is not really correct as it depends on the JavaScript runtime which types are present. \ No newline at end of file +- do we really want to have the list of all the 'library' types (Math, Dom...). It adds a lot of size to the grammar, lots of special rules and is not really correct as it depends on the JavaScript runtime which types are present. diff --git a/i18n/chs/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/chs/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index f1f362da927..4b77210ee8f 100644 --- a/i18n/chs/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/chs/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "例如 myFile.txt", - "activeEditorMedium": "例如 myFolder/myFile.txt", - "activeEditorLong": "例如 /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "例如 myFolder1、myFolder2、myFolder3", - "rootPath": "例如 /Users/Development/myProject", - "folderName": "例如 myFolder", - "folderPath": "例如 /Users/Development/myFolder", + "activeEditorShort": "文件名 (例如 myFile.txt)", + "activeEditorMedium": "相对于工作区文件夹的文件路径 (例如 myFolder/myFile.txt)", + "activeEditorLong": "文件的完整路径 (例如 /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "工作区名称 (例如 myFolder 或 myWorkspace)", + "rootPath": "工作区路径 (例如 /Users/Development/myWorkspace)", + "folderName": "文件所在工作区文件夹的名称 (例如 myFolder)", + "folderPath": "文件所在工作区文件夹的路径 (例如 /Users/Development/myFolder)", "appName": "例如 VS Code", "dirty": "一个更新的指示器,指示活动编辑器是否更新", "separator": "一个条件分隔符(\"-\"),仅在左右是具有值的变量时才显示", diff --git a/i18n/chs/extensions/emmet/package.i18n.json b/i18n/chs/extensions/emmet/package.i18n.json index fe933ada874..f5fda686eff 100644 --- a/i18n/chs/extensions/emmet/package.i18n.json +++ b/i18n/chs/extensions/emmet/package.i18n.json @@ -28,13 +28,6 @@ "command.incrementNumberByTen": "增加 10", "command.decrementNumberByTen": "减少 10", "emmetSyntaxProfiles": "为指定的语法定义配置文件或使用带有特定规则的配置文件。", - "emmetExclude": "不应展开 Emmet 缩写的语言数组。", - "emmetExtensionsPath": "含有 Emmet 配置文件和片段的文件夹路径。", - "emmetShowExpandedAbbreviation": "显示扩展的 Emmet 缩写作为建议。\n\"inMarkupAndStylesheetFilesOnly\" 选项适用于 html、haml、jade、slim、xml、xsl、css、scss、sass、less 和 stylus。\n\"always\" 选项适用于 markup/css 文件的所有部分。", - "emmetShowAbbreviationSuggestions": "显示可能的 Emmet 缩写作为建议。在风格表中或将 emmet.showExpandedAbbreviation 设置为 \"never\" 时不适用。", - "emmetIncludeLanguages": "启用使用默认不支持的语言的 Emmet 缩写。在此添加该语言与支持 Emmet 的语言之间的映射。示例: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", - "emmetVariables": "要用于 Emmet 代码片段的变量", - "emmetTriggerExpansionOnTab": "启用后,按 TAB 键时,将展开 Emmet 缩写。", "emmetPreferences": "用于修改 Emmet 某些操作和解析程序的行为的首选项。", "emmetPreferencesIntUnit": "整数值的默认单位", "emmetPreferencesFloatUnit": "浮点数值的默认单位", @@ -44,5 +37,7 @@ "emmetPreferencesCssBetween": "展开 CSS 缩写时在 CSS 属性之间放置的符号", "emmetPreferencesSassBetween": "在 Sass 文件中展开 CSS 缩写时在 CSS 属性之间放置的符号", "emmetPreferencesStylusBetween": "在 Stylus 文件中展开 CSS 缩写时在 CSS 属性之间放置的符号", - "emmetShowSuggestionsAsSnippets": "若为 \"true\",Emmet 建议将会显示为代码片段,根据editor.snippetSuggestions 设置进行排列。" + "emmetPreferencesFilterCommentBefore": "使用注释过滤器时,应置于匹配元素前注释的定义。", + "emmetPreferencesFilterCommentAfter": "使用注释过滤器时,应置于匹配元素后注释的定义。", + "emmetPreferencesFilterCommentTrigger": "用半角逗号 (\",\") 隔开的属性名缩写的数组,将由注释筛选器应用" } \ No newline at end of file diff --git a/i18n/chs/extensions/git/out/commands.i18n.json b/i18n/chs/extensions/git/out/commands.i18n.json index 5b826945eab..c28138c3ddb 100644 --- a/i18n/chs/extensions/git/out/commands.i18n.json +++ b/i18n/chs/extensions/git/out/commands.i18n.json @@ -12,8 +12,9 @@ "cloning": "正在克隆 GIT 存储库...", "openrepo": "打开存储库", "proposeopen": "是否要打开已克隆存储库?", - "path to init": "文件夹路径", - "provide path": "请提供用于初始化 Git 存储库的文件夹路径", + "init repo": "初始化存储库", + "create repo": "初始化存储库", + "are you sure": "将在“{0}”中创建 Git 存储库。确定要继续吗?", "HEAD not available": "“{0}”的 HEAD 版本不可用。", "confirm stage files with merge conflicts": "确定要暂存含有合并冲突的 {0} 个文件吗?", "confirm stage file with merge conflicts": "确定要暂存含有合并冲突的 {0} 吗?", @@ -60,7 +61,7 @@ "push with tags success": "已成功带标签进行推送。", "nobranch": "请签出一个分支以推送到远程。", "pick remote": "选取要将分支“{0}”发布到的远程:", - "sync is unpredictable": "此操作从“{0}”推送和拉取提交。", + "sync is unpredictable": "此操作将推送提交至“{0}”,并从中拉取提交。", "ok": "确定", "never again": "好,永不再显示", "no remotes to publish": "存储库未配置任何要发布到的远程存储库。", diff --git a/i18n/chs/extensions/git/out/repository.i18n.json b/i18n/chs/extensions/git/out/repository.i18n.json index 8b700b3abe3..130408fe060 100644 --- a/i18n/chs/extensions/git/out/repository.i18n.json +++ b/i18n/chs/extensions/git/out/repository.i18n.json @@ -21,6 +21,8 @@ "deleted by us": "已被我们删除", "both added": "两者均已添加", "both modified": "二者均已修改", + "untracked, short": "U", + "modified, short": "M", "commit": "提交", "merge changes": "合并更改", "staged changes": "暂存的更改", diff --git a/i18n/chs/extensions/git/package.i18n.json b/i18n/chs/extensions/git/package.i18n.json index 35849ac0289..319483d9eeb 100644 --- a/i18n/chs/extensions/git/package.i18n.json +++ b/i18n/chs/extensions/git/package.i18n.json @@ -15,6 +15,8 @@ "command.stageAll": "暂存所有更改", "command.stageSelectedRanges": "暂存所选范围", "command.revertSelectedRanges": "还原所选更改", + "command.stageChange": "暂存更改", + "command.revertChange": "还原更改", "command.unstage": "取消暂存更改", "command.unstageAll": "取消暂存所有更改", "command.unstageSelectedRanges": "取消暂存所选范围", @@ -53,11 +55,11 @@ "config.enableLongCommitWarning": "是否针对长段提交消息进行警告", "config.confirmSync": "同步 Git 存储库前进行确认", "config.countBadge": "控制 Git 徽章计数器。“all”计算所有更改。“tracked”只计算跟踪的更改。“off”关闭此功能。", - "config.checkoutType": "控制运行“签出到...”时列出的分支的类型。“all”显示所有 refs,“local”只显示本地分支,“tags”只显示标签,“remote”只显示远程分支。", + "config.checkoutType": "控制运行“签出到...”命令时列出的分支的类型。\"all\" 显示所有 refs,\"local\" 只显示本地分支,\"tags\" 只显示标记,\"remote\" 只显示远程分支。", "config.ignoreLegacyWarning": "忽略旧版 Git 警告", "config.ignoreLimitWarning": "忽略“存储库中存在大量更改”的警告", "config.defaultCloneDirectory": "克隆 Git 存储库的默认位置", "config.enableSmartCommit": "在没有暂存的更改时提交所有更改。", "config.enableCommitSigning": "启用使用 GPG 签名的提交", - "config.discardAllScope": "控制运行\"放弃所有更改\"命令时放弃的更改。\"all\" 放弃所有更改。 \"tracked\" 只放弃跟踪的文件。 \"prompt\" 每次运行此操作时显示提示对话框。" + "config.discardAllScope": "控制运行“放弃所有更改”命令时放弃的更改类型。\"all\" 放弃所有更改。\"tracked\" 只放弃跟踪的文件。\"prompt\" 表示在每次运行此操作时显示提示对话框。" } \ No newline at end of file diff --git a/i18n/chs/extensions/typescript/package.i18n.json b/i18n/chs/extensions/typescript/package.i18n.json index 03246f64123..2fcc5d4f672 100644 --- a/i18n/chs/extensions/typescript/package.i18n.json +++ b/i18n/chs/extensions/typescript/package.i18n.json @@ -44,7 +44,8 @@ "typescript.npm": "指定用于自动获取类型的 NPM 可执行文件的路径。要求 TypeScript >= 2.3.4。", "typescript.check.npmIsInstalled": "检查是否安装了 NPM 以自动获取类型。", "javascript.nameSuggestions": "启用/禁用在 JavaScript 建议列表中包含文件中的唯一名称。", - "typescript.tsc.autoDetect": "控制自动检测 tsc 任务是否打开。", + "typescript.tsc.autoDetect": "控制 tsc 任务的自动检测。\"off\" 关闭此功能。\"build\" 仅创建单次运行编译任务。\"watch\" 仅创建编译及监视任务。\"on\" 创建构建及监视任务。默认值为 \"on\"。", "typescript.problemMatchers.tsc.label": "TypeScript 问题", - "typescript.problemMatchers.tscWatch.label": "TypeScript 问题(观看模式)" + "typescript.problemMatchers.tscWatch.label": "TypeScript 问题(观看模式)", + "typescript.quickSuggestionsForPaths": "当输入导入路径时启用或禁用快速建议。" } \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/chs/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 214239c0607..8cd6a9a0ef4 100644 --- a/i18n/chs/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/chs/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,6 @@ "label.replaceButton": "替换", "label.replaceAllButton": "全部替换", "label.toggleReplaceButton": "切换替换模式", - "title.matchesCountLimit": "仅前 999 个结果突出显示,但所有查找操作均针对整个文本。", "label.matchesLocation": "第 {0} 个(共 {1} 个)", "label.noResults": "无结果" } \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/chs/src/vs/editor/contrib/find/common/findController.i18n.json index 8f77be77375..385ba32bfeb 100644 --- a/i18n/chs/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/chs/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "查找下一个选择", "previousSelectionMatchFindAction": "查找上一个选择", "startReplace": "替换", - "addSelectionToNextFindMatch": "将选择添加到下一个查找匹配项", - "addSelectionToPreviousFindMatch": "将选择内容添加到上一查找匹配项", - "moveSelectionToNextFindMatch": "将上次选择移动到下一个查找匹配项", - "moveSelectionToPreviousFindMatch": "将上个选择内容移动到上一查找匹配项", - "selectAllOccurrencesOfFindMatch": "选择所有找到的查找匹配项", - "changeAll.label": "更改所有匹配项", "showNextFindTermAction": "显示下一个搜索结果", "showPreviousFindTermAction": "显示上一个搜索结果" } \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/chs/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 88bbf6c3a12..3c402b850dd 100644 --- a/i18n/chs/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/chs/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "在上面添加光标", "mutlicursor.insertBelow": "在下面添加光标", - "mutlicursor.insertAtEndOfEachLineSelected": "在行尾添加光标" + "mutlicursor.insertAtEndOfEachLineSelected": "在行尾添加光标", + "addSelectionToNextFindMatch": "将选择添加到下一个查找匹配项", + "addSelectionToPreviousFindMatch": "将选择内容添加到上一查找匹配项", + "moveSelectionToNextFindMatch": "将上次选择移动到下一个查找匹配项", + "moveSelectionToPreviousFindMatch": "将上个选择内容移动到上一查找匹配项", + "selectAllOccurrencesOfFindMatch": "选择所有找到的查找匹配项", + "changeAll.label": "更改所有匹配项" } \ No newline at end of file diff --git a/i18n/chs/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/chs/src/vs/platform/theme/common/colorRegistry.i18n.json index 0784d4fbc11..6f4c25c20dd 100644 --- a/i18n/chs/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/chs/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "颜色格式无效。请使用 #RGB、#RGBA、#RRGGBB 或 #RRGGBBAA", "schema.colors": "工作台中使用的颜色。", "foreground": "整体前景色。此颜色仅在不被组件覆盖时适用。", "errorForeground": "错误信息的整体前景色。此颜色仅在不被组件覆盖时适用。", diff --git a/i18n/chs/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/chs/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 47a9c28f390..16082cd725c 100644 --- a/i18n/chs/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -9,14 +9,17 @@ "addFolderToWorkspace": "将文件夹添加到工作区...", "add": "添加(&&A)", "addFolderToWorkspaceTitle": "将文件夹添加到工作区", + "globalRemoveFolderFromWorkspace": "将文件夹从工作区删除…", "newWorkspace": "新建工作区...", "select": "选择(&&S)", "selectWorkspace": "选择文件夹作为工作区", "removeFolderFromWorkspace": "将文件夹从工作区删除", + "openFolderSettings": "打开文件夹设置", "saveWorkspaceAsAction": "将工作区另存为...", "save": "保存(&&S)", "saveWorkspace": "保存工作区", "openWorkspaceAction": "打开工作区...", "openWorkspaceConfigFile": "打开工作区配置文件", + "openFolderAsWorkspaceInNewWindow": "在新窗口中将文件夹作为工作区打开", "workspaceFolderPickerPlaceholder": "选择工作区文件夹" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index 9b17b8e6572..ab430ed5a0d 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "隐藏活动栏", - "activityBarAriaLabel": "活动视图切换器", "globalActions": "全局动作" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..738f1c78726 --- /dev/null +++ b/i18n/chs/src/vs/workbench/browser/parts/compositebar/compositeBar.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. +{ + "activityBarAriaLabel": "活动视图切换器" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..bcd8d15ce40 --- /dev/null +++ b/i18n/chs/src/vs/workbench/browser/parts/compositebar/compositeBarActions.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. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "其他视图", + "numberBadge": "{0} ({1})", + "manageExtension": "管理扩展", + "titleKeybinding": "{0} ({1})", + "hide": "隐藏", + "toggle": "切换已固定的视图" +} \ 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 96695e518e9..a2f0727f579 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 @@ -12,5 +12,6 @@ "groupTwoPicker": "在第二组中显示编辑器", "groupThreePicker": "在第三组中显示编辑器", "allEditorsPicker": "显示所有已打开的编辑器", - "view": "查看" + "view": "查看", + "file": "文件" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 11e4c9243b7..fbfbe4e5483 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "命令“{0}”当前未启用,无法运行。", "manageExtension": "管理扩展" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/chs/src/vs/workbench/electron-browser/main.contribution.i18n.json index b2ac4ce4c5a..dd88bf14419 100644 --- a/i18n/chs/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,18 +10,15 @@ "workspaces": "工作区", "developer": "开发者", "showEditorTabs": "控制打开的编辑器是否显示在选项卡中。", - "workbench.editor.labelFormat.default": "显示文件名。当启用选项卡且在同一组内有两个相同名称的文件时,将添加每个文件路径中可以用于区分的部分。在选项卡被禁用且编辑器活动时,将显示相对于工作区根目录的路径。", "workbench.editor.labelFormat.short": "在文件的目录名之后显示文件名。", - "workbench.editor.labelFormat.medium": "在文件相对当前工作空间根的路径之后显示文件名。", "workbench.editor.labelFormat.long": "在文件的绝对路径之后显示文件名。", "tabDescription": "控制编辑器标签的格式。修改这项设置会让文件的路径更容易理解:\n- short: \"parent\"\n- medium: \"workspace/src/parent\"\n- long: \"/home/user/workspace/src/parent\"\n- default: 当与另一选项卡标题相同时为 \".../parent\"。选项卡被禁用时则为相对工作区路径", "editorTabCloseButton": "控制编辑器的选项卡关闭按钮的位置,或当设置为 \"off\" 时禁用关闭它们。", "showIcons": "控制打开的编辑器是否随图标一起显示。这还需启用图标主题。", "enablePreview": "控制是否将打开的编辑器显示为预览。预览编辑器将会重用至其被保留(例如,通过双击或编辑),且其字体样式将为斜体。", "enablePreviewFromQuickOpen": "控制 Quick Open 中打开的编辑器是否显示为预览。预览编辑器可以重新使用,直到将其保留(例如,通过双击或编辑)。", - "editorOpenPositioning": "控制打开编辑器的位置。选择“左侧”或“右侧”以在当前活动位置的左侧或右侧打开编辑器。选择“第一个”或“最后一个”以从当前活动位置独立打开编辑器。", "revealIfOpen": "控制打开时编辑器是否显示在任何可见组中。如果禁用,编辑器会优先在当前活动编辑器组中打开。如果启用,会显示已打开的编辑器而不是在当前活动编辑器组中再次打开。请注意,有些情况下会忽略此设置,例如强制编辑器在特定组中或在当前活动组的边侧打开时。", - "commandHistory": "控制命令面板中保留最近使用命令的数量。设置为 0 则禁用命令历史记录。", + "commandHistory": "控制命令面板中保留最近使用命令的数量。设置为 0 时禁用命令历史功能。", "preserveInput": "控制是否在再次打开命令面板时恢复上一次的输入内容。", "closeOnFocusLost": "控制 Quick Open 是否应在失去焦点时自动关闭。", "openDefaultSettings": "控制打开设置时是否打开显示所有默认设置的编辑器。", @@ -50,7 +47,7 @@ "restoreWindows": "控制重启后重新打开窗口的方式。选择 \"none\" 则永远在启动时打开一个空工作区,\"one\" 则重新打开最后使用的窗口,\"folders\" 则重新打开所有含有文件夹的窗口,\"all\" 则重新打开上次会话的所有窗口。", "restoreFullscreen": "如果窗口已退出全屏模式,控制其是否应还原为全屏模式。", "zoomLevel": "调整窗口的缩放级别。原始大小是 0,每次递增(例如 1)或递减(例如 -1)表示放大或缩小 20%。也可以输入小数以便以更精细的粒度调整缩放级别。", - "title": "基于活动编辑器控制窗口标题。变量基于上下文进行替换:\n${activeEditorShort}: 例如 myFile.txt\n${activeEditorMedium}: 例如 myFolder/myFile.txt\n${activeEditorLong}: 例如 /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: 例如 myFolder\n${folderPath}: 例如 /Users/Development/myFolder\n${rootName}: 例如 myFolder1, myFolder2, myFolder3\n${rootPath}: 例如 /Users/Development/myWorkspace\n${appName}: 例如 VS Code\n${dirty}: 更新的指示器(如果活动编辑器已更新)\n${separator}: 仅在被带值的变量包围时显示的条件分隔符(\" - \")", + "title": "根据活动编辑器控制窗口标题。变量基于上下文进行替换:\n${activeEditorShort}: 文件名 (如 myFile.txt)\n${activeEditorMedium}: 相对于工作区文件夹的文件路径 (如 myFolder/myFile.txt)\n${activeEditorLong}: 文件的完整路径 (如 /Users/Development/myProject/myFolder/myFile.txt)\n${folderName}: 文件所在工作区文件夹名称 (如 myFolder)\n${folderPath}: 文件所在工作区文件夹路径 (如 /Users/Development/myFolder)\n${rootName}: 工作区名称 (如 myFolder 或 myWorkspace)\n${rootPath}: 工作区路径 (如 /Users/Development/myWorkspace)\n${appName}: 如 VS Code\n${dirty}: 活动编辑器有更新时显示的更新指示器\n${separator}: 仅在被有值变量包围时显示的分隔符 (\" - \")", "window.newWindowDimensions.default": "在屏幕中心打开新窗口。", "window.newWindowDimensions.inherit": "以与上一个活动窗口相同的尺寸打开新窗口。", "window.newWindowDimensions.maximized": "打开最大化的新窗口。", diff --git a/i18n/chs/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 1b158fedfe7..6c03799a8b6 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0},调试", "debugAriaLabel": "键入启动配置的名称以运行。", + "addConfigTo": "添加配置 ({0})...", + "addConfiguration": "添加配置...", "noConfigurationsMatching": "无任何调试配置匹配", "noConfigurationsFound": "找不到任何调试配置。请创建一个 \"launch.json\" 文件。" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..d8dee095caa --- /dev/null +++ b/i18n/chs/src/vs/workbench/parts/debug/browser/debugStatus.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. +{ + "debug": "调试" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..fcbe0434d7e --- /dev/null +++ b/i18n/chs/src/vs/workbench/parts/debug/browser/debugViewlet.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. +{ + "debugFocusVariablesView": "聚焦于变量视图", + "debugFocusWatchView": "聚焦于监视视图", + "debugFocusCallStackView": "聚焦于调用堆栈视图", + "debugFocusBreakpointsView": "聚焦于断点视图" +} \ No newline at end of file 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 327f1b6fd82..fd6211c4e06 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 @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "用于生成初始 \"launch.json\" 的配置。", "vscode.extension.contributes.debuggers.languages": "可能被视为“默认调试程序”的调试扩展的语言列表。", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "如果指定的 VS Code 将调用此命令以确定调试适配器的可执行路径和要传递的参数。", - "vscode.extension.contributes.debuggers.startSessionCommand": "如果指定的 VS Code 将为针对此扩展的“调试”或“运行”操作调用此命令。", "vscode.extension.contributes.debuggers.configurationSnippets": "用于在 \"launch.json\" 中添加新配置的代码段。", "vscode.extension.contributes.debuggers.configurationAttributes": "用于验证 \"launch.json\" 的 JSON 架构配置。", "vscode.extension.contributes.debuggers.windows": "Windows 特定的设置。", diff --git a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 0a2caf6c161..8a42e364b44 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,8 +12,8 @@ "breakpointRemoved": "已删除断点,行 {0},文件 {1}", "compoundMustHaveConfigurations": "复合项必须拥有 \"configurations\" 属性集,才能启动多个配置。", "configMissing": "\"launch.json\" 中缺少配置“{0}”。", - "debugRequestNotSupported": "所选的调试配置有一个不支持的属性值“{0}”: “{1}”。", - "debugRequesMissing": "所选的调试配置缺少属性“{0}”。", + "debugRequestNotSupported": "所选调试配置的属性“{0}”的值“{1}”不受支持。", + "debugRequesMissing": "在所选的调试配置中缺少属性 '{0}' 。", "debugTypeNotSupported": "配置的类型“{0}”不受支持。", "debugTypeMissing": "所选的启动配置缺少属性 \"type\"。", "preLaunchTaskErrors": "preLaunchTask“{0}”期间检测到多个生成错误。", diff --git a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 16828d670d2..1de1dd184f1 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -8,5 +8,5 @@ "replVariableAriaLabel": "变量 {0} 具有值 {1}、读取 Eval 打印循环,调试", "replExpressionAriaLabel": "表达式 {0} 具有值 {1},读取 Eval 打印循环,调试", "replValueOutputAriaLabel": "{0},读取 Eval 打印循环,调试", - "replKeyValueOutputAriaLabel": "输出变量 {0} 具有值 {1},读取 Eval 打印循环,调试" + "replRawObjectAriaLabel": "Repl(交互式解释器)变量 {0} 具有值 {1},读取 求值 输出 循环,调试" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index e137dd70e6b..eb4a6b8039f 100644 --- a/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -44,7 +44,7 @@ "showOutdatedExtensions": "显示过时扩展", "showPopularExtensions": "显示常用的扩展", "showRecommendedExtensions": "显示推荐的扩展", - "showWorkspaceRecommendedExtensions": "显示工作区建议的扩展名", + "showWorkspaceRecommendedExtensions": "显示根据工作区推荐的扩展", "showRecommendedKeymapExtensions": "显示推荐键映射", "showRecommendedKeymapExtensionsShort": "键映射", "showLanguageExtensions": "显示语言扩展", diff --git a/i18n/chs/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/chs/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 95ca006c03e..9e7feeb37b4 100644 --- a/i18n/chs/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "是否确实要删除“{0}”?", "undoBin": "可以从回收站还原。", "undoTrash": "可以从回收站还原。", + "doNotAskAgain": "不再询问", "confirmDeleteMessageFolder": "是否确定要永久删除“{0}”及其内容?", "confirmDeleteMessageFile": "是否确定要永久删除“{0}”?", "irreversible": "此操作不可逆!", @@ -37,8 +38,6 @@ "openToSide": "打开到侧边", "compareSource": "选择以进行比较", "globalCompareFile": "比较活动文件与...", - "pickHistory": "选择要进行比较的之前已打开的文件", - "unableToFileToCompare": "无法将所选文件与“{0}”进行比较。", "openFileToCompare": "首先打开文件以将其与另外一个文件比较。", "compareWith": "将“{0}”与“{1}”比较", "compareFiles": "比较文件", @@ -47,7 +46,7 @@ "saveAs": "另存为...", "saveAll": "全部保存", "saveAllInGroup": "保存组中的全部内容", - "saveFiles": "保存已更新文件", + "saveFiles": "保存所有文件", "revert": "还原文件", "focusOpenEditors": "专注于“打开的编辑器”视图", "focusFilesExplorer": "关注文件资源浏览器", diff --git a/i18n/chs/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 7f0b0600897..32f442dc95c 100644 --- a/i18n/chs/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -40,10 +40,14 @@ "dynamicHeight": "控制打开的编辑器部分的高度是否应动态适应元素数量。", "autoReveal": "控制资源管理器是否应在打开文件时自动显示并选择它们。", "enableDragAndDrop": "控制资源管理器是否应该允许通过拖放移动文件和文件夹。", + "confirmDragAndDrop": "控制资源管理器是否应在拖拽移动文件或文件夹时进行确认。", + "confirmDelete": "控制资源管理器是否应在删除文件到回收站时进行确认。", "sortOrder.default": "按名称的字母顺序排列文件和文件夹。文件夹显示在文件前。", "sortOrder.mixed": "按名称的字母顺序排列文件和文件夹。两者穿插显示。", "sortOrder.filesFirst": "按名称的字母顺序排列文件和文件夹。文件显示在文件夹前。", "sortOrder.type": "按扩展名的字母顺序排列文件和文件夹。文件夹显示在文件前。", "sortOrder.modified": "按最后修改日期降序排列文件和文件夹。文件夹显示在文件前。", - "sortOrder": "控制资源管理器文件和文件夹的排列顺序。除了默认排列顺序,你也可以设置为 \"mixed\" (文件和文件夹一起排序)、\"type\" (按文件类型排)、\"modified\" (按最后修改日期排)或是 \"filesFirst\" (将文件排在文件夹前)。" + "sortOrder": "控制资源管理器文件和文件夹的排列顺序。除了默认排列顺序,你也可以设置为 \"mixed\" (文件和文件夹一起排序)、\"type\" (按文件类型排)、\"modified\" (按最后修改日期排)或是 \"filesFirst\" (将文件排在文件夹前)。", + "explorer.decorations.colors": "控制文件修饰是否用颜色。", + "explorer.decorations.badges": "控制文件修饰是否用徽章。" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/chs/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 51ca4525bf3..5939052419b 100644 --- a/i18n/chs/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "无打开的文件夹", "explorerSection": "文件资源管理器部分", - "noWorkspaceHelp": "尚未打开文件夹。", + "noWorkspaceHelp": "你还没有在工作区中添加文件夹。", + "addFolder": "添加文件夹", + "noFolderHelp": "尚未打开文件夹。", "openFolder": "打开文件夹" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/chs/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index cd38244eb23..02057ebfda8 100644 --- a/i18n/chs/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -4,12 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "canNotResolve": "无法解析文件夹 {0}", "fileInputAriaLabel": "键入文件名。按 Enter 以确认或按 Esc 以取消。", "filesExplorerViewerAriaLabel": "{0},文件资源管理器", "dropFolders": "你是否要将文件夹添加到工作区?", "dropFolder": "你是否要将文件夹添加到工作区?", "addFolders": "添加文件夹(&&A)", "addFolder": "添加文件夹(&&A)", + "confirmMove": "是否确实要移动“{0}”?", + "doNotAskAgain": "不再询问", "confirmOverwriteMessage": "目标文件夹中已存在“{0}”。是否要将其替换?", "irreversible": "此操作不可逆!", "replaceButtonLabel": "替换(&&R)" diff --git a/i18n/chs/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/chs/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..6536d821661 --- /dev/null +++ b/i18n/chs/src/vs/workbench/parts/markers/browser/markersFileDecorations.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. +{ + "label": "问题", + "tooltip.1": "此文件存在 1 个问题", + "tooltip.N": "此文件存在 {0} 个问题", + "markers.showOnFile": "显示关于文件与文件夹的错误与警告。" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index c70f6d72be0..123be43ab7b 100644 --- a/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "将设置放入此处以覆盖\"默认设置\"。", - "errorInvalidConfiguration": "无法写入设置。请更正文件中的错误/警告,然后重试。", "emptyWorkspaceSettingsHeader": "将设置放入此处以覆盖\"用户设置\"。", "emptyFolderSettingsHeader": "将文件夹设置放入此处以覆盖\"工作区设置\"。", "defaultFolderSettingsTitle": "默认文件夹设置", diff --git a/i18n/chs/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/chs/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index e66ea5624b1..30778096b47 100644 --- a/i18n/chs/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "在当前上下文中没有启用命令“{0}”。", "recentlyUsed": "最近使用", "morecCommands": "其他命令", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "没有匹配的命令" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/chs/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index c4aae56e0d9..839def0b2a6 100644 --- a/i18n/chs/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,6 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "第 {0} 个更改 (共 {1} 个)", + "change": "第 {0} 个更改 (共 {1} 个)", + "show previous change": "显示上一个更改", + "show next change": "显示下一个更改", "editorGutterModifiedBackground": "编辑器导航线中被修改行的背景颜色。", "editorGutterAddedBackground": "编辑器导航线中已插入行的背景颜色。", "editorGutterDeletedBackground": "编辑器导航线中被删除行的背景颜色。", diff --git a/i18n/chs/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index ad7c43ade10..3fbefcc2302 100644 --- a/i18n/chs/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -17,7 +17,7 @@ "exclude": "配置 glob 模式以在搜索中排除文件和文件夹。从 files.exclude 设置中继承所有 glob 模式。", "exclude.boolean": "匹配文件路径所依据的 glob 模式。设置为 true 或 false 可启用或禁用该模式。", "exclude.when": "对匹配文件的同级文件的其他检查。使用 $(basename) 作为匹配文件名的变量。", - "useRipgrep": "控制是否在文本搜索中使用 ripgrep", + "useRipgrep": "控制是否在文本和文件搜索中使用 ripgrep", "useIgnoreFilesByDefault": "控制在新工作区中搜索时是否默认使用 .gitignore 和 .ignore 文件。", "search.quickOpen.includeSymbols": "配置为在 Quick Open 文件结果中包括全局符号搜索的结果。" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/chs/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 6af8f4d7574..9b159465788 100644 --- a/i18n/chs/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -19,7 +19,6 @@ "ClearSearchResultsAction.label": "清除搜索结果", "FocusNextSearchResult.label": "聚焦下一搜索结果", "FocusPreviousSearchResult.label": "聚焦上一搜索结果", - "RemoveAction.label": "删除", "file.replaceAll.label": "全部替换", "match.replace.label": "替换" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/chs/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index d2110b961fc..9da8ac35792 100644 --- a/i18n/chs/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,8 +10,8 @@ "vscode.extension.contributes.snippets": "添加代码段。", "vscode.extension.contributes.snippets-language": "此代码片段参与的语言标识符。", "vscode.extension.contributes.snippets-path": "代码片段文件的路径。该路径相对于扩展文件夹,通常以 \"./snippets/\" 开头。", - "badFile": "无法读取代码片段文件“{0}”。", "badVariableUse": "“{0}”代码片段很可能混淆了片段变量和片段占位符。有关详细信息,请访问 https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax。", + "badFile": "无法读取代码片段文件“{0}”。", "source.snippet": "用户代码片段", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0},{1}" diff --git a/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 925312c210a..9e55d0c22e6 100644 --- a/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -14,6 +14,7 @@ "runningTasks": "显示运行中的任务", "tasks": "任务", "TaskSystem.noHotSwap": "在有活动任务运行时更换任务执行引擎需要重新加载窗口", + "TaskServer.folderIgnored": "由于使用任务版本 0.1.0,文件夹 {0} 将被忽略", "TaskService.noBuildTask1": "未定义任何生成任务。使用 \"isBuildCommand\" 在 tasks.json 文件中标记任务。", "TaskService.noBuildTask2": "未定义任何生成任务。在 tasks.json 文件中将任务标记为 \"build\" 组。", "TaskService.noTestTask1": "未定义任何测试任务。使用 \"isTestCommand\" 在 tasks.json 文件中标记任务。", @@ -30,6 +31,7 @@ "TaskSystem.activeSame.noBackground": "任务 \"{0}\" 已处于活动状态。若要终止任务,请选择“任务”菜单中的“终止任务...”。", "TaskSystem.active": "当前已有任务正在运行。请先终止它,然后再执行另一项任务。", "TaskSystem.restartFailed": "未能终止并重启任务 {0}", + "TaskService.noConfiguration": "错误: {0} 任务检测没有提供拥有下列配置的任务:\n{1}\n将忽略此任务。", "TaskSystem.configurationErrors": "错误: 提供的任务配置具有验证错误,无法使用。请首先改正错误。", "taskService.ignoreingFolder": "将忽略工作区文件夹 {0} 的任务配置。多文件夹工作区任务支持要求所有文件夹使用任务版本 2.0.0\n", "TaskSystem.invalidTaskJson": "错误: tasks.json 文件的内容具有语法错误。请先更正错误然后再执行任务。\n", 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 ab9987787d1..892b51d9473 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 @@ -17,6 +17,7 @@ "terminal.integrated.fontFamily": "控制终端的字体系列,这在编辑器中是默认的。fontFamily 的值。", "terminal.integrated.fontSize": "控制终端的字号(以像素为单位)。", "terminal.integrated.lineHeight": "控制终端的行高,此数字乘以终端字号得到实际行高(以像素表示)。", + "terminal.integrated.enableBold": "是否在终端内启用粗体文本,注意这需要终端命令行的支持。", "terminal.integrated.cursorBlinking": "控制终端光标是否闪烁。", "terminal.integrated.cursorStyle": "控制终端游标的样式。", "terminal.integrated.scrollback": "控制终端保持在缓冲区的最大行数。", 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 61a809c2168..d96d23dca0e 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 @@ -16,7 +16,6 @@ "workbench.action.terminal.new.short": "新的终端", "workbench.action.terminal.focus": "聚焦于终端", "workbench.action.terminal.focusNext": "聚焦于下一终端", - "workbench.action.terminal.focusAtIndex": "焦点终端 {0}", "workbench.action.terminal.focusPrevious": "聚焦于上一终端", "workbench.action.terminal.paste": "粘贴到活动终端中", "workbench.action.terminal.DefaultShell": "选择默认 Shell", diff --git a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.i18n.json b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.i18n.json index 204cfda7f73..6c965409e92 100644 --- a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.i18n.json @@ -6,5 +6,5 @@ { "terminalLinkHandler.followLinkAlt": "Alt + 单击以访问链接", "terminalLinkHandler.followLinkCmd": "Cmd + 单击以跟踪链接", - "terminalLinkHandler.followLinkCtrl": "Ctrl + 单击以跟踪链接" + "terminalLinkHandler.followLinkCtrl": "按住 Ctrl 并单击可访问链接" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index d3e2c12d9a6..837bb66bacc 100644 --- a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "复制", - "createNewTerminal": "新的终端", "paste": "粘贴", "selectAll": "全选", "clear": "清除" diff --git a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 27b7ce1e9c3..6b431f37d7f 100644 --- a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "好,永不再显示", "terminal.integrated.chooseWindowsShell": "选择首选的终端 shell,你可稍后在设置中进行更改", "terminalService.terminalCloseConfirmationSingular": "存在一个活动的终端会话,是否要终止此会话?", - "terminalService.terminalCloseConfirmationPlural": "存在 {0} 个活动的终端会话,是否要终止这些会话?", - "yes": "是" + "terminalService.terminalCloseConfirmationPlural": "存在 {0} 个活动的终端会话,是否要终止这些会话?" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/chs/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..2eb80022de4 --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "设置摘要。此标签将在设置文件中用作分隔注释。", + "vscode.extension.contributes.configuration.properties": "配置属性的描述。", + "scope.window.description": "特定于窗口的配置,可在“用户”或“工作区”设置中配置。", + "scope.resource.description": "特定于资源的配置,可在“用户”、“工作区”或“文件夹”设置中配置。", + "scope.description": "配置适用的范围。可用范围有“窗口”和“资源”。", + "vscode.extension.contributes.configuration": "用于配置字符串。", + "invalid.title": "configuration.title 必须是字符串", + "vscode.extension.contributes.defaultConfiguration": "按语言提供默认编辑器配置设置。", + "invalid.properties": "configuration.properties 必须是对象", + "invalid.allOf": "\"configuration.allOf\" 已被弃用且不应被使用。你可以将多个配置单元作为数组传递给 \"configuration\" 参与点。", + "workspaceConfig.folders.description": "将载入到工作区的文件夹列表。", + "workspaceConfig.path.description": "文件路径。例如 \"/root/folderA\" 或 \"./folderA\"。后者表示根据工作区文件位置进行解析的相对路径。", + "workspaceConfig.name.description": "文件夹的可选名称。", + "workspaceConfig.uri.description": "文件夹的 URI", + "workspaceConfig.settings.description": "工作区设置", + "workspaceConfig.extensions.description": "工作区扩展", + "unknownWorkspaceProperty": "未知的工作区配置属性" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/chs/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/editor/common/editorService.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. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/chs/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index 3006c199103..1c27ab2249d 100644 --- a/i18n/chs/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/chs/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -6,6 +6,7 @@ { "schema.token.settings": "标记的颜色和样式。", "schema.token.foreground": "标记的前景色。", + "schema.token.background.warning": "暂不支持标记背景色。", "schema.token.fontStyle": "规则字体样式:“斜体”、“粗体”和“下划线”中的一种或者组合", "schema.fontStyle.error": "字体样式必须为 \"italic\"(斜体)、 \"bold\"(粗体)和 \"underline\"(下划线)的组合。", "schema.properties.name": "规则的描述。", diff --git a/i18n/chs/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/chs/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index 182830f549e..47cfacc0457 100644 --- a/i18n/chs/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/chs/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "使用某种字体时: 文本字体的字体大小(以百分比表示)。如果未设置,则默认为字体定义中的大小。", "schema.fontId": "使用某种字体时: 字体的 ID。如果未设置,则默认为第一个字体定义。", "schema.light": "浅色主题中文件图标的可选关联。", - "schema.highContrast": "高对比度颜色主题中文件图标的可选关联。" + "schema.highContrast": "高对比度颜色主题中文件图标的可选关联。", + "schema.hidesExplorerArrows": "配置文件资源管理器的箭头是否应在此主题启用时隐藏。" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/chs/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..61d59fe560d --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.themes": "请提供 TextMate 颜色主题。", + "vscode.extension.contributes.themes.id": "用户设置中使用的图标主题的 ID。", + "vscode.extension.contributes.themes.label": "显示在 UI 中的颜色主题标签。", + "vscode.extension.contributes.themes.uiTheme": "用于定义编辑器周围颜色的基本主题: \"vs\" 是浅色主题,\"vs-dark\" 是深色主题。\"hc-black\" 是深色高对比度主题。", + "vscode.extension.contributes.themes.path": "tmTheme 文件的路径。该路径相对于扩展文件夹,通常为 \"./themes/themeFile.tmTheme\"。", + "reqarray": "扩展点“{0}”必须是一个数组。", + "reqpath": "“contributes.{0}.path”中应为字符串。提供的值: {1}", + "invalid.path.1": "“contributes.{0}.path”({1})应包含在扩展的文件夹({2})内。这可能会使扩展不可移植。" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/chs/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..0ccb5d7ff4d --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.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. +{ + "error.cannotparseicontheme": "分析文件图标文件时出现问题: {0}" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/chs/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..239f4582a9f --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.iconThemes": "提供文件图标主题。", + "vscode.extension.contributes.iconThemes.id": "用户设置中使用的图标主题的 ID。", + "vscode.extension.contributes.iconThemes.label": "UI 中显示的图标主题的标签。", + "vscode.extension.contributes.iconThemes.path": "图标主题定义文件的路径。该路径相对于扩展文件夹,通常是 \"./icons/awesome-icon-theme.json\"。", + "reqarray": "扩展点“{0}”必须是一个数组。", + "reqpath": "“contributes.{0}.path”中应为字符串。提供的值: {1}", + "reqid": "contributes.{0}.id\" 中的预期字符串。提供的值: {1}", + "invalid.path.1": "“contributes.{0}.path”({1})应包含在扩展的文件夹({2})内。这可能会使扩展不可移植。" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/chs/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index fae9207b8f3..2a7c7dc77d5 100644 --- a/i18n/chs/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/chs/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,31 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "用户设置中使用的图标主题的 ID。", - "vscode.extension.contributes.themes.label": "显示在 UI 中的颜色主题标签。", - "vscode.extension.contributes.themes.uiTheme": "用于定义编辑器周围颜色的基本主题: \"vs\" 是浅色主题,\"vs-dark\" 是深色主题。\"hc-black\" 是深色高对比度主题。", - "vscode.extension.contributes.themes.path": "tmTheme 文件的路径。该路径相对于扩展文件夹,通常为 \"./themes/themeFile.tmTheme\"。", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "用户设置中使用的图标主题的 ID。", - "vscode.extension.contributes.iconThemes.label": "UI 中显示的图标主题的标签。", - "vscode.extension.contributes.iconThemes.path": "图标主题定义文件的路径。该路径相对于扩展文件夹,通常是 \"./icons/awesome-icon-theme.json\"。", "migration.completed": "已向用户设置添加了新的主题设置。{0} 中可备份。", "error.cannotloadtheme": "无法加载 {0}: {1}", - "reqarray": "扩展点“{0}”必须是一个数组。", - "reqpath": "“contributes.{0}.path”中应为字符串。提供的值: {1}", - "invalid.path.1": "“contributes.{0}.path”({1})应包含在扩展的文件夹({2})内。这可能会使扩展不可移植。", - "reqid": "“contributes.{0}.id”中应为字符串。提供的值: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "指定工作台中使用的颜色主题。", "colorThemeError": "主题未知或未安装。", "iconTheme": "指定在工作台中使用的图标主题,或指定 \"null\" 以不显示任何文件图标。", "noIconThemeDesc": "No file icons", "iconThemeError": "文件图标主题未知或未安装。", "workbenchColors": "覆盖当前所选颜色主题的颜色。", - "workbenchColors.deprecated": "该设置不再是实验性设置,并已重命名为“workbench.colorCustomizations”", - "workbenchColors.deprecatedDescription": "改用“workbench.colorCustomizations”", "editorColors": "覆盖当前所选颜色主题中的编辑器颜色和字体样式。", "editorColors.comments": "设置注释的颜色和样式", "editorColors.strings": "设置字符串文本的颜色和样式", diff --git a/i18n/chs/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/chs/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..9db48716791 --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/workspace/node/workspaceEditingService.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. +{ + "openWorkspaceConfigurationFile": "打开工作区配置文件", + "close": "关闭" +} \ No newline at end of file diff --git a/i18n/cht/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/cht/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index 54a0b2aaf23..885fb5847ec 100644 --- a/i18n/cht/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/cht/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,8 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "例如 myFile.txt", - "activeEditorMedium": "例如 myFolder/myFile.txt", - "activeEditorLong": "例如 /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "例如 myFolder1, , myFolder2, myFolder3", - "rootPath": "例如 /Users/Development/myProject", - "folderName": "例如 myFolder", - "folderPath": "例如 /Users/Development/myFolder", + "activeEditorShort": "檔案名稱(例如:myFile.txt)", + "activeEditorMedium": "檔案相對於工作區資料夾的相對路徑(例如:myFolder/myFile.txt)", "appName": "例如 VS Code", "dirty": "若使用中的編輯器已變更,即為已變更的指示區", "separator": "條件式分隔符號 (' - '),只會在前後為具有值的變數時顯示", diff --git a/i18n/cht/extensions/emmet/package.i18n.json b/i18n/cht/extensions/emmet/package.i18n.json index 392c4b2278a..84abd814d8a 100644 --- a/i18n/cht/extensions/emmet/package.i18n.json +++ b/i18n/cht/extensions/emmet/package.i18n.json @@ -28,13 +28,6 @@ "command.incrementNumberByTen": "依 10 遞增", "command.decrementNumberByTen": "依 10 遞減", "emmetSyntaxProfiles": "為指定的語法定義設定檔,或透過特定規則使用自己的設定檔。", - "emmetExclude": "不應展開 Emmet 縮寫的語言陣列。", - "emmetExtensionsPath": "包含 Emmet 設定檔與程式碼片段的資料夾路徑。」", - "emmetShowExpandedAbbreviation": "顯示建議之展開的 Emmet 縮寫\n\"inMarkupAndStylesheetFilesOnly\" 選項適用於 html、haml、jade、slim、xml、xsl、css、scss、sass、less 和 stylus。\n不論標記/css 為何,該選項「一律」適用於檔案的所有部分。", - "emmetShowAbbreviationSuggestions": "顯示建議之可能的 Emmet 縮寫。但在樣式表內,或若 emmet.showExpandedAbbreviation 設為「永不」,則不適用。", - "emmetIncludeLanguages": "以預設未支援的語言啟用 Emmet 縮寫。在此新增該語言和 Emmet 支援的語言間之對應。例如: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"} ", - "emmetVariables": "要在 Emmet 程式碼片段中使用的變數", - "emmetTriggerExpansionOnTab": "如有啟用,只要按 Tab 鍵就能展開 Emmet 縮寫。", "emmetPreferences": "喜好設定,用以修改某些動作的行為及 Emmet 的解析程式。", "emmetPreferencesIntUnit": "整數值的預設單位", "emmetPreferencesFloatUnit": "浮點值的預設單位", @@ -43,6 +36,5 @@ "emmetPreferencesStylusAfter": "在手寫筆檔案中展開 CSS 縮寫時,要放在 CSS 屬性結尾的符號", "emmetPreferencesCssBetween": "展開 CSS 縮寫時,要放在 CSS 屬性與值之間的符號", "emmetPreferencesSassBetween": "在 SASS 檔案中展開 CSS 縮寫時,要放在 CSS 屬性與值之間的符號", - "emmetPreferencesStylusBetween": "在手寫筆檔案中展開 CSS 縮寫時,要放在 CSS 屬性與值之間的符號", - "emmetShowSuggestionsAsSnippets": "若為 true,則 Emmet 建議會顯示為程式碼片段,可讓您在每個 editor.snippetSuggestions 設定為其排序。" + "emmetPreferencesStylusBetween": "在手寫筆檔案中展開 CSS 縮寫時,要放在 CSS 屬性與值之間的符號" } \ No newline at end of file diff --git a/i18n/cht/extensions/git/out/commands.i18n.json b/i18n/cht/extensions/git/out/commands.i18n.json index d7ef0b15a46..6c7a6f8972a 100644 --- a/i18n/cht/extensions/git/out/commands.i18n.json +++ b/i18n/cht/extensions/git/out/commands.i18n.json @@ -12,8 +12,8 @@ "cloning": "正在複製 Git 儲存庫...", "openrepo": "開啟儲存庫", "proposeopen": "要開啟複製的儲存庫嗎?", - "path to init": "資料夾路徑", - "provide path": "請提供資料夾路徑以初始化 Git 存放庫", + "init repo": "初始化儲存庫", + "create repo": "初始化儲存庫", "HEAD not available": "'{0}' 的 HEAD 版本無法使用。", "confirm stage files with merge conflicts": "確定要暫存 {0} 個有合併衝突的檔案嗎?", "confirm stage file with merge conflicts": "確定要暫存有合併衝突的 {0} 嗎?", diff --git a/i18n/cht/extensions/git/out/repository.i18n.json b/i18n/cht/extensions/git/out/repository.i18n.json index c07485bdb63..9cbc280931f 100644 --- a/i18n/cht/extensions/git/out/repository.i18n.json +++ b/i18n/cht/extensions/git/out/repository.i18n.json @@ -21,6 +21,8 @@ "deleted by us": "已受到我們刪除", "both added": "皆已新增", "both modified": "皆已修改", + "untracked, short": "U", + "modified, short": "M", "commit": "認可", "merge changes": "合併變更", "staged changes": "已分段的變更", diff --git a/i18n/cht/extensions/typescript/package.i18n.json b/i18n/cht/extensions/typescript/package.i18n.json index e56e400373b..a881af4077d 100644 --- a/i18n/cht/extensions/typescript/package.i18n.json +++ b/i18n/cht/extensions/typescript/package.i18n.json @@ -44,7 +44,6 @@ "typescript.npm": "指定用於自動類型取得的 NPM 可執行檔路徑。TypeScript 必須 >= 2.3.4.", "typescript.check.npmIsInstalled": "檢查是否已安裝NPM用以取得自動類型擷取.", "javascript.nameSuggestions": "從JavaScript推薦表檔案中啟用/停用包含唯一檔名", - "typescript.tsc.autoDetect": "控制 tsc 工作的自動偵測為開啟或關閉。", "typescript.problemMatchers.tsc.label": "TypeScript 問題", "typescript.problemMatchers.tscWatch.label": " TypeScript 問題 (監看模式)" } \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/cht/src/vs/editor/common/view/editorColorRegistry.i18n.json index 4cdf779ce91..85ff9ee951e 100644 --- a/i18n/cht/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/cht/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -6,7 +6,7 @@ { "lineHighlight": "目前游標位置行的反白顯示背景色彩。", "lineHighlightBorderBox": "目前游標位置行之周圍框線的背景色彩。", - "rangeHighlight": "反白顯示範圍的背景色彩,例如 Quick Open 與尋找功能。", + "rangeHighlight": "反白顯示範圍的背景色彩,例如快速開啟與尋找功能。", "caret": "編輯器游標的色彩。", "editorCursorBackground": "編輯器游標的背景色彩。允許自訂區塊游標重疊的字元色彩。", "editorWhitespaces": "編輯器中空白字元的色彩。", diff --git a/i18n/cht/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/cht/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 32ac75ef725..19132dbfd98 100644 --- a/i18n/cht/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/cht/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,6 @@ "label.replaceButton": "取代", "label.replaceAllButton": "全部取代", "label.toggleReplaceButton": "切換取代模式", - "title.matchesCountLimit": "只會將前 999 筆結果醒目提示,但所有尋找作業會在完整文字上執行。", "label.matchesLocation": "{0} / {1}", "label.noResults": "沒有結果" } \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/cht/src/vs/editor/contrib/find/common/findController.i18n.json index c75e923d0b7..cbbf89b710f 100644 --- a/i18n/cht/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/cht/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "尋找下一個選取項目", "previousSelectionMatchFindAction": "尋找上一個選取項目", "startReplace": "取代", - "addSelectionToNextFindMatch": "將選取項目加入下一個找到的相符項", - "addSelectionToPreviousFindMatch": "將選取項目加入前一個找到的相符項中", - "moveSelectionToNextFindMatch": "將最後一個選擇項目移至下一個找到的相符項", - "moveSelectionToPreviousFindMatch": "將最後一個選擇項目移至前一個找到的相符項", - "selectAllOccurrencesOfFindMatch": "選取所有找到的相符項目", - "changeAll.label": "變更所有發生次數", "showNextFindTermAction": "顯示下一個尋找字詞", "showPreviousFindTermAction": "顯示上一個尋找字詞" } \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/cht/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 722b3100d2e..381e4cfcb4c 100644 --- a/i18n/cht/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/cht/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "在上方加入游標", "mutlicursor.insertBelow": "在下方加入游標", - "mutlicursor.insertAtEndOfEachLineSelected": "在行尾新增游標" + "mutlicursor.insertAtEndOfEachLineSelected": "在行尾新增游標", + "addSelectionToNextFindMatch": "將選取項目加入下一個找到的相符項", + "addSelectionToPreviousFindMatch": "將選取項目加入前一個找到的相符項中", + "moveSelectionToNextFindMatch": "將最後一個選擇項目移至下一個找到的相符項", + "moveSelectionToPreviousFindMatch": "將最後一個選擇項目移至前一個找到的相符項", + "selectAllOccurrencesOfFindMatch": "選取所有找到的相符項目", + "changeAll.label": "變更所有發生次數" } \ No newline at end of file diff --git a/i18n/cht/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/cht/src/vs/platform/theme/common/colorRegistry.i18n.json index 5f7d8743b2b..1ec0770a363 100644 --- a/i18n/cht/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/cht/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "色彩格式無效。請使用 #RGB、#RGBA、#RRGGBB 或 #RRGGBBAA", "schema.colors": "工作台中使用的色彩。", "foreground": "整體的前景色彩。僅當未被任何元件覆疊時,才會使用此色彩。", "errorForeground": "整體錯誤訊息的前景色彩。僅當未被任何元件覆蓋時,才會使用此色彩。", diff --git a/i18n/cht/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/cht/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 18a591310bd..604755744c9 100644 --- a/i18n/cht/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -13,6 +13,7 @@ "select": "選取(&&S)", "selectWorkspace": "為工作區選取資料夾", "removeFolderFromWorkspace": "將資料夾從工作區移除", + "openFolderSettings": "開啟資料夾設定", "saveWorkspaceAsAction": "另存工作區為...", "save": "儲存(&&S)", "saveWorkspace": "儲存工作區", diff --git a/i18n/cht/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index e2c33864cd6..1ca947dd5de 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "隱藏活動列", - "activityBarAriaLabel": "即時檢視切換器", "globalActions": "全域動作" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..313c717e038 --- /dev/null +++ b/i18n/cht/src/vs/workbench/browser/parts/compositebar/compositeBar.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. +{ + "activityBarAriaLabel": "即時檢視切換器" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..0ab2723d455 --- /dev/null +++ b/i18n/cht/src/vs/workbench/browser/parts/compositebar/compositeBarActions.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. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "其他檢視", + "numberBadge": "{0} ({1})", + "manageExtension": "管理延伸模組", + "titleKeybinding": "{0} ({1})", + "hide": "隱藏", + "toggle": "切換釘選的檢視" +} \ 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 156d3f5bd02..fc25ce13ad0 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 @@ -12,5 +12,6 @@ "groupTwoPicker": "在第二個群組顯示編輯器", "groupThreePicker": "在第三個群組顯示編輯器", "allEditorsPicker": "顯示所有開啟的編輯器", - "view": "檢視" + "view": "檢視", + "file": "檔案" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index d59f4257e4e..05f1e85eb7b 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "命令 '{0}' 目前未啟用,因此無法執行。", "manageExtension": "管理延伸模組" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/cht/src/vs/workbench/electron-browser/main.contribution.i18n.json index 8b6818a6c02..af13c8df70b 100644 --- a/i18n/cht/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,18 +10,14 @@ "workspaces": "工作區", "developer": "開發人員", "showEditorTabs": "控制已開啟的編輯器是否應顯示在索引標籤中。", - "workbench.editor.labelFormat.default": "顯示檔案的名稱。當啟用索引標籤時,若在一個群組中有兩個檔案使用相同的名稱,就會新增每個檔案路徑具有辨識度的區段。當索引標籤停用時,若編輯器在使用中,則會顯示工作區根目錄的相關路徑。", "workbench.editor.labelFormat.short": "顯示檔案的名稱,並在名稱後接著該檔案的目錄名稱。", - "workbench.editor.labelFormat.medium": "顯示檔案的名稱,並在名稱後接著該檔案與工作區根目錄有關的路徑。", "workbench.editor.labelFormat.long": "顯示檔案的名稱,並在名稱後接著該檔案的絕對路徑。", "tabDescription": "控制編輯器的標籤格式。變更此設定具有多項優點,例如可讓檔案的位置更加清楚:\n-簡短: 'parent'\n-中等: 'workspace/src/parent'\n-完整: '/home/user/workspace/src/parent'\n-預設: '.../parent',當另一個索引標籤共用相同的標題,或若路徑停用,卻共用相關的工作區路徑時", "editorTabCloseButton": "控制編輯器的索引標籤關閉按鈕位置,或在設為 'off' 時將其停用。", "showIcons": "控制開啟的編輯器是否搭配圖示顯示。這需要同時啟用圖示佈景主題。", "enablePreview": "控制已開啟的編輯器是否顯示為預覽。預覽編輯器會重複使用到被保留 (例如按兩下或進行編輯) 並以斜體字型樣式顯示為止。", "enablePreviewFromQuickOpen": "控制透過 Quick Open 所開啟的編輯器是否顯示為預覽。預覽編輯器會重複使用到被保留 (例如按兩下或進行編輯) 為止。", - "editorOpenPositioning": "控制要在何處開啟編輯器。選取 [左] 或 [右] 在目前使用中編輯器的左側或右側開啟編輯器。選取 [先] 或 [後] 從目前使用中編輯器另外開啟編輯器。", "revealIfOpen": "控制編輯器是否要在任何顯示的群組開啟時,在其中顯示。若啟用此選項,已經開啟的編輯器將會繼續顯示,而不會在目前使用中的編輯器群組中再開啟一次。請注意,有一些情況會忽略此設定,例如當強制編輯器在特定群組中開啟,或強制編輯器在目前使用中的群組旁開啟等情況。", - "commandHistory": "控制是否要保留在命令選擇區歷程記錄中最近所使用的命令數目。設定為 0 以停用命令歷程記錄。", "preserveInput": "控制下次開啟命令選擇區時,最後鍵入的輸入是否應該還原。", "closeOnFocusLost": "控制是否在 Quick Open 失去焦點時自動關閉。", "openDefaultSettings": "控制開啟設定時是否也會開啟顯示所有預設設定的編輯器。", @@ -50,7 +46,6 @@ "restoreWindows": "控制重新啟動後視窗重新開啟的方式。選取 [無] 一律以空白工作區開始、選取 [一] 從上一個編輯的視窗重新開啟、選取 [資料夾] 重新開啟所有資料夾曾經開啟的視窗,或選取 [全部] 重新開啟上一個工作階段的所有視窗。", "restoreFullscreen": "控制當視窗在全螢幕模式下結束後,下次是否仍以全螢幕模式開啟。", "zoomLevel": "調整視窗的縮放比例。原始大小為 0,而且每個向上增量 (例如 1) 或向下增量 (例如 -1) 代表放大或縮小 20%。您也可以輸入小數,更細微地調整縮放比例。", - "title": "依據使用中的編輯器控制視窗標題。變數會依據內容替換:\n${activeEditorShort}: 例如 myFile.txt\n${activeEditorMedium}: 例如 myFolder/myFile.txt\n${activeEditorLong}: 例如 /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: 例如 myFolder\n${folderPath}: 例如 /Users/Development/myFolder\n${rootName}: 例如 myFolder1,myFolder2,myFolder3\n${rootPath}: 例如 /Users/Development/myWorkspace\n${appName}: 例如 VS Code\n${dirty}: 用以指出編輯器經過變更的指標\n${separator}: 條件式分隔符號 (' - '),只會在前後為具有值的變數時顯示", "window.newWindowDimensions.default": "在螢幕中央開啟新視窗。", "window.newWindowDimensions.inherit": "以相同於上一個使用中之視窗的維度開啟新視窗。", "window.newWindowDimensions.maximized": "開啟並最大化新視窗。", diff --git a/i18n/cht/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index b6a825d8df7..86768e58c63 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0},偵錯", "debugAriaLabel": "輸入要執行之啟動組態的名稱。", + "addConfigTo": "新增組態 ({0})...", + "addConfiguration": "新增組態...", "noConfigurationsMatching": "沒有任何相符的偵錯組態", "noConfigurationsFound": "找不到任何偵錯組態。請建立'launch.json' 檔案。" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..24c491ad8e0 --- /dev/null +++ b/i18n/cht/src/vs/workbench/parts/debug/browser/debugStatus.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. +{ + "debug": "偵錯" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/cht/src/vs/workbench/parts/debug/browser/debugViewlet.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/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 d0e90daa9e8..19f502a82ef 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 @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "組態,用於產生初始 'launch.json'。", "vscode.extension.contributes.debuggers.languages": "可將偵錯延伸模組視為「預設偵錯工具」的語言清單。", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "如有指定,VS Code 會呼叫此命令以決定偵錯配接器的可執行檔路徑及要傳遞的引數。", - "vscode.extension.contributes.debuggers.startSessionCommand": "如有指定,VS Code 會為以此延伸模組為目標的「偵錯」或「執行」動作呼叫此命令。", "vscode.extension.contributes.debuggers.configurationSnippets": "用於在 'launch.json' 中新增組態的程式碼片段。", "vscode.extension.contributes.debuggers.configurationAttributes": "JSON 結構描述組態,用於驗證 'launch.json'。", "vscode.extension.contributes.debuggers.windows": "Windows 特定設定。", diff --git a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 4bdc5fb94f2..c949e5dbf8b 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,10 +12,7 @@ "breakpointRemoved": "已移除中斷點,行 {0},檔案 {1}", "compoundMustHaveConfigurations": "複合必須設有 \"configurations\" 屬性,才能啟動多個組態。", "configMissing": "'launch.json' 中遺漏組態 '{0}'。", - "debugRequestNotSupported": "所選的偵錯組態具有不支援的屬性值 '{0}': '{1}'。", - "debugRequesMissing": "所選的偵錯組態遺漏屬性 '{0}'。", "debugTypeNotSupported": "不支援設定的偵錯類型 '{0}'。", - "debugTypeMissing": "遺漏所選啟動設定的屬性 'type'。", "preLaunchTaskErrors": "執行 preLaunchTask '{0}' 期間偵測到建置錯誤。", "preLaunchTaskError": "執行 preLaunchTask '{0}' 期間偵測到建置錯誤。", "preLaunchTaskExitCode": "preLaunchTask '{0}' 已終止,結束代碼為 {1}。", diff --git a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index e7982d93dfd..39f259be4a4 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -7,6 +7,5 @@ "stateCapture": "第一次評估會擷取物件狀態", "replVariableAriaLabel": "變數 {0} 具有值 {1},「讀取、求值、輸出」迴圈,偵錯", "replExpressionAriaLabel": "運算式 {0} 具有值 {1},「讀取、求值、輸出」迴圈,偵錯", - "replValueOutputAriaLabel": "{0},「讀取、求值、輸出」迴圈,偵錯", - "replKeyValueOutputAriaLabel": "輸出變數 {0} 具有值 {1},「讀取、求值、輸出」迴圈,偵錯" + "replValueOutputAriaLabel": "{0},「讀取、求值、輸出」迴圈,偵錯" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/cht/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 0ce10edb281..141887ab75f 100644 --- a/i18n/cht/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -37,8 +37,6 @@ "openToSide": "開至側邊", "compareSource": "選取用以比較", "globalCompareFile": "使用中檔案的比較對象...", - "pickHistory": "選取先前開啟的檔案以相比較", - "unableToFileToCompare": "選取的檔案無法與 '{0}' 進行比較。", "openFileToCompare": "先開啟檔案以與其他檔案進行比較", "compareWith": "比較 '{0}' 與 '{1}'", "compareFiles": "比較檔案", @@ -47,7 +45,6 @@ "saveAs": "另存新檔...", "saveAll": "全部儲存", "saveAllInGroup": "全部儲存在群組中", - "saveFiles": "儲存已變更的檔案", "revert": "還原檔案", "focusOpenEditors": "聚焦在 [開放式編輯器] 檢視", "focusFilesExplorer": "將焦點設在檔案總管上", diff --git a/i18n/cht/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/cht/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 22aa2fcc887..19ea692c744 100644 --- a/i18n/cht/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,6 @@ { "noWorkspace": "沒有開啟的資料夾", "explorerSection": "檔案總管區段", - "noWorkspaceHelp": "您尚未開啟資料夾。", + "noFolderHelp": "您尚未開啟資料夾。", "openFolder": "開啟資料夾" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/cht/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..79cb63cbd79 --- /dev/null +++ b/i18n/cht/src/vs/workbench/parts/markers/browser/markersFileDecorations.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. +{ + "label": "問題" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index 12df0eb0474..fdeeb3c2a27 100644 --- a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "將您的設定放置在此以覆寫預設設定。", - "errorInvalidConfiguration": "無法寫入設定.請開啟使用者設定並修正檔案中的錯誤/警告後再試一次.", "emptyWorkspaceSettingsHeader": "將您的設定放置在此以覆寫使用者設定。", "emptyFolderSettingsHeader": "將您的資料夾設定放置在此以覆寫工作區設定的資料夾設定。", "defaultFolderSettingsTitle": "預設資料夾設定", diff --git a/i18n/cht/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/cht/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 6b7c584d6f2..510d9ec3ad3 100644 --- a/i18n/cht/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "目前內容中未啟用命令 '{0}'。", "recentlyUsed": "最近使用的", "morecCommands": "其他命令", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "沒有相符的命令" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index 533ad58e7aa..5bd2e68d516 100644 --- a/i18n/cht/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -17,7 +17,6 @@ "exclude": "設定 Glob 模式,以排除不要搜尋的檔案及資料夾。請從 file.exclude 設定繼承所有的 Glob 模式。", "exclude.boolean": "要符合檔案路徑的 Glob 模式。設為 True 或 False 可啟用或停用模式。", "exclude.when": "在相符檔案同層級上額外的檢查。請使用 $(basename) 作為相符檔案名稱的變數。", - "useRipgrep": "控制是否要在文字搜尋中使用 ripgrep", "useIgnoreFilesByDefault": "控制在搜尋新的工作區時,是否要根據預設使用 .gitignore 及 .ignore 檔案。", "search.quickOpen.includeSymbols": "設定以將全域符號搜尋的結果納入 Quick Open 的檔案結果中。" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/cht/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 52826c8f8d8..c638d855adf 100644 --- a/i18n/cht/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -19,7 +19,6 @@ "ClearSearchResultsAction.label": "清除搜尋結果", "FocusNextSearchResult.label": "聚焦於下一個搜尋結果", "FocusPreviousSearchResult.label": "聚焦於上一個搜尋結果", - "RemoveAction.label": "移除", "file.replaceAll.label": "全部取代", "match.replace.label": "取代" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/cht/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 8f1cdc4c641..a7b095ad28a 100644 --- a/i18n/cht/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,8 +10,8 @@ "vscode.extension.contributes.snippets": "提供程式碼片段。", "vscode.extension.contributes.snippets-language": "要予以提供此程式碼片段的語言識別碼。", "vscode.extension.contributes.snippets-path": "程式碼片段檔案的路徑。此路徑是擴充功能資料夾的相對路徑,而且一般會以 './snippets/' 開頭。", - "badFile": "無法讀取程式碼片段檔案 \"{0}\"。", "badVariableUse": "程式碼片段 \"{0}\" 很可能會混淆 snippet-variables 及 snippet-placeholders。如需詳細資料,請參閱 https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax。", + "badFile": "無法讀取程式碼片段檔案 \"{0}\"。", "source.snippet": "使用者程式碼片段", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0},{1}" 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 db8c0bb2809..40342458179 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 @@ -16,7 +16,6 @@ "workbench.action.terminal.new.short": "新增終端機", "workbench.action.terminal.focus": "聚焦終端機", "workbench.action.terminal.focusNext": "聚焦下一個終端機", - "workbench.action.terminal.focusAtIndex": "聚焦終端機 {0}", "workbench.action.terminal.focusPrevious": "聚焦上一個終端機", "workbench.action.terminal.paste": "貼入使用中的終端機", "workbench.action.terminal.DefaultShell": "選取預設殼層", diff --git a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index f9f8c2b8d9e..4c35ec5d698 100644 --- a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "複製", - "createNewTerminal": "新增終端機", "paste": "貼上", "selectAll": "全選", "clear": "清除" 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 19e71491bf0..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 @@ -10,6 +10,5 @@ "never again": "確定,不要再顯示", "terminal.integrated.chooseWindowsShell": "請選取所需的終端機殼層。您之後可以在設定中變更此選擇", "terminalService.terminalCloseConfirmationSingular": "仍有一個使用中的終端機工作階段。要予以終止嗎?", - "terminalService.terminalCloseConfirmationPlural": "目前共有 {0} 個使用中的終端機工作階段。要予以終止嗎?", - "yes": "是" + "terminalService.terminalCloseConfirmationPlural": "目前共有 {0} 個使用中的終端機工作階段。要予以終止嗎?" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/cht/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..2bc73e75628 --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "設定的摘要。此標籤將會在設定檔中作為分隔註解使用。", + "vscode.extension.contributes.configuration.properties": "組態屬性的描述。", + "scope.window.description": "視窗特定組態,可在使用者或工作區設定中予以設定。", + "scope.resource.description": "資源特定設定,可在使用者、工作區或資料夾設定中予以設定。", + "scope.description": "組態適用的範圍。可用的範圍為「視窗」和「資源」。", + "vscode.extension.contributes.configuration": "提供組態設定。", + "invalid.title": "'configuration.title' 必須是字串", + "vscode.extension.contributes.defaultConfiguration": "依語言貢獻預設編輯器組態設定。", + "invalid.properties": "'configuration.properties' 必須是物件", + "invalid.allOf": "'configuration.allOf' 已取代而不應再使用。請改為將多個組態區段作為陣列,傳遞至「組態」貢獻點。", + "workspaceConfig.folders.description": "要載入工作區之資料夾的清單。", + "workspaceConfig.path.description": "檔案路徑,例如 `/root/folderA` 或 `./folderA` 即為會對工作區檔案位置解析的相關路徑。", + "workspaceConfig.name.description": "資料夾的選用名稱。", + "workspaceConfig.uri.description": "資料夾的 URI", + "workspaceConfig.settings.description": "工作區設定", + "workspaceConfig.extensions.description": "工作區延伸模組", + "unknownWorkspaceProperty": "未知的工作區組態屬性" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/cht/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/editor/common/editorService.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. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/cht/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..f1b7981878d --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.themes": "提供 Textmate 彩色佈景主題。", + "vscode.extension.contributes.themes.id": "用在使用者設定中的圖示佈景主題識別碼。", + "vscode.extension.contributes.themes.label": "如 UI 中所示的彩色佈景主題標籤。", + "vscode.extension.contributes.themes.uiTheme": "基底佈景主題定義編輯器的色彩: 'vs' 是淺色佈景主題,'vs-dark' 是深色佈景主題。'hc-black' 是深色高對比佈景主題。", + "vscode.extension.contributes.themes.path": "tmTheme 檔案的路徑。此路徑是擴充功能資料夾的相對路徑,通常為 './themes/themeFile.tmTheme'。", + "reqarray": "擴充點 '{0}' 必須是陣列。", + "reqpath": "'contributes.{0}.path' 中應有字串。提供的值: {1}", + "invalid.path.1": "擴充功能資料夾 ({2}) 應包含 'contributes.{0}.path' ({1})。這可能會導致擴充功能無法移植。" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/cht/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..e7493947e49 --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.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. +{ + "error.cannotparseicontheme": "剖析檔案的圖示檔時發生問題: {0}" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/cht/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..dd6a68fb722 --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.iconThemes": "貢獻檔案圖示佈景主題。", + "vscode.extension.contributes.iconThemes.id": "用在使用者設定中的圖示佈景主題識別碼。", + "vscode.extension.contributes.iconThemes.label": "以 UI 顯示的圖示佈景主題標籤。", + "vscode.extension.contributes.iconThemes.path": "圖示佈景主題定義檔案。路徑相對於擴充功能資料夾,通常為 './icons/awesome-icon-theme.json'。", + "reqarray": "擴充點 '{0}' 必須是陣列。", + "reqpath": "'contributes.{0}.path' 中應有字串。提供的值: {1}", + "reqid": "`contributes.{0}.id` 中應有字串。提供的值: {1}", + "invalid.path.1": "擴充功能資料夾 ({2}) 應包含 'contributes.{0}.path' ({1})。這可能會導致擴充功能無法移植。" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/cht/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index 34021b15c0a..5ab16a62ce2 100644 --- a/i18n/cht/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/cht/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,31 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "用在使用者設定中的圖示佈景主題識別碼。", - "vscode.extension.contributes.themes.label": "如 UI 中所示的彩色佈景主題標籤。", - "vscode.extension.contributes.themes.uiTheme": "基底佈景主題定義編輯器的色彩: 'vs' 是淺色佈景主題,'vs-dark' 是深色佈景主題。'hc-black' 是深色高對比佈景主題。", - "vscode.extension.contributes.themes.path": "tmTheme 檔案的路徑。此路徑是擴充功能資料夾的相對路徑,通常為 './themes/themeFile.tmTheme'。", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "用在使用者設定中的圖示佈景主題識別碼。", - "vscode.extension.contributes.iconThemes.label": "以 UI 顯示的圖示佈景主題標籤。", - "vscode.extension.contributes.iconThemes.path": "圖示佈景主題定義檔案。路徑相對於擴充功能資料夾,通常為 './icons/awesome-icon-theme.json'。", "migration.completed": "已將新的佈景主題設定新增到使用者設定。備份位於 {0}。", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "`contributes.{0}.path` 中的預期字串。提供的值: {1}", - "invalid.path.1": "要包含在擴充功能資料夾 ({2}) 中的預期 `contributes.{0}.path` ({1})。這可能會使擴充功能無法移植。", - "reqid": "`contributes.{0}.id` 中的預期字串。提供的值: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "指定在工作台中使用的圖示主題,或設定為 'null' 不顯示任何檔案圖示。", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "依目前選擇的彩色佈景主題覆寫顏色", - "workbenchColors.deprecated": "此設定不再為實驗性,且已被重新命名為 'workbench.colorCustomizations'", - "workbenchColors.deprecatedDescription": "改用'workbench.colorCustomizations'", "editorColors": "依目前選取的色彩佈景主題覆寫編輯器色彩與字型樣式。", "editorColors.comments": "設定註解的色彩與樣式", "editorColors.strings": "設定字串常值的色彩與樣式。", diff --git a/i18n/cht/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/cht/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..e3d8abe8ffe --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/workspace/node/workspaceEditingService.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. +{ + "openWorkspaceConfigurationFile": "開啟工作區組態檔", + "close": "關閉" +} \ No newline at end of file diff --git a/i18n/deu/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/deu/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index 7dc4d240d04..b68dd3a3b2a 100644 --- a/i18n/deu/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/deu/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "z. B. myFile.txt", - "activeEditorMedium": "e.g. myFolder/myFile.txt", - "activeEditorLong": "e.g. /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "z. B. meinOrdner1, meinOrdner2, meinOrdner3", - "rootPath": "z. B. /Users/Development/myProject", - "folderName": "z. B. meinOrdner", - "folderPath": "z. B. /Users/Development/meinOrdner", + "activeEditorShort": "Der Dateiname (z.B. meineDatei.txt)", + "activeEditorLong": "Der vollständige Pfad der Datei (z.B. /Benutzer/Entwicklung/meinProjekt/meinOrdner/meineDatei.txt)", + "rootName": "Name des Arbeitsbereichs (z.B. meinOrdner oder meinArbeitsberech)", + "rootPath": "Dateipfad des Arbeitsbereichs (z.B. /Benutzer/Entwicklung/meinArbeitsbereich)", "appName": "z. B. VS Code", "dirty": "Ein geänderter Indikator, wenn der aktive Editor geändert wurde", "separator": "Ein bedingtes Trennzeichen (' - '), das nur in der Umgebung von Variablen mit Werten angezeigt wird", diff --git a/i18n/deu/extensions/emmet/package.i18n.json b/i18n/deu/extensions/emmet/package.i18n.json index aef483c7df2..7c71a6c1109 100644 --- a/i18n/deu/extensions/emmet/package.i18n.json +++ b/i18n/deu/extensions/emmet/package.i18n.json @@ -28,13 +28,6 @@ "command.incrementNumberByTen": "Um 10 erhöhen", "command.decrementNumberByTen": "Um 10 verringern", "emmetSyntaxProfiles": "Definieren Sie das Profil für die angegebene Syntax, oder verwenden Sie Ihr eigenes Profil mit bestimmten Regeln.", - "emmetExclude": "Ein Array von Sprachen, in dem Emmet-Abkürzungen nicht erweitert werden sollen.", - "emmetExtensionsPath": "Pfad zu einem Ordner mit Emmet-Profilen und Ausschnitten.", - "emmetShowExpandedAbbreviation": "Zeigt erweiterte Emmet-Abkürzungen als Vorschläge an.\nDie Option inMarkupAndStylesheetFilesOnly gilt für HTML, HAML, Jade, Slim, XML, XSL, CSS, SCSS, Sass, Less und Stylus.\nDie Option \"always\" gilt unabhängig vom Markup/CSS für alle Teile der Datei.", - "emmetShowAbbreviationSuggestions": "Zeigt mögliche Emmet-Abkürzungen als Vorschläge an. Diese Option gilt nicht in Stylesheets oder wenn emmet.showExpandedAbbreviation auf \"never\" festgelegt ist.", - "emmetIncludeLanguages": "Aktivieren Sie Emmet-Abkürzungen in Sprachen, die nicht standardmäßig unterstützt werden. Fügen Sie hier ein Mapping zwischen der Sprache und der von Emmet unterstützten Sprache hinzu.\nBeispiel: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", - "emmetVariables": "In Emmet-Ausschnitten zu verwendende Variablen", - "emmetTriggerExpansionOnTab": "Wenn aktiviert, werden Emmet-Abkürzungen beim Drücken der TAB-TASTE erweitert.", "emmetPreferences": "Einstellungen, die zum Ändern des Verhaltens einiger Aktionen und Konfliktlöser von Emmet verwendet werden.", "emmetPreferencesIntUnit": "Standardeinheit für Integerwerte", "emmetPreferencesFloatUnit": "Standardeinheit für Floatwerte", @@ -43,6 +36,5 @@ "emmetPreferencesStylusAfter": "Symbol, das beim Erweitern von CSS-Abkürzungen in Stylus-Dateien am Ende der CSS-Eigenschaft eingefügt werden soll", "emmetPreferencesCssBetween": "Symbol, das beim Erweitern von CSS-Abkürzungen zwischen der CSS-Eigenschaft und dem Wert eingefügt werden soll", "emmetPreferencesSassBetween": "Symbol, das beim Erweitern von CSS-Abkürzungen in Sass-Dateien zwischen der CSS-Eigenschaft und dem Wert eingefügt werden soll", - "emmetPreferencesStylusBetween": "Symbol, das beim Erweitern von CSS-Abkürzungen in Stylus-Dateien zwischen der CSS-Eigenschaft und dem Wert eingefügt werden soll", - "emmetShowSuggestionsAsSnippets": "Bei TRUE werden die Emmet-Vorschläge als Ausschnitte angezeigt, mit denen Sie sie der editor.snippetSuggestions-Einstellung entsprechend anordnen können." + "emmetPreferencesStylusBetween": "Symbol, das beim Erweitern von CSS-Abkürzungen in Stylus-Dateien zwischen der CSS-Eigenschaft und dem Wert eingefügt werden soll" } \ No newline at end of file diff --git a/i18n/deu/extensions/git/out/commands.i18n.json b/i18n/deu/extensions/git/out/commands.i18n.json index c3d3a5519b7..3f2fcad2989 100644 --- a/i18n/deu/extensions/git/out/commands.i18n.json +++ b/i18n/deu/extensions/git/out/commands.i18n.json @@ -12,8 +12,9 @@ "cloning": "Git-Repository wird geklont...", "openrepo": "Repository öffnen", "proposeopen": "Möchten Sie das geklonte Repository öffnen?", - "path to init": "Ordnerpfad", - "provide path": "Geben Sie einen Ordnerpfad zum Initialisieren eines Git-Repositorys an.", + "init repo": "Repository initialisieren", + "create repo": "Repository initialisieren", + "are you sure": "Erstellt ein Git-Repository unter '{0}'. Sind Sie sicher das Sie weiterfahren möchten?", "HEAD not available": "Es ist keine HEAD-Version von \"{0}\" verfügbar.", "confirm stage files with merge conflicts": "Möchten Sie {0} Dateien mit Mergingkonflikten bereitstellen?", "confirm stage file with merge conflicts": "Möchten Sie {0} mit Mergingkonflikten bereitstellen?", diff --git a/i18n/deu/extensions/git/out/repository.i18n.json b/i18n/deu/extensions/git/out/repository.i18n.json index eeff60b713c..aa81d1a2b07 100644 --- a/i18n/deu/extensions/git/out/repository.i18n.json +++ b/i18n/deu/extensions/git/out/repository.i18n.json @@ -21,6 +21,8 @@ "deleted by us": "Gelöscht von uns", "both added": "Beide hinzugefügt", "both modified": "Beide geändert", + "untracked, short": "U", + "modified, short": "M", "commit": "Commit", "merge changes": "Änderungen zusammenführen", "staged changes": "Bereitgestellte Änderungen", diff --git a/i18n/deu/extensions/git/package.i18n.json b/i18n/deu/extensions/git/package.i18n.json index 4b4b197df1a..42eb8374ef1 100644 --- a/i18n/deu/extensions/git/package.i18n.json +++ b/i18n/deu/extensions/git/package.i18n.json @@ -15,6 +15,8 @@ "command.stageAll": "Alle Änderungen bereitstellen", "command.stageSelectedRanges": "Gewählte Bereiche bereitstellen", "command.revertSelectedRanges": "Ausgewählte Bereiche zurücksetzen", + "command.stageChange": "Änderung bereitstellen", + "command.revertChange": "Änderung zurücksetzen", "command.unstage": "Bereitstellung der Änderungen aufheben", "command.unstageAll": "Bereitstellung aller Änderungen aufheben", "command.unstageSelectedRanges": "Bereitstellung gewählter Bereiche aufheben", diff --git a/i18n/deu/extensions/typescript/package.i18n.json b/i18n/deu/extensions/typescript/package.i18n.json index 227e220881d..3725f9400c0 100644 --- a/i18n/deu/extensions/typescript/package.i18n.json +++ b/i18n/deu/extensions/typescript/package.i18n.json @@ -44,7 +44,6 @@ "typescript.npm": "Gibt den Pfad zur ausführbaren NPM-Datei an, die für die automatische Typerfassung verwendet wird. Hierfür ist TypeScript 2.3.4 oder höher erforderlich.", "typescript.check.npmIsInstalled": "Überprüfen Sie, ob NPM für die automatische Typerfassung installiert ist.", "javascript.nameSuggestions": "Das Einbeziehen eindeutiger Namen von der Datei in der JavaScript-Vorschlagsliste aktivieren/deaktivieren.", - "typescript.tsc.autoDetect": "Steuert, ob die automatische Erkennung von tsc-Tasks aktiviert oder deaktiviert ist.\n", "typescript.problemMatchers.tsc.label": "TypeScript-Probleme", "typescript.problemMatchers.tscWatch.label": "TypeScript-Probleme (Überwachungsmodus)" } \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/deu/src/vs/editor/contrib/find/browser/findWidget.i18n.json index bbffc013c9e..1a791fe2241 100644 --- a/i18n/deu/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/deu/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,6 @@ "label.replaceButton": "Ersetzen", "label.replaceAllButton": "Alle ersetzen", "label.toggleReplaceButton": "Ersetzen-Modus wechseln", - "title.matchesCountLimit": "Nur die ersten 999 Ergebnisse werden hervorgehoben, alle Suchvorgänge beziehen sich aber auf den gesamten Text.", "label.matchesLocation": "{0} von {1}", "label.noResults": "Keine Ergebnisse" } \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/deu/src/vs/editor/contrib/find/common/findController.i18n.json index a704a485374..966c9eafe93 100644 --- a/i18n/deu/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/deu/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "Nächste Auswahl suchen", "previousSelectionMatchFindAction": "Vorherige Auswahl suchen", "startReplace": "Ersetzen", - "addSelectionToNextFindMatch": "Auswahl zur nächsten Übereinstimmungssuche hinzufügen", - "addSelectionToPreviousFindMatch": "Letzte Auswahl zu vorheriger Übereinstimmungssuche hinzufügen", - "moveSelectionToNextFindMatch": "Letzte Auswahl in nächste Übereinstimmungssuche verschieben", - "moveSelectionToPreviousFindMatch": "Letzte Auswahl in vorherige Übereinstimmungssuche verschieben", - "selectAllOccurrencesOfFindMatch": "Alle Vorkommen auswählen und Übereinstimmung suchen", - "changeAll.label": "Alle Vorkommen ändern", "showNextFindTermAction": "Nächsten Suchbegriff anzeigen", "showPreviousFindTermAction": "Vorherigen Suchbegriff anzeigen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/deu/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 58edd06f8f7..66385866668 100644 --- a/i18n/deu/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/deu/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Cursor oberhalb hinzufügen", "mutlicursor.insertBelow": "Cursor unterhalb hinzufügen", - "mutlicursor.insertAtEndOfEachLineSelected": "Cursor an Zeilenenden hinzufügen" + "mutlicursor.insertAtEndOfEachLineSelected": "Cursor an Zeilenenden hinzufügen", + "addSelectionToNextFindMatch": "Auswahl zur nächsten Übereinstimmungssuche hinzufügen", + "addSelectionToPreviousFindMatch": "Letzte Auswahl zu vorheriger Übereinstimmungssuche hinzufügen", + "moveSelectionToNextFindMatch": "Letzte Auswahl in nächste Übereinstimmungssuche verschieben", + "moveSelectionToPreviousFindMatch": "Letzte Auswahl in vorherige Übereinstimmungssuche verschieben", + "selectAllOccurrencesOfFindMatch": "Alle Vorkommen auswählen und Übereinstimmung suchen", + "changeAll.label": "Alle Vorkommen ändern" } \ No newline at end of file diff --git a/i18n/deu/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/deu/src/vs/platform/theme/common/colorRegistry.i18n.json index a26d1d4b935..b1b17e724eb 100644 --- a/i18n/deu/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/deu/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "Ungültiges Farbformat. Verwenden Sie #RGB, #RGBA, #RRGGBB oder #RRGGBBAA.", "schema.colors": "In der Workbench verwendete Farben.", "foreground": "Allgemeine Vordergrundfarbe. Diese Farbe wird nur verwendet, wenn sie nicht durch eine Komponente überschrieben wird.", "errorForeground": "Allgemeine Vordergrundfarbe. Diese Farbe wird nur verwendet, wenn sie nicht durch eine Komponente überschrieben wird.", diff --git a/i18n/deu/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/deu/src/vs/workbench/browser/actions/workspaceActions.i18n.json index d630b8be8f2..fd7afc2d998 100644 --- a/i18n/deu/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -9,14 +9,17 @@ "addFolderToWorkspace": "Ordner zum Arbeitsbereich hinzufügen...", "add": "&&Hinzufügen", "addFolderToWorkspaceTitle": "Ordner zum Arbeitsbereich hinzufügen", + "globalRemoveFolderFromWorkspace": "Ordner aus dem Arbeitsbereich entfernen...", "newWorkspace": "Neuer Arbeitsbereich...", "select": "Au&&swählen", "selectWorkspace": "Ordner für den Arbeitsbereich auswählen", "removeFolderFromWorkspace": "Ordner aus dem Arbeitsbereich entfernen", + "openFolderSettings": "Ordnereinstellungen öffnen", "saveWorkspaceAsAction": "Arbeitsbereich speichern unter...", "save": "&&Speichern", "saveWorkspace": "Arbeitsbereich speichern", "openWorkspaceAction": "Arbeitsbereich öffnen...", "openWorkspaceConfigFile": "Konfigurationsdatei des Arbeitsbereichs öffnen", + "openFolderAsWorkspaceInNewWindow": "Ordner als Arbeitsbereich in neuem Fenster öffnen", "workspaceFolderPickerPlaceholder": "Arbeitsbereichsordner auswählen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index 419bdb09927..4bf40f11e3b 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Aktivitätsleiste ausblenden", - "activityBarAriaLabel": "Umschaltung der aktiven Ansicht", "globalActions": "Globale Aktionen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..a2d382d743c --- /dev/null +++ b/i18n/deu/src/vs/workbench/browser/parts/compositebar/compositeBar.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. +{ + "activityBarAriaLabel": "Umschaltung der aktiven Ansicht" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..3e71b2d6ba4 --- /dev/null +++ b/i18n/deu/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "Zusätzliche Ansichten", + "numberBadge": "{0} ({1})", + "manageExtension": "Erweiterung verwalten", + "titleKeybinding": "{0} ({1})", + "toggle": "Ansichtsfixierung umschalten" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 7ce49db8855..0812b9299a4 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "Editoren in zweiter Gruppe anzeigen", "groupThreePicker": "Editoren in dritter Gruppe anzeigen", "allEditorsPicker": "Alle geöffneten Editoren anzeigen", - "view": "Anzeigen" + "view": "Anzeigen", + "file": "Datei" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index f86613230bf..cda94be8348 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "Der Befehl \"{0}\" ist zurzeit nicht aktiviert und kann nicht ausgeführt werden.", "manageExtension": "Erweiterung verwalten" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/deu/src/vs/workbench/electron-browser/main.contribution.i18n.json index ac447a68175..3cc4c47add8 100644 --- a/i18n/deu/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,18 +10,14 @@ "workspaces": "Arbeitsbereiche", "developer": "Entwickler", "showEditorTabs": "Steuert, ob geöffnete Editoren auf Registerkarten angezeigt werden sollen.", - "workbench.editor.labelFormat.default": "Zeigt den Namen der Datei an. Wenn Registerkarten aktiviert sind und zwei Dateien den gleichen Namen in einer Gruppe haben, werden die besonderen Abschnitte des Pfads jeder Datei hinzugefügt. Wenn Registerkarten deaktiviert sind, wird der Pfad zum Arbeitsbereich-Stammverzeichnis angezeigt, wenn der Editor aktiv ist.", "workbench.editor.labelFormat.short": "Den Namen der Datei anzeigen, gefolgt von dessen Verzeichnisnamen.", - "workbench.editor.labelFormat.medium": "Zeigt den Namen der Datei an, gefolgt vom Pfad zum Arbeitsbereich-Stammverzeichnis.", "workbench.editor.labelFormat.long": "Zeigt den Namen der Datei an, gefolgt von ihrem absoluten Pfad.", "tabDescription": "Steuert das Format der Beschriftung für einen Editor. Wenn Sie diese Einstellung ändern, ist beispielsweise der Speicherort einer Datei besser ersichtlich:\n- kurz: \"parent\"\n- mittel: \"workspace/src/parent\"\n- lang: \"/home/user/workspace/src/parent\"\n- Standard: \".../parent\", wenn eine andere Registerkarte denselben Titel hat, oder den relativen Arbeitsbereichspfad, wenn Registerkarten deaktiviert sind.", "editorTabCloseButton": "Steuert die Position der Schließen-Schaltflächen der Editor-Registerkarten oder deaktiviert sie bei der Einstellung \"off\".", "showIcons": "Steuert, ob geöffnete Editoren mit einem Symbol angezeigt werden sollen. Hierzu muss auch ein Symboldesign aktiviert werden.", "enablePreview": "Steuert, ob geöffnete Editoren als Vorschau angezeigt werden. Vorschau-Editoren werden wiederverwendet, bis sie gespeichert werden (z. B. über Doppelklicken oder Bearbeiten), und sie werden mit kursivem Schriftschnitt angezeigt.", "enablePreviewFromQuickOpen": "Steuert, ob geöffnete Editoren aus Quick Open als Vorschau angezeigt werden. Vorschau-Editoren werden wiederverwendet, bis sie gespeichert werden (z. B. über Doppelklicken oder Bearbeiten).", - "editorOpenPositioning": "Steuert, wo Editoren geöffnet werden. Wählen Sie \"Links\" oder \"Rechts\" aus, um Editoren links oder rechts vom aktuellen aktiven Editor zu öffnen. Wählen Sie \"Erster\" oder \"Letzter\" aus, um Editoren unabhängig vom aktuell aktiven Editor zu öffnen.", "revealIfOpen": "Steuert, ob ein geöffneter Editor in einer der sichtbaren Gruppen angezeigt wird. Ist diese Option deaktiviert, wird ein Editor vorzugsweise in der aktuell aktiven Editorgruppe geöffnet. Ist diese Option aktiviert, wird ein bereits geöffneter Editor angezeigt und nicht in der aktuell aktiven Editorgruppe erneut geöffnet. In einigen Fällen wird diese Einstellung ignoriert, z. B. wenn das Öffnen eines Editors in einer bestimmten Gruppe oder neben der aktuell aktiven Gruppe erzwungen wird.", - "commandHistory": "Steuert, ob die Anzahl zuletzt verwendeter Befehle im Verlauf für die Befehlspalette gespeichert wird. Legen Sie diese Option auf 0 fest, um den Befehlsverlauf zu deaktivieren.", "preserveInput": "Steuert, ob die letzte typisierte Eingabe in die Befehlspalette beim nächsten Öffnen wiederhergestellt wird.", "closeOnFocusLost": "Steuert, ob Quick Open automatisch geschlossen werden soll, sobald das Feature den Fokus verliert.", "openDefaultSettings": "Steuert, ob beim Öffnen der Einstellungen auch ein Editor geöffnet wird, der alle Standardeinstellungen anzeigt.", @@ -50,7 +46,6 @@ "restoreWindows": "Steuert, wie Fenster nach einem Neustart erneut geöffnet werden. Wählen Sie \"none\", um immer mit einem leeren Arbeitsbereich zu beginnen, \"one\", um das zuletzt verwendete Fenster erneut zu öffnen, \"folders\", um alle Fenster, in denen Ordner geöffnet waren, erneut zu öffnen, oder \"all\", um alle Fenster der letzten Sitzung erneut zu öffnen.", "restoreFullscreen": "Steuert, ob ein Fenster im Vollbildmodus wiederhergestellt wird, wenn es im Vollbildmodus beendet wurde.", "zoomLevel": "Passen Sie den Zoomfaktor des Fensters an. Die ursprüngliche Größe ist 0. Jede Inkrementierung nach oben (z. B. 1) oder unten (z. B. -1) stellt eine Vergrößerung bzw. Verkleinerung um 20 % dar. Sie können auch Dezimalwerte eingeben, um den Zoomfaktor genauer anzupassen.", - "title": "Steuert den Fenstertitel basierend auf dem aktiven Editor. Variablen werden abhängig vom Kontext ersetzt:\n${activeEditorShort}: z. B. meineDatei.txt\n${activeEditorMedium}: z. B. meinOrdner/meineDatei.txt\n${activeEditorLong}: z. B. /Users/Development/meinProjekt/meinOrdner/meineDatei.txt\n${folderName}: z. B. \nmeinOrdner${folderPath}: z. B. /Users/Development/meinOrdner\n${rootName}: z. B. meinOrdner1, meinOrdner2, meinOrdner3\n${rootPath}: z. B. /Users/Development/meinArbeitsbereich\n${appName}: z. B. VS Code\n${dirty}: ein Änderungsindikator, wenn der aktive Editor geändert wurde\n${separator}: ein bedingtes Trennzeichen (\" - \"), das nur angezeigt wird, wenn es zwischen Variablen mit Werten steht", "window.newWindowDimensions.default": "Öffnet neue Fenster in der Mitte des Bildschirms.", "window.newWindowDimensions.inherit": "Öffnet neue Fenster mit den gleichen Abmessungen wie das letzte aktive Fenster.", "window.newWindowDimensions.maximized": "Öffnet neue Fenster maximiert.", diff --git a/i18n/deu/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index be338b43ea2..b06443ae9ef 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, Debugging", "debugAriaLabel": "Geben Sie den Namen einer auszuführenden Startkonfiguration ein.", + "addConfigTo": "Konfiguration hinzufügen ({0})...", + "addConfiguration": "Konfiguration hinzufügen...", "noConfigurationsMatching": "Keine übereinstimmenden Debugkonfigurationen", "noConfigurationsFound": "Keine Debugkonfiguration gefunden. Erstellen Sie die Datei \"launch.json\"." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..5345ba65476 --- /dev/null +++ b/i18n/deu/src/vs/workbench/parts/debug/browser/debugStatus.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. +{ + "debug": "Debuggen" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/deu/src/vs/workbench/parts/debug/browser/debugViewlet.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/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 427b79c92de..1c098b69622 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 @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "Konfigurationen zum Generieren der anfänglichen Datei \"launch.json\".", "vscode.extension.contributes.debuggers.languages": "Liste der Sprachen, für die die Debugerweiterung als \"Standarddebugger\" angesehen werden kann", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Wenn dies festgelegt ist, ruft der VS Code diesen Befehl auf, um den ausführbaren Pfad des Debugadapters und die zu übergebenden Argumente zu bestimmen.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Wenn dies festgelegt ist, ruft der VS Code diesen Befehl für die Debug- oder Ausführungsaktionen aus, die für diese Erweiterung bestimmt sind.", "vscode.extension.contributes.debuggers.configurationSnippets": "Snippets zum Hinzufügen neuer Konfigurationen in \"launch.json\".", "vscode.extension.contributes.debuggers.configurationAttributes": "JSON-Schemakonfigurationen zum Überprüfen von \"launch.json\".", "vscode.extension.contributes.debuggers.windows": "Windows-spezifische Einstellungen.", diff --git a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 85809743b85..2cbcf3ae529 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,10 +12,7 @@ "breakpointRemoved": "Der Haltepunkt wurde entfernt. Zeile {0}, Datei \"{1}\".", "compoundMustHaveConfigurations": "Für den Verbund muss das Attribut \"configurations\" festgelegt werden, damit mehrere Konfigurationen gestartet werden können.", "configMissing": "Konfiguration \"{0}\" fehlt in \"launch.json\".", - "debugRequestNotSupported": "Die ausgewählte Debugkonfiguration verfügt über einen nicht unterstützten Attributwert \"{0}\": \"{1}\".", - "debugRequesMissing": "Das Attribut \"{0}\" fehlt in der ausgewählten Debugkonfiguration.", "debugTypeNotSupported": "Der konfigurierte Debugtyp \"{0}\" wird nicht unterstützt.", - "debugTypeMissing": "Fehlende Eigenschaft \"type\" für die ausgewählte Startkonfiguration.", "preLaunchTaskErrors": "Buildfehler während preLaunchTask \"{0}\".", "preLaunchTaskError": "Buildfehler während preLaunchTask \"{0}\".", "preLaunchTaskExitCode": "Der preLaunchTask \"{0}\" wurde mit dem Exitcode {1} beendet.", diff --git a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index dded802b64c..fc3e3434fee 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -7,6 +7,5 @@ "stateCapture": "Der Objektstatus wird aus der ersten Auswertung erfasst.", "replVariableAriaLabel": "Variable {0} besitzt den Wert {1}, Read Eval Print-Loop, Debuggen", "replExpressionAriaLabel": "Ausdruck {0} besitzt den Wert {1}, Read Eval Print-Loop, Debuggen", - "replValueOutputAriaLabel": "{0}, Read Eval Print-Loop, Debuggen", - "replKeyValueOutputAriaLabel": "Ausgabevariable {0} besitzt den Wert {1}, Read Eval Print-Loop, Debuggen" + "replValueOutputAriaLabel": "{0}, Read Eval Print-Loop, Debuggen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index bc53701d4ae..46de1e8541a 100644 --- a/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "Dateien", + "filesCategory": "Datei", "revealInSideBar": "In Seitenleiste anzeigen", "acceptLocalChanges": "Änderungen verwenden und Datenträgerinhalte überschreiben", "revertLocalChanges": "Änderungen verwerfen und Datenträgerinhalte wiederherstellen" diff --git a/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 9bbadf5a16f..241386f0b5c 100644 --- a/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "Möchten Sie \"{0}\" wirklich löschen?", "undoBin": "Die Wiederherstellung kann aus dem Papierkorb erfolgen.", "undoTrash": "Die Wiederherstellung kann aus dem Papierkorb erfolgen.", + "doNotAskAgain": "Nicht erneut fragen", "confirmDeleteMessageFolder": "Möchten Sie \"{0}\" samt Inhalt wirklich endgültig löschen?", "confirmDeleteMessageFile": "Möchten Sie \"{0}\" wirklich endgültig löschen?", "irreversible": "Diese Aktion kann nicht rückgängig gemacht werden.", @@ -37,8 +38,6 @@ "openToSide": "Zur Seite öffnen", "compareSource": "Für Vergleich auswählen", "globalCompareFile": "Aktive Datei vergleichen mit...", - "pickHistory": "Zuvor geöffnete Datei für den Vergleich auswählen", - "unableToFileToCompare": "Die ausgewählte Datei kann nicht mit \"{0}\" verglichen werden.", "openFileToCompare": "Zuerst eine Datei öffnen, um diese mit einer anderen Datei zu vergleichen", "compareWith": "'{0}' mit '{1}' vergleichen", "compareFiles": "Dateien vergleichen", @@ -47,7 +46,7 @@ "saveAs": "Speichern unter...", "saveAll": "Alle speichern", "saveAllInGroup": "Alle in der Gruppe speichern", - "saveFiles": "Geänderte Dateien speichern", + "saveFiles": "Alle Dateien speichern", "revert": "Datei wiederherstellen", "focusOpenEditors": "Fokus auf Ansicht \"Geöffnete Editoren\"", "focusFilesExplorer": "Fokus auf Datei-Explorer", diff --git a/i18n/deu/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 93f045f545a..e396ef8d753 100644 --- a/i18n/deu/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -40,6 +40,8 @@ "dynamicHeight": "Steuert, ob sich die Höhe des Abschnitts \"Geöffnete Editoren\" dynamisch an die Anzahl der Elemente anpassen soll.", "autoReveal": "Steuert, ob der Explorer Dateien beim Öffnen automatisch anzeigen und auswählen soll.", "enableDragAndDrop": "Steuert, ob der Explorer das Verschieben von Dateien und Ordnern mithilfe von Drag Drop zulassen soll.", + "confirmDragAndDrop": "Steuert, ob der Explorer um Bestätigung bitten soll, beim Verschieben von Dateien oder Ordnern per Ziehen und Ablegen.", + "confirmDelete": "Steuert, ob der Explorer um Bestätigung bitten soll, wenn Sie eine Datei über den Papierkorb löschen.", "sortOrder.default": "Dateien und Ordner werden nach ihren Namen in alphabetischer Reihenfolge sortiert. Ordner werden vor Dateien angezeigt. ", "sortOrder.mixed": "Dateien und Ordner werden nach ihren Namen in alphabetischer Reihenfolge sortiert. Dateien und Ordner werden vermischt angezeigt.", "sortOrder.filesFirst": "Dateien und Ordner werden nach ihren Namen in alphabetischer Reihenfolge sortiert. Dateien werden vor Ordnern angezeigt.", diff --git a/i18n/deu/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/deu/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index e04313a8208..e3de54fe532 100644 --- a/i18n/deu/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "Es ist kein Ordner geöffnet.", "explorerSection": "Datei-Explorer-Abschnitt", - "noWorkspaceHelp": "Sie haben noch keinen Ordner geöffnet.", + "noWorkspaceHelp": "Sie haben noch keinen Ordner zum Arbeitsbereich hinzugefügt.", + "addFolder": "Ordner hinzufügen", + "noFolderHelp": "Sie haben noch keinen Ordner geöffnet.", "openFolder": "Ordner öffnen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/deu/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index 31a534a16fa..972dbbe86f2 100644 --- a/i18n/deu/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -4,12 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "canNotResolve": "Ordner {0} kann nicht aufgelöst werden.", "fileInputAriaLabel": "Geben Sie den Dateinamen ein. Drücken Sie zur Bestätigung die EINGABETASTE oder ESC, um den Vorgang abzubrechen.", "filesExplorerViewerAriaLabel": "{0}, Datei-Explorer", "dropFolders": "Möchten Sie die Ordner zum Arbeitsbereich hinzufügen?", "dropFolder": "Möchten Sie den Ordner zum Arbeitsbereich hinzufügen?", "addFolders": "&&Ordner hinzufügen", "addFolder": "&&Ordner hinzufügen", + "confirmMove": "Sind Sie sicher, dass Sie \"{0}\" verschieben möchten?", + "doNotAskAgain": "Nicht erneut fragen", "confirmOverwriteMessage": "{0} ist im Zielordner bereits vorhanden. Möchten Sie das Element ersetzen?", "irreversible": "Diese Aktion kann nicht rückgängig gemacht werden.", "replaceButtonLabel": "&&Ersetzen" diff --git a/i18n/deu/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/deu/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..cf58a240413 --- /dev/null +++ b/i18n/deu/src/vs/workbench/parts/markers/browser/markersFileDecorations.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. +{ + "label": "Probleme", + "tooltip.1": "1 Problem in dieser Datei", + "tooltip.N": "{0} Probleme in dieser Datei", + "markers.showOnFile": "Fehler & Warnungen auf Dateien und Ordnern anzeigen." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index c7f0245455c..b100f612513 100644 --- a/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "Platzieren Sie Ihre Einstellungen hier, um die Standardeinstellungen zu überschreiben.", - "errorInvalidConfiguration": "Einstellungen können nicht geschrieben werden. Öffnen Sie die Datei, um Fehler/Warnungen in der Datei zu korrigieren. Versuchen Sie es anschließend noch mal.", "emptyWorkspaceSettingsHeader": "Platzieren Sie Ihre Einstellungen hier, um die Benutzereinstellungen zu überschreiben.", "emptyFolderSettingsHeader": "Platzieren Sie Ihre Ordnereinstellungen hier, um die Einstellungen in den Arbeitsbereichseinstellungen zu überschreiben.", "defaultFolderSettingsTitle": "Standardordnereinstellungen", diff --git a/i18n/deu/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/deu/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 321ccab5284..77769778060 100644 --- a/i18n/deu/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "Der Befehl \"{0}\" ist im aktuellen Kontext nicht aktiviert.", "recentlyUsed": "zuletzt verwendet", "morecCommands": "andere Befehle", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "Keine übereinstimmenden Befehle." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/deu/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index 96756d61e40..bd63f3fb9cd 100644 --- a/i18n/deu/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,6 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "{0} von {1} Änderungen", + "change": "{0} von {1} Änderung", + "show previous change": "Vorherige Änderung anzeigen", + "show next change": "Nächste Änderung anzeigen", "editorGutterModifiedBackground": "Hintergrundfarbe für die Editor-Leiste für Zeilen, die geändert wurden.", "editorGutterAddedBackground": "Hintergrundfarbe für die Editor-Leiste für Zeilen, die hinzugefügt wurden.", "editorGutterDeletedBackground": "Hintergrundfarbe für die Editor-Leiste für Zeilen, die gelöscht wurden.", diff --git a/i18n/deu/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index 44f81eb9c7f..b36930b05c6 100644 --- a/i18n/deu/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -17,7 +17,6 @@ "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.", "exclude.when": "Zusätzliche Überprüfung der gleichgeordneten Elemente einer entsprechenden Datei. Verwenden Sie \"$(basename)\" als Variable für den entsprechenden Dateinamen.", - "useRipgrep": "Steuert, ob \"ripgrep\" in der Textsuche verwendet wird", "useIgnoreFilesByDefault": "Steuert, ob bei der Suche in einem neuen Arbeitsbereich standardmäßig GITIGNORE- und IGNORE-Dateien verwendet werden sollen.", "search.quickOpen.includeSymbols": "Konfigurieren Sie diese Option, um Ergebnisse aus einer globalen Symbolsuche in die Dateiergebnisse für Quick Open einzuschließen." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/deu/src/vs/workbench/parts/search/browser/searchActions.i18n.json index b16c9eacc2a..94d13d8f553 100644 --- a/i18n/deu/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -19,7 +19,6 @@ "ClearSearchResultsAction.label": "Suchergebnisse löschen", "FocusNextSearchResult.label": "Fokus auf nächstes Suchergebnis", "FocusPreviousSearchResult.label": "Fokus auf vorheriges Suchergebnis", - "RemoveAction.label": "Entfernen", "file.replaceAll.label": "Alle ersetzen", "match.replace.label": "Ersetzen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/deu/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 016b1854df2..1d0d27e52b0 100644 --- a/i18n/deu/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,8 +10,8 @@ "vscode.extension.contributes.snippets": "Trägt Codeausschnitte bei.", "vscode.extension.contributes.snippets-language": "Der Sprachbezeichner, für den dieser Codeausschnitt beigetragen wird.", "vscode.extension.contributes.snippets-path": "Der Pfad der Codeausschnittdatei. Der Pfad ist relativ zum Erweiterungsordner und beginnt normalerweise mit \". /snippets/\".", - "badFile": "Die Ausschnittsdatei \"{0}\" konnte nicht gelesen werden.", "badVariableUse": "Das \"{0}\"-Snippet verwirrt wahrscheinlich Snippet-Variablen und Snippet-Paltzhalter. Schaue https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax für weitere Informationen.", + "badFile": "Die Ausschnittsdatei \"{0}\" konnte nicht gelesen werden.", "source.snippet": "Benutzercodeausschnitt", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 5f9f1928ae6..09fd787097a 100644 --- a/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -14,6 +14,7 @@ "runningTasks": "Aktive Aufgaben anzeigen", "tasks": "Aufgaben", "TaskSystem.noHotSwap": "Zum Ändern des Aufgabenausführungsmoduls mit einem aktiven Task muss das Fenster erneut geladen werden.", + "TaskServer.folderIgnored": "Der Ordner {0} wird ignoriert, da er Aufgabenversion 0.1.0 verwendet", "TaskService.noBuildTask1": "Keine Buildaufgabe definiert. Markieren Sie eine Aufgabe mit 'isBuildCommand' in der tasks.json-Datei.", "TaskService.noBuildTask2": "Es ist keine Buildaufgabe definiert. Markieren Sie eine Aufgabe in der Datei \"tasks.json\" als \"Buildgruppe\". ", "TaskService.noTestTask1": "Keine Testaufgabe definiert. Markieren Sie eine Aufgabe mit 'isTestCommand' in der tasks.json-Datei.", diff --git a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 7d62688f024..93a8b04286a 100644 --- a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -16,7 +16,6 @@ "workbench.action.terminal.new.short": "Neues Terminal", "workbench.action.terminal.focus": "Fokus im Terminal", "workbench.action.terminal.focusNext": "Fokus im nächsten Terminal", - "workbench.action.terminal.focusAtIndex": "Terminal {0} im Fokus", "workbench.action.terminal.focusPrevious": "Fokus im vorherigen Terminal", "workbench.action.terminal.paste": "In aktives Terminal einfügen", "workbench.action.terminal.DefaultShell": "Standardshell auswählen", diff --git a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 558f228c1f1..cf9ef31e248 100644 --- a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Kopieren", - "createNewTerminal": "Neues Terminal", "paste": "Einfügen", "selectAll": "Alles auswählen", "clear": "Löschen" diff --git a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index e01f30f61a5..ac6f1dfc78c 100644 --- a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "OK, nicht mehr anzeigen", "terminal.integrated.chooseWindowsShell": "Wählen Sie Ihre bevorzugte Terminalshell. Sie können diese später in Ihren Einstellungen ändern.", "terminalService.terminalCloseConfirmationSingular": "Eine aktive Terminalsitzung ist vorhanden. Möchten Sie sie beenden?", - "terminalService.terminalCloseConfirmationPlural": "{0} aktive Terminalsitzungen sind vorhanden. Möchten Sie sie beenden?", - "yes": "Ja" + "terminalService.terminalCloseConfirmationPlural": "{0} aktive Terminalsitzungen sind vorhanden. Möchten Sie sie beenden?" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/deu/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..ce08826d007 --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,22 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.configuration.title": "Eine Zusammenfassung der Einstellungen. Diese Bezeichnung wird in der Einstellungsdatei als trennender Kommentar verwendet.", + "vscode.extension.contributes.configuration.properties": "Die Beschreibung der Konfigurationseigenschaften.", + "scope.window.description": "Fensterspezifische Konfiguration, die in den Benutzer- oder Arbeitsbereichseinstellungen konfiguriert werden kann.", + "scope.resource.description": "Ressourcenspezifische Konfiguration, die in den Benutzer-, Arbeitsbereichs- oder Ordnereinstellungen konfiguriert werden kann.", + "scope.description": "Bereich, in dem die Konfiguration gültig ist. Verfügbare Gültigkeitsbereiche sind \"window\" und \"resource\".", + "vscode.extension.contributes.configuration": "Trägt Konfigurationseigenschaften bei.", + "invalid.title": "configuration.title muss eine Zeichenfolge sein.", + "vscode.extension.contributes.defaultConfiguration": "Trägt zu Konfigurationeinstellungen des Standard-Editors für die jeweilige Sprache bei.", + "invalid.properties": "\"configuration.properties\" muss ein Objekt sein.", + "invalid.allOf": "\"configuration.allOf\" ist veraltet und sollte nicht mehr verwendet werden. Übergeben Sie stattdessen mehrere Konfigurationsabschnitte als Array an den Beitragspunkt \"configuration\".", + "workspaceConfig.folders.description": "Liste von Ordnern, die in den Arbeitsbereich geladen werden.", + "workspaceConfig.path.description": "Ein Dateipfad, z. B. \" /root/folderA\" oder \"./folderA\" bei einem relativen Pfad, der in Bezug auf den Speicherort der Arbeitsbereichsdatei aufgelöst wird.", + "workspaceConfig.name.description": "Ein optionaler Name für den Ordner.", + "workspaceConfig.extensions.description": "Arbeitsbereichserweiterungen", + "unknownWorkspaceProperty": "Unbekannte Arbeitsbereichs-Konfigurationseigenschaft" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/deu/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/editor/common/editorService.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. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/deu/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index 3628bed2f06..d13ca944626 100644 --- a/i18n/deu/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/deu/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -6,6 +6,7 @@ { "schema.token.settings": "Farben und Stile für das Token.", "schema.token.foreground": "Vordergrundfarbe für das Token.", + "schema.token.background.warning": "Token Hintergrundfarben werden derzeit nicht unterstützt.", "schema.token.fontStyle": "Schriftschnitt der Regel: kursiv, fett und unterstrichen (einzeln oder in Kombination)", "schema.fontStyle.error": "Der Schriftschnitt muss eine Kombination aus \"kursiv\", \"fett\" und \"unterstrichen\" sein.", "schema.properties.name": "Beschreibung der Regel.", diff --git a/i18n/deu/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/deu/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index 86353589189..cce0737bd42 100644 --- a/i18n/deu/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/deu/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "Wenn eine Schriftart verwendet wird: der Schriftgrad als Prozentsatz der Textschriftart. Wenn diese Angabe nicht festgelegt wird, wird standardmäßig die Größe in der Schriftartdefinition verwendet.", "schema.fontId": "Bei Verwendung einer Schriftart: die ID der Schriftart. Wenn diese Angabe nicht festgelegt wird, wird standardmäßig die erste Schriftartdefinition verwendet.", "schema.light": "Optionale Zuordnungen für Dateisymbole in hellen Farbdesigns.", - "schema.highContrast": "Optionale Zuordnungen für Dateisymbole in Farbdesigns mit hohem Kontrast." + "schema.highContrast": "Optionale Zuordnungen für Dateisymbole in Farbdesigns mit hohem Kontrast.", + "schema.hidesExplorerArrows": "Konfiguriert, ob die Datei-Explorer Pfeile ausgeblendet werden sollen, wenn dieses Motiv aktiv ist." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/deu/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..667f131a465 --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.themes": "Contributes textmate color themes.", + "vscode.extension.contributes.themes.id": "Die ID des Symboldesigns wie in den Benutzereinstellungen verwendet.", + "vscode.extension.contributes.themes.label": "Die Bezeichnung des Farbdesigns wie in der Benutzeroberfläche angezeigt.", + "vscode.extension.contributes.themes.uiTheme": "Das Basisdesign, das die Farben um den Editor definiert: \"vs\" ist das helle Farbdesign, \"vs-dark\" das dunkle Farbdesign. \"hc-black\" ist das dunkle Design mit hohem Kontrast.", + "vscode.extension.contributes.themes.path": "Der Pfad der TMTHEME-Datei. Der Pfad ist relativ zum Erweiterungsordner und lautet normalerweise \"./themes/themeFile.tmTheme\".", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "Expected string in `contributes.{0}.path`. Provided value: {1}", + "invalid.path.1": "Es wurde erwartet, dass \"contributes.{0}.path\" ({1}) im Ordner ({2}) der Erweiterung enthalten ist. Dies führt ggf. dazu, dass die Erweiterung nicht portierbar ist." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/deu/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..b0f9faf6b52 --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.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. +{ + "error.cannotparseicontheme": "Problems parsing file icons file: {0}" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/deu/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..65109048ac5 --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "Die ID des Symboldesigns wie in den Benutzereinstellungen verwendet.", + "vscode.extension.contributes.iconThemes.label": "Die Bezeichnung des Symboldesigns wie in der Benutzeroberfläche angezeigt.", + "vscode.extension.contributes.iconThemes.path": "Der Pfad der Symboldesign-Definitionsdatei. Der Pfad ist relativ zum Erweiterungsordner und lautet normalerweise \"./icons/awesome-icon-theme.json\".", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "Expected string in `contributes.{0}.path`. Provided value: {1}", + "reqid": "In \"contributes.{0}.id\" wurde eine Zeichenfolge erwartet. Bereitgestellter Wert: {1}", + "invalid.path.1": "Es wurde erwartet, dass \"contributes.{0}.path\" ({1}) im Ordner ({2}) der Erweiterung enthalten ist. Dies führt ggf. dazu, dass die Erweiterung nicht portierbar ist." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/deu/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index a3137e30eb6..d551e506d69 100644 --- a/i18n/deu/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/deu/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,31 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "Die ID des Symboldesigns wie in den Benutzereinstellungen verwendet.", - "vscode.extension.contributes.themes.label": "Die Bezeichnung des Farbdesigns wie in der Benutzeroberfläche angezeigt.", - "vscode.extension.contributes.themes.uiTheme": "Das Basisdesign, das die Farben um den Editor definiert: \"vs\" ist das helle Farbdesign, \"vs-dark\" das dunkle Farbdesign. \"hc-black\" ist das dunkle Design mit hohem Kontrast.", - "vscode.extension.contributes.themes.path": "Der Pfad der TMTHEME-Datei. Der Pfad ist relativ zum Erweiterungsordner und lautet normalerweise \"./themes/themeFile.tmTheme\".", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "Die ID des Symboldesigns wie in den Benutzereinstellungen verwendet.", - "vscode.extension.contributes.iconThemes.label": "Die Bezeichnung des Symboldesigns wie in der Benutzeroberfläche angezeigt.", - "vscode.extension.contributes.iconThemes.path": "Der Pfad der Symboldesign-Definitionsdatei. Der Pfad ist relativ zum Erweiterungsordner und lautet normalerweise \"./icons/awesome-icon-theme.json\".", "migration.completed": "Den Benutzereinstellungen wurden neue Designeinstellungen hinzugefügt. Sicherung verfügbar unter {0}.", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "In \"contributes.{0}.path\" wurde eine Zeichenfolge erwartet. Bereitgestellter Wert: {1}", - "invalid.path.1": "Es wurde erwartet, dass \"contributes.{0}.path\" ({1}) im Ordner ({2}) der Erweiterung enthalten ist. Dies führt ggf. dazu, dass die Erweiterung nicht portierbar ist.", - "reqid": "In \"contributes.{0}.id\" wurde eine Zeichenfolge erwartet. Bereitgestellter Wert: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "Gibt das in der Workbench verwendete Symboldesign oder \"null\", um keine Dateisymbole anzuzeigen, an.", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "Überschreibt Farben aus dem derzeit ausgewählte Farbdesign.", - "workbenchColors.deprecated": "Diese Einstellung ist nicht mehr experimentell und wurde in \"workbench.colorCustomizations\" umbenannt.", - "workbenchColors.deprecatedDescription": "Verwenden Sie stattdessen \"workbench.colorCustomizations\".", "editorColors": "Überschreibt Editorfarben und den Schriftschnitt aus dem momentan ausgewählten Farbdesign.", "editorColors.comments": "Legt die Farben und Stile für Kommentare fest.", "editorColors.strings": "Legt die Farben und Stile für Zeichenfolgenliterale fest.", diff --git a/i18n/deu/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/deu/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..9bb276f44ac --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/workspace/node/workspaceEditingService.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. +{ + "openWorkspaceConfigurationFile": "Konfigurationsdatei des Arbeitsbereichs öffnen", + "close": "Schließen" +} \ No newline at end of file diff --git a/i18n/esn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/esn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index 6f2a10e46de..0fea08772ca 100644 --- a/i18n/esn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/esn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "p. ej. myFile.txt", - "activeEditorMedium": "e.g. myFolder/myFile.txt", - "activeEditorLong": "e.g. /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "p. ej. myFolder1, myFolder2, myFolder3", - "rootPath": "p. ej. /Users/Development/myProject", - "folderName": "p. ej. myFolder", - "folderPath": "p. ej. /Users/Development/myFolder", + "activeEditorShort": "el nombre del archivo (por ejemplo miarchivo.txt)", + "activeEditorMedium": "la ruta de acceso del archivo relativa a la carpeta del espacio de trabajo (p. ej. miCarpeta/miArchivo.txt)", + "activeEditorLong": "la ruta de acceso completa del archivo (por ejemplo, /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "nombre del área de trabajo (p. ej. myFolder o myWorkspace)", + "rootPath": "ruta del archivo del área de trabajo (p. ej. /Users/Development/myWorkspace)", + "folderName": "nombre de la carpeta del área de trabajo en la que el archivo está contenido (p. ej. myFolder)", + "folderPath": "ruta de acceso de archivo de la carpeta del área de trabajo en la que el archivo está contenido (p. ej. /Users/Development/myFolder)", "appName": "p. ej. VS Code", "dirty": "un indicador con modificaciones si el editor activo tiene modificaciones", "separator": "un separador condicional (\"-\") que aparece solo cuando está rodeado de variables con valores", diff --git a/i18n/esn/extensions/emmet/package.i18n.json b/i18n/esn/extensions/emmet/package.i18n.json index 07653dd9567..863e98a95bb 100644 --- a/i18n/esn/extensions/emmet/package.i18n.json +++ b/i18n/esn/extensions/emmet/package.i18n.json @@ -28,13 +28,6 @@ "command.incrementNumberByTen": "Aumentar por 10", "command.decrementNumberByTen": "Disminuir por 10", "emmetSyntaxProfiles": "Defina el perfil de la sintaxis especificada o use su propio perfil con reglas específicas.", - "emmetExclude": "Matriz de lenguajes donde no deben expandirse la abreviación Emmet.", - "emmetExtensionsPath": "Ruta de acceso a una carpeta que contiene los perfiles de emmet y fragmentos.»", - "emmetShowExpandedAbbreviation": "\nMuestra abreviaciones Emmet expandidas como sugerencias. La opción \"inMarkupAndStylesheetFilesOnly\" se aplica a HTML, HAML, Jade, Slim, XML, XSL, CSS, SCSS, SASS, LESS y Stylus. La opción \"always\" se aplica a todas las partes del archivo, independientemente de que sea de marcado o CSS.", - "emmetShowAbbreviationSuggestions": "Muestra posibles abreviaciones Emmet como sugerencias. No se aplica a hojas de estilos ni cuando emmet.showExpandedAbbreviation está establecido en \"never\".", - "emmetIncludeLanguages": "Habilita abreviaciones Emmet en lenguajes que no se admiten de forma predeterminada. Agregue una asignación aquí entre el lenguaje y el lenguaje que admite Emmet.\n Ejemplo: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", - "emmetVariables": "Variables para usar en fragmentos de código Emmet", - "emmetTriggerExpansionOnTab": "Cuando se habilita, se expande la abreviación Emmet al presionar la tecla TAB.", "emmetPreferences": "Preferencias usadas para modificar el comportamiento de algunas acciones y resoluciones de Emmet.", "emmetPreferencesIntUnit": "Unidad predeterminada para valores enteros", "emmetPreferencesFloatUnit": "Unidad predeterminada para valores float", @@ -43,6 +36,5 @@ "emmetPreferencesStylusAfter": "Símbolo que debe colocarse al final de una propiedad CSS cuando se expanden abreviaturas CSS en archivos Stylus", "emmetPreferencesCssBetween": "Símbolo que debe colocarse entre una propiedad CSS y un valor cuando se expanden abreviaturas CSS", "emmetPreferencesSassBetween": "Símbolo que debe colocarse entre una propiedad CSS y un valor cuando se expanden abreviaturas CSS en archivos SASS", - "emmetPreferencesStylusBetween": "Símbolo que debe colocarse entre una propiedad CSS y un valor cuando se expanden abreviaturas CSS en archivos Stylus", - "emmetShowSuggestionsAsSnippets": "Si es true, las sugerencias Emmet se muestran como fragmentos de código, de modo que puede ordenarlas por el valor editor.snippetSuggestions." + "emmetPreferencesStylusBetween": "Símbolo que debe colocarse entre una propiedad CSS y un valor cuando se expanden abreviaturas CSS en archivos Stylus" } \ 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 0376ca94cc1..69862736c9d 100644 --- a/i18n/esn/extensions/git/out/commands.i18n.json +++ b/i18n/esn/extensions/git/out/commands.i18n.json @@ -12,8 +12,9 @@ "cloning": "Clonando el repositorio GIT...", "openrepo": "Abrir repositorio", "proposeopen": "¿Desea abrir el repositorio clonado?", - "path to init": "Ruta de acceso de la carpeta", - "provide path": "Proporcione una ruta de acceso de carpeta para inicializar un repositorio GIT", + "init repo": "Inicializar el repositorio", + "create repo": "Inicializar el repositorio", + "are you sure": "Esto creará un repositorio Git en '{0}'. ¿Está seguro de que desea continuar?", "HEAD not available": "La versión HEAD de '{0}' no está disponible.", "confirm stage files with merge conflicts": "¿Está seguro de que quiere hacer una copia intermedia de {0} archivos con conflictos de fusión mediante combinación?", "confirm stage file with merge conflicts": "¿Está seguro de que quiere hacer una copia intermedia de {0} con conflictos de fusión mediante combinación? ", diff --git a/i18n/esn/extensions/git/out/repository.i18n.json b/i18n/esn/extensions/git/out/repository.i18n.json index fc557b451ea..b6063166fd7 100644 --- a/i18n/esn/extensions/git/out/repository.i18n.json +++ b/i18n/esn/extensions/git/out/repository.i18n.json @@ -21,6 +21,8 @@ "deleted by us": "Borrado por nosotros", "both added": "Ambos añadidos", "both modified": "Ambos modificados", + "untracked, short": "U", + "modified, short": "M", "commit": "Confirmar", "merge changes": "Fusionar cambios mediante combinación", "staged changes": "Cambios almacenados provisionalmente", diff --git a/i18n/esn/extensions/typescript/package.i18n.json b/i18n/esn/extensions/typescript/package.i18n.json index 2aeb36b7218..61e69211e91 100644 --- a/i18n/esn/extensions/typescript/package.i18n.json +++ b/i18n/esn/extensions/typescript/package.i18n.json @@ -44,7 +44,6 @@ "typescript.npm": "Especifica la ruta de acceso al archivo ejecutable de NPM usada para la adquisición automática de tipos. Requiere TypeScript >= 2.3.4.", "typescript.check.npmIsInstalled": "Compruebe si NPM está instalado para la adquisición automática de tipos.", "javascript.nameSuggestions": "Habilitar/deshabilitar nombres únicos de la lista de sugerencias en los archivos de JavaScript. ", - "typescript.tsc.autoDetect": "Controla si la detección automática de tareas TSC está activada o desactivada.", "typescript.problemMatchers.tsc.label": "Problemas de TypeScript", "typescript.problemMatchers.tscWatch.label": "Problemas de TypeScript (modo de inspección)" } \ No newline at end of file diff --git a/i18n/esn/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/esn/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 6ffe5c01c29..5b52fbf2852 100644 --- a/i18n/esn/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/esn/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,6 @@ "label.replaceButton": "Reemplazar", "label.replaceAllButton": "Reemplazar todo", "label.toggleReplaceButton": "Alternar modo de reemplazar", - "title.matchesCountLimit": "Solo se resaltan los primeros 999 resultados, pero todas las operaciones de búsqueda trabajan en todo el texto.", "label.matchesLocation": "{0} de {1}", "label.noResults": "Sin resultados" } \ No newline at end of file diff --git a/i18n/esn/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/esn/src/vs/editor/contrib/find/common/findController.i18n.json index 2928bececec..27d384a1b68 100644 --- a/i18n/esn/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/esn/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "Buscar selección siguiente", "previousSelectionMatchFindAction": "Buscar selección anterior", "startReplace": "Reemplazar", - "addSelectionToNextFindMatch": "Agregar selección hasta la siguiente coincidencia de búsqueda", - "addSelectionToPreviousFindMatch": "Agregar selección hasta la anterior coincidencia de búsqueda", - "moveSelectionToNextFindMatch": "Mover última selección hasta la siguiente coincidencia de búsqueda", - "moveSelectionToPreviousFindMatch": "Mover última selección hasta la anterior coincidencia de búsqueda", - "selectAllOccurrencesOfFindMatch": "Seleccionar todas las repeticiones de coincidencia de búsqueda", - "changeAll.label": "Cambiar todas las ocurrencias", "showNextFindTermAction": "Mostrar el siguiente término de búsqueda", "showPreviousFindTermAction": "Mostrar término de búsqueda anterior" } \ No newline at end of file diff --git a/i18n/esn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/esn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 13f4bac636a..d5994146753 100644 --- a/i18n/esn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/esn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Agregar cursor arriba", "mutlicursor.insertBelow": "Agregar cursor debajo", - "mutlicursor.insertAtEndOfEachLineSelected": "Añadir cursores a finales de línea" + "mutlicursor.insertAtEndOfEachLineSelected": "Añadir cursores a finales de línea", + "addSelectionToNextFindMatch": "Agregar selección hasta la siguiente coincidencia de búsqueda", + "addSelectionToPreviousFindMatch": "Agregar selección hasta la anterior coincidencia de búsqueda", + "moveSelectionToNextFindMatch": "Mover última selección hasta la siguiente coincidencia de búsqueda", + "moveSelectionToPreviousFindMatch": "Mover última selección hasta la anterior coincidencia de búsqueda", + "selectAllOccurrencesOfFindMatch": "Seleccionar todas las repeticiones de coincidencia de búsqueda", + "changeAll.label": "Cambiar todas las ocurrencias" } \ No newline at end of file diff --git a/i18n/esn/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/esn/src/vs/platform/theme/common/colorRegistry.i18n.json index 91ed718d0ad..354ba1a82a9 100644 --- a/i18n/esn/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/esn/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "Formato de color no válido. Use #TGB, #RBGA, #RRGGBB o #RRGGBBAA", "schema.colors": "Colores usados en el área de trabajo.", "foreground": "Color de primer plano general. Este color solo se usa si un componente no lo invalida.", "errorForeground": "Color de primer plano general para los mensajes de erroe. Este color solo se usa si un componente no lo invalida.", diff --git a/i18n/esn/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/esn/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 81bfd015f9e..fc9101aee18 100644 --- a/i18n/esn/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -9,14 +9,17 @@ "addFolderToWorkspace": "Agregar carpeta al área de trabajo...", "add": "&& Agregar", "addFolderToWorkspaceTitle": "Agregar carpeta al área de trabajo", + "globalRemoveFolderFromWorkspace": "Quitar carpeta del Área de trabajo...", "newWorkspace": "Nueva área de trabajo...", "select": "&&Seleccionar", "selectWorkspace": "Seleccionar carpetas para el área de trabajo", "removeFolderFromWorkspace": "Quitar carpeta del área de trabajo", + "openFolderSettings": "Abrir Configuración de carpeta", "saveWorkspaceAsAction": "Guardar área de trabajo como...", "save": "&&Guardar", "saveWorkspace": "Guardar área de trabajo", "openWorkspaceAction": "Abrir área de trabajo...", "openWorkspaceConfigFile": "Abrir archivo de configuración del área de trabajo", + "openFolderAsWorkspaceInNewWindow": "Abrir carpeta como Área de trabajo en una Nueva Ventana", "workspaceFolderPickerPlaceholder": "Seleccionar la carpeta del área de trabajo" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index bfe695f895b..66f040cada4 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Ocultar barra de actividades", - "activityBarAriaLabel": "Modificador de vista activa", "globalActions": "Acciones globales" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..bbaa4095de7 --- /dev/null +++ b/i18n/esn/src/vs/workbench/browser/parts/compositebar/compositeBar.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. +{ + "activityBarAriaLabel": "Modificador de vista activa" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..b8bb426ec85 --- /dev/null +++ b/i18n/esn/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1} ", + "additionalViews": "Vistas adicionales", + "numberBadge": "{0} ({1})", + "manageExtension": "Administrar extensión", + "titleKeybinding": "{0} ({1})", + "toggle": "Alternar vista fijada" +} \ 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 c5c13f08096..ae6d0079e4c 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 @@ -12,5 +12,6 @@ "groupTwoPicker": "Mostrar editores del segundo grupo", "groupThreePicker": "Mostrar editores del tercer grupo", "allEditorsPicker": "Mostrar todos los editores abiertos", - "view": "Ver" + "view": "Ver", + "file": "Archivo" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 7dd9c672cbe..4f9bdabe15e 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "El comando \"{0}\" no está habilitado actualmente y no se puede ejecutar.", "manageExtension": "Administrar extensión" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/esn/src/vs/workbench/electron-browser/main.contribution.i18n.json index 4655a5812be..20663bc3124 100644 --- a/i18n/esn/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,18 +10,15 @@ "workspaces": "Áreas de trabajo", "developer": "Desarrollador", "showEditorTabs": "Controla si los editores abiertos se deben mostrar o no en pestañas.", - "workbench.editor.labelFormat.default": "Mostrar el nombre del archivo. Cuando las pestañas están habilitadas y dos archivos tienen el mismo nombre en un grupo, se agregan las secciones distintivas de la ruta de acceso de cada archivo. Cuando las pestañas están deshabilitadas, se muestra la ruta de acceso relativa a la raíz del área de trabajo si el editor está activo.", "workbench.editor.labelFormat.short": "Mostrar el nombre del archivo seguido de su nombre de directorio.", - "workbench.editor.labelFormat.medium": "Mostrar el nombre del archivo seguido de la ruta de acceso relativo a la raíz del espacio de trabajo.", "workbench.editor.labelFormat.long": "Mostrar el nombre del archivo seguido de la ruta de acceso absoluta.", "tabDescription": "Controla el formato de la etiqueta para un editor. Modificar este ajuste puede hacer, por ejemplo, que sea más fácil entender la ubicación de un archivo: - corta: 'parent' - media: 'workspace/src/parent' - larga: '/home/user/workspace/src/parect' - por defecto: '.../parent', cuando otra pestaña comparte el mismo título, o la ruta de acceso relativa del espacio de trabajo si las pestañas están deshabilitadas", "editorTabCloseButton": "Controla la posición de los botones de cierre de pestañas del editor o los deshabilita si se establece en \"off\".", "showIcons": "Controla si los editores abiertos deben mostrarse o no con un icono. Requiere que también se habilite un tema de icono.", "enablePreview": "Controla si los editores abiertos se muestran en vista previa. Los editores en vista previa se reutilizan hasta que se guardan (por ejemplo, mediante doble clic o editándolos) y se muestran en cursiva.", "enablePreviewFromQuickOpen": "Controla si los editores abiertos mediante Quick Open se muestran en modo de vista previa. Los editores en modo de vista previa se reutilizan hasta que se conservan (por ejemplo, mediante doble clic o editándolos).", - "editorOpenPositioning": "Controla dónde se abren los editores. Seleccione 'izquierda' o 'derecha' para abrir los editores situados a la izquierda o la derecha del que está actualmente activo. Seleccione 'primero' o 'último' para abrir los editores con independencia del que esté actualmente activo.", "revealIfOpen": "Controla si un editor se muestra en alguno de los grupos visibles cuando se abre. Si se deshabilita esta opción, un editor preferirá abrirse en el grupo de editores activo en ese momento. Si se habilita, un editor ya abierto se mostrará en lugar de volver a abrirse en el grupo de editores activo. Tenga en cuenta que hay casos en los que esta opción se omite; por ejemplo, cuando se fuerza la apertura de un editor en un grupo específico o junto al grupo activo actual.", - "commandHistory": "Controla el número de comandos usados recientemente a almacenar en el historial para la paleta de comandos. Establezca a 0 para deshabilitar el historial de comandos.", + "commandHistory": "Controla el número de comandos utilizados recientemente que se mantendrán en el historial de la paleta de comandos. Establezca el valor a 0 para desactivar el historial de comandos.", "preserveInput": "Controla si la última entrada introducida en la paleta de comandos debería ser restaurada cuando sea abierta la próxima vez.", "closeOnFocusLost": "Controla si Quick Open debe cerrarse automáticamente cuando pierde el foco.", "openDefaultSettings": "Controla si la configuración de apertura también abre un editor que muestra todos los valores predeterminados.", @@ -50,7 +47,6 @@ "restoreWindows": "Controla cómo se vuelven a abrir las ventanas tras un reinicio. Seleccione \"none\" para comenzar siempre con un área de trabajo vacía, \"one\" para volver a abrir la última ventana en la que trabajó, \"folders\" para volver a abrir todas las ventanas que tenían carpetas abiertas o \"all\" para volver a abrir todas las ventanas de la última sesión.", "restoreFullscreen": "Controla si una ventana se debe restaurar al modo de pantalla completa si se salió de ella en dicho modo.", "zoomLevel": "Ajuste el nivel de zoom de la ventana. El tamaño original es 0 y cada incremento (por ejemplo, 1) o disminución (por ejemplo, -1) representa una aplicación de zoom un 20 % más grande o más pequeño. También puede especificar decimales para ajustar el nivel de zoom con una granularidad más precisa.", - "title": "Controla el título de la ventana según el editor activo. Las variables se sustituyen según el contexto:\n${activeEditorShort}: e.g. myFile.txt\n${activeEditorMedium}: e.g. myFolder/myFile.txt\n${activeEditorLong}: por ejemplo, /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: por ejemplo, myFolder\n${folderPath}: por ejemplo, /Users/Development/myFolder\n${rootName}: por ejemplo, myFolder1, myFolder2, myFolder3\n${rootPath}: por ejemplo, /Users/Development/myWorkspace\n${appName}: por ejemplo, VS Code\n${dirty}: un indicador con modificaciones si el editor activo está desfasado\n${separator}: separador condicional (\" - \") que solo se muestra cuando está rodeado de variables con valores", "window.newWindowDimensions.default": "Abrir las nuevas ventanas en el centro de la pantalla.", "window.newWindowDimensions.inherit": "Abrir las nuevas ventanas con la misma dimensión que la última activa.", "window.newWindowDimensions.maximized": "Abrir las nuevas ventanas maximizadas.", diff --git a/i18n/esn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index be6974deb6b..e9a982317e2 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, depurar", "debugAriaLabel": "Escriba un nombre de una configuración de inicio para ejecutar.", + "addConfigTo": "Agregar configuración ({0})...", + "addConfiguration": "Agregar configuración...", "noConfigurationsMatching": "No hay ninguna configuración de depuración coincidente", "noConfigurationsFound": "No se encontró ninguna configuración de inicio. Cree un archivo \"launch.json\"." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..7a6db36a29e --- /dev/null +++ b/i18n/esn/src/vs/workbench/parts/debug/browser/debugStatus.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. +{ + "debug": "Depurar" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/esn/src/vs/workbench/parts/debug/browser/debugViewlet.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/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 f4d25015e28..28c7690312b 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 @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "Configuraciones para generar el archivo \"launch.json\" inicial.", "vscode.extension.contributes.debuggers.languages": "Lista de lenguajes para los que la extensión de depuración podría considerarse el \"depurador predeterminado\".", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Si se especifica, VS Code llamará a este comando para determinar la ruta de acceso ejecutable del adaptador de depuración y los argumentos que se deben pasar.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Si se especifica, VS Code llamará a este comando para las acciones de \"depuración\" o \"ejecución\" destinadas para esta extensión.", "vscode.extension.contributes.debuggers.configurationSnippets": "Fragmentos de código para agregar nuevas configuraciones a \"launch.json\".", "vscode.extension.contributes.debuggers.configurationAttributes": "Configuraciones de esquema JSON para validar \"launch.json\".", "vscode.extension.contributes.debuggers.windows": "Configuración específica de Windows.", diff --git a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 39eca78322f..01b6c98e302 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,10 +12,7 @@ "breakpointRemoved": "Punto de interrupción quitado, línea {0}, archivo {1}", "compoundMustHaveConfigurations": "El compuesto debe tener configurado el atributo \"configurations\" a fin de iniciar varias configuraciones.", "configMissing": "La configuración \"{0}\" falta en \"launch.json\".", - "debugRequestNotSupported": "La configuración de depuración seleccionada tiene un valor de atributo '{0}': '{1}' no compatible.", - "debugRequesMissing": "El atributo '{0}' está ausente en la configuración de depuración elegida.", "debugTypeNotSupported": "El tipo de depuración '{0}' configurado no es compatible.", - "debugTypeMissing": "Falta la propiedad \"type\" en la configuración de inicio seleccionada.", "preLaunchTaskErrors": "Errores de compilación durante la tarea preLaunchTask '{0}'.", "preLaunchTaskError": "Error de compilación durante la tarea preLaunchTask '{0}'.", "preLaunchTaskExitCode": "La tarea preLaunchTask '{0}' finalizó con el código de salida {1}.", diff --git a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index c71edc9f51f..29384cb26e7 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -7,6 +7,5 @@ "stateCapture": "El estado del objeto se captura desde la primera evaluación", "replVariableAriaLabel": "La variable {0} tiene el valor {1}, read–eval–print loop, depuración", "replExpressionAriaLabel": "La expresión {0} tiene el valor {1}, read–eval–print loop, depuración", - "replValueOutputAriaLabel": "{0}, read–eval–print loop, depuración", - "replKeyValueOutputAriaLabel": "La variable de salida {0} tiene el valor {1}, read–eval–print loop, depuración" + "replValueOutputAriaLabel": "{0}, read–eval–print loop, depuración" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index 9b4c0a6fb45..5b4f1d9a867 100644 --- a/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "Archivos", + "filesCategory": "Archivo", "revealInSideBar": "Mostrar en barra lateral", "acceptLocalChanges": "Usar los cambios y sobrescribir el contenido del disco", "revertLocalChanges": "Descartar los cambios y volver al contenido del disco" diff --git a/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 836362af71e..5d9def6792e 100644 --- a/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "¿Está seguro de que desea eliminar '{0}'?", "undoBin": "Puede restaurar desde la papelera de reciclaje.", "undoTrash": "Puede restaurar desde la papelera.", + "doNotAskAgain": "No volver a preguntarme", "confirmDeleteMessageFolder": "¿Está seguro de que desea eliminar '{0}' y su contenido de forma permanente?", "confirmDeleteMessageFile": "¿Está seguro de que desea eliminar '{0}' de forma permanente?", "irreversible": "Esta acción es irreversible.", @@ -37,8 +38,6 @@ "openToSide": "Abrir en el lateral", "compareSource": "Seleccionar para comparar", "globalCompareFile": "Comparar archivo activo con...", - "pickHistory": "Seleccione un archivo abierto anteriormente para comparar", - "unableToFileToCompare": "El archivo seleccionado no se puede comparar con '{0}'.", "openFileToCompare": "Abrir un archivo antes para compararlo con otro archivo.", "compareWith": "Comparar \"{0}\" con \"{1}\"", "compareFiles": "Comparar archivos", @@ -47,7 +46,7 @@ "saveAs": "Guardar como...", "saveAll": "Guardar todos", "saveAllInGroup": "Guardar todo en el grupo", - "saveFiles": "Guardar archivos con modificaciones", + "saveFiles": "Guardar todos los archivos", "revert": "Revertir archivo", "focusOpenEditors": "Foco sobre la vista de editores abiertos", "focusFilesExplorer": "Enfocar Explorador de archivos", diff --git a/i18n/esn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/esn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index ed00449cce3..8857fa7d07b 100644 --- a/i18n/esn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,7 @@ { "noWorkspace": "No hay ninguna carpeta abierta", "explorerSection": "Sección del Explorador de archivos", - "noWorkspaceHelp": "Todavía no ha abierto ninguna carpeta.", + "noWorkspaceHelp": "Todavía no ha agregado una carpeta al espacio de trabajo.", + "noFolderHelp": "Todavía no ha abierto ninguna carpeta.", "openFolder": "Abrir carpeta" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/esn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index 7903df9c11b..40f9fcc3277 100644 --- a/i18n/esn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -4,12 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "canNotResolve": "No se puede resolver la carpeta {0}", "fileInputAriaLabel": "Escriba el nombre de archivo. Presione ENTRAR para confirmar o Esc para cancelar", "filesExplorerViewerAriaLabel": "{0}, Explorador de archivos", "dropFolders": "¿Quiere agregar las carpetas al área de trabajo?", "dropFolder": "¿Quiere agregar la carpeta al área de trabajo?", "addFolders": "&&Agregar carpetas", "addFolder": "&&Agregar carpeta", + "confirmMove": "¿Está seguro de que desea mover '{0}'?", "confirmOverwriteMessage": "'{0}' ya existe en la carpeta de destino. ¿Desea reemplazarlo?", "irreversible": "Esta acción es irreversible.", "replaceButtonLabel": "Reemplazar" diff --git a/i18n/esn/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/esn/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..710f5b027a0 --- /dev/null +++ b/i18n/esn/src/vs/workbench/parts/markers/browser/markersFileDecorations.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. +{ + "label": "Problemas", + "tooltip.1": "1 problema en este fichero", + "tooltip.N": "{0} problemas en este fichero", + "markers.showOnFile": "Mostrar Errores y Advertencias en la carpeta y ficheros." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index ed5419507d3..da443e5daba 100644 --- a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "Coloque aquí su configuración para sobrescribir la configuración predeterminada.", - "errorInvalidConfiguration": "No se puede escribir la configuración. Corrija los errores o advertencias del archivo y vuelva a intentarlo.", "emptyWorkspaceSettingsHeader": "Coloque aquí su configuración para sobrescribir la configuración de usuario.", "emptyFolderSettingsHeader": "Coloque aquí su configuración de carpeta para sobrescribir la que se especifica en la configuración de área de trabajo.", "defaultFolderSettingsTitle": "Configuración de carpeta predeterminada", diff --git a/i18n/esn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/esn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 5b11b46879d..e0012dd14f7 100644 --- a/i18n/esn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "El comando '{0}' no está habilitado en el contexto actual.", "recentlyUsed": "usado recientemente", "morecCommands": "otros comandos", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "No hay comandos coincidentes" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index c0de845ea64..4c8491b6c87 100644 --- a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "show previous change": "Mostrar el cambio anterior", + "show next change": "Mostrar el cambio siguiente", "editorGutterModifiedBackground": "Color de fondo del medianil del editor para las líneas modificadas.", "editorGutterAddedBackground": "Color de fondo del medianil del editor para las líneas agregadas.", "editorGutterDeletedBackground": "Color de fondo del medianil del editor para las líneas eliminadas.", diff --git a/i18n/esn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index a77598c77bc..d0eef49247f 100644 --- a/i18n/esn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -17,7 +17,7 @@ "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.", "exclude.when": "Comprobación adicional de los elementos del mismo nivel de un archivo coincidente. Use $(nombreBase) como variable para el nombre de archivo que coincide.", - "useRipgrep": "Controla si debe utilizarse ripgrep en la búsqueda de texto", + "useRipgrep": "Controla si se utiliza ripgrep en la búsqueda de texto y ficheros", "useIgnoreFilesByDefault": "Controla si usar los archivos .gitignore y .ignore de forma predeterminada al buscar en una nueva área de trabajo.", "search.quickOpen.includeSymbols": "Configurar para incluir los resultados de una búsqueda global de símbolos en los resultados de archivos de Quick Open." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/esn/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 314acd5b6dd..572f519b892 100644 --- a/i18n/esn/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -19,7 +19,6 @@ "ClearSearchResultsAction.label": "Borrar resultados de la búsqueda", "FocusNextSearchResult.label": "Centrarse en el siguiente resultado de la búsqueda", "FocusPreviousSearchResult.label": "Centrarse en el anterior resultado de la búsqueda", - "RemoveAction.label": "Quitar", "file.replaceAll.label": "Reemplazar todo", "match.replace.label": "Reemplazar" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/esn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 3353f89b68d..bc5073a75cf 100644 --- a/i18n/esn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,8 +10,8 @@ "vscode.extension.contributes.snippets": "Aporta fragmentos de código.", "vscode.extension.contributes.snippets-language": "Identificador del lenguaje al que se aporta este fragmento de código.", "vscode.extension.contributes.snippets-path": "Ruta de acceso del archivo de fragmentos de código. La ruta es relativa a la carpeta de extensión y normalmente empieza por \"./snippets/\".", - "badFile": "No se pudo leer el archivo del fragmento \"{0}\".", "badVariableUse": "Es muy probable que el fragmento de código \"{0}\" confunda las variables de fragmento de código y los marcadores de posición de fragmento de código. Consulte https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax para más informacion.", + "badFile": "No se pudo leer el archivo del fragmento \"{0}\".", "source.snippet": "Fragmento de código del usuario", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index ad64a450cf5..50d2ca8b4b1 100644 --- a/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -30,6 +30,7 @@ "TaskSystem.activeSame.noBackground": "La tarea \"{0}\" ya está activa. Para terminarla, use la opción \"Terminar tarea\" del menú Tareas.", "TaskSystem.active": "Ya hay una tarea en ejecución. Finalícela antes de ejecutar otra tarea.", "TaskSystem.restartFailed": "No se pudo terminar y reiniciar la tarea {0}", + "TaskService.noConfiguration": "Error: La detección de tarea {0} no encontró una tarea para la siguiente configuración:\n{1}\nLa tarea será omitida.\n", "TaskSystem.configurationErrors": "Error: La configuración de la tarea proporcionada tiene errores de validación y no se puede usar. Corrija los errores primero.", "taskService.ignoreingFolder": "Ignorando las configuraciones de tarea para la carpeta del area de trabajo {0}. El soporte de tarea de area de trabajo multi carpeta requiere que todas las carpetas usen la versión de tarea 2.0.0 ", "TaskSystem.invalidTaskJson": "Error: El contenido del archivo tasks.json tiene errores de sintaxis. Corríjalos antes de ejecutar una tarea.", diff --git a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 2fb25c70d99..c3d0cfd1e37 100644 --- a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -16,7 +16,6 @@ "workbench.action.terminal.new.short": "Nuevo terminal", "workbench.action.terminal.focus": "Enfocar terminal", "workbench.action.terminal.focusNext": "Enfocar terminal siguiente", - "workbench.action.terminal.focusAtIndex": "Enfocar terminal {0}", "workbench.action.terminal.focusPrevious": "Enfocar terminal anterior", "workbench.action.terminal.paste": "Pegar en el terminal activo", "workbench.action.terminal.DefaultShell": "Seleccionar el shell predeterminado", diff --git a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 1b04639ccd5..a2ea49d47f1 100644 --- a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Copiar", - "createNewTerminal": "Nuevo terminal", "paste": "Pegar", "selectAll": "Seleccionar todo", "clear": "Borrar" diff --git a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 6b1dbc4c66a..1a5374df014 100644 --- a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "De acuerdo, no volver a mostrar este mensaje", "terminal.integrated.chooseWindowsShell": "Seleccione el shell de terminal que desee, puede cambiarlo más adelante en la configuración", "terminalService.terminalCloseConfirmationSingular": "Hay una sesión de terminal activa, ¿quiere terminarla?", - "terminalService.terminalCloseConfirmationPlural": "Hay {0} sesiones de terminal activas, ¿quiere terminarlas?", - "yes": "Sí" + "terminalService.terminalCloseConfirmationPlural": "Hay {0} sesiones de terminal activas, ¿quiere terminarlas?" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/esn/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..38c0dd3726b --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.configuration.title": "Resumen de la configuración. Esta etiqueta se usará en el archivo de configuración como comentario divisor.", + "vscode.extension.contributes.configuration.properties": "Descripción de las propiedades de configuración.", + "scope.window.description": "Configuración específica para ventanas, que se puede definir en la configuración de usuario o de área de trabajo.", + "scope.resource.description": "Configuración específica para recursos, que se puede definir en la configuración de usuario, de área de trabajo o de carpeta.", + "scope.description": "Ámbito donde es aplicable la configuración. Los ámbitos disponibles son \"window\" y \"resource\".", + "vscode.extension.contributes.configuration": "Aporta opciones de configuración.", + "invalid.title": "configuration.title debe ser una cadena", + "vscode.extension.contributes.defaultConfiguration": "Contribuye a la configuración de los parámetros del editor predeterminados por lenguaje.", + "invalid.properties": "configuration.properties debe ser un objeto", + "workspaceConfig.folders.description": "Lista de carpetas para cargar en el área de trabajo. ", + "workspaceConfig.path.description": "Ruta de acceso de archivo; por ejemplo, \"/raíz/carpetaA\" o \"./carpetaA\" para una ruta de acceso de archivo que se resolverá respecto a la ubicación del archivo del área de trabajo.", + "workspaceConfig.settings.description": "Configuración de área de trabajo", + "workspaceConfig.extensions.description": "Extensiones del área de trabajo", + "unknownWorkspaceProperty": "Propiedad de configuración de espacio de trabajo desconocida" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/esn/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/editor/common/editorService.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. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/esn/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..5be27841f5b --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.themes": "Contributes textmate color themes.", + "vscode.extension.contributes.themes.id": "Identificador del tema de icono como se usa en la configuración de usuario.", + "vscode.extension.contributes.themes.label": "Etiqueta del tema de color tal como se muestra en la interfaz de usuario.", + "vscode.extension.contributes.themes.uiTheme": "Tema base que define los colores que se usan en el editor: 'vs' es el tema de color claro, 'vs-dark' es el tema de color oscuro, 'hc-black' es el tema oscuro de alto contraste.", + "vscode.extension.contributes.themes.path": "Ruta de acceso del archivo tmTheme. La ruta de acceso es relativa a la carpeta de extensión y suele ser './themes/themeFile.tmTheme'.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "Se esperaba una cadena en \"contributes.{0}.path\". Valor proporcionado: {1}", + "invalid.path.1": "Se esperaba que \"contributes.{0}.path\" ({1}) se incluyera en la carpeta de la extensión ({2}). Esto puede hacer que la extensión no sea portátil." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/esn/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..b0f9faf6b52 --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.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. +{ + "error.cannotparseicontheme": "Problems parsing file icons file: {0}" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/esn/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..541e0ac3d8b --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "Identificador del tema de icono como se usa en la configuración de usuario.", + "vscode.extension.contributes.iconThemes.label": "Etiqueta del tema de icono como se muestra en la interfaz de usuario.", + "vscode.extension.contributes.iconThemes.path": "Ruta de acceso del archivo de definición de temas de icono. La ruta de acceso es relativa a la carpeta de extensión y suele ser './icons/awesome-icon-theme.json'.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "Se esperaba una cadena en \"contributes.{0}.path\". Valor proporcionado: {1}", + "reqid": "Se esperaba una cadena en `contributes.{0}.id`. Valor proporcionado: {1}", + "invalid.path.1": "Se esperaba que \"contributes.{0}.path\" ({1}) se incluyera en la carpeta de la extensión ({2}). Esto puede hacer que la extensión no sea portátil." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/esn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index 7c308f9717e..cb85af9d3cd 100644 --- a/i18n/esn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/esn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,31 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "Identificador del tema de icono como se usa en la configuración de usuario.", - "vscode.extension.contributes.themes.label": "Etiqueta del tema de color tal como se muestra en la interfaz de usuario.", - "vscode.extension.contributes.themes.uiTheme": "Tema base que define los colores que se usan en el editor: 'vs' es el tema de color claro, 'vs-dark' es el tema de color oscuro, 'hc-black' es el tema oscuro de alto contraste.", - "vscode.extension.contributes.themes.path": "Ruta de acceso del archivo tmTheme. La ruta de acceso es relativa a la carpeta de extensión y suele ser './themes/themeFile.tmTheme'.", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "Identificador del tema de icono como se usa en la configuración de usuario.", - "vscode.extension.contributes.iconThemes.label": "Etiqueta del tema de icono como se muestra en la interfaz de usuario.", - "vscode.extension.contributes.iconThemes.path": "Ruta de acceso del archivo de definición de temas de icono. La ruta de acceso es relativa a la carpeta de extensión y suele ser './icons/awesome-icon-theme.json'.", "migration.completed": "Se han agregado nuevos valores de tema a la configuración de usuario. Hay una copia de seguridad disponible en {0}.", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "Se esperaba una cadena en \"contributes.{0}.path\". Valor proporcionado: {1}", - "invalid.path.1": "Se esperaba que \"contributes.{0}.path\" ({1}) se incluyera en la carpeta de la extensión ({2}). Esto puede hacer que la extensión no sea portátil.", - "reqid": "Se esperaba una cadena en `contributes.{0}.id`. Valor proporcionado: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "Especifica el tema de icono utilizado en el área de trabajo o \"null\" para no mostrar ningún icono de archivo.", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "Reemplaza los colores del tema de color actual", - "workbenchColors.deprecated": "Esta configuracion no es experimental y se ha cambiado de nombre a 'workbench.colorCustomizations'", - "workbenchColors.deprecatedDescription": "Utilice 'workbench.colorCustomizations' en su lugar", "editorColors": "Reemplaza los colores y el estilo de fuente del editor del tema de color seleccionado.", "editorColors.comments": "Establece los colores y estilos para los comentarios", "editorColors.strings": "Establece los colores y estilos para los literales de cadena.", diff --git a/i18n/esn/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/esn/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..17798aeb3c8 --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/workspace/node/workspaceEditingService.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. +{ + "openWorkspaceConfigurationFile": "Abrir archivo de configuración del área de trabajo", + "close": "Cerrar" +} \ No newline at end of file diff --git a/i18n/fra/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/fra/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index fcedce53b3c..c8334701a65 100644 --- a/i18n/fra/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/fra/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "exemple : myFile.txt", - "activeEditorMedium": "exemple : myFolder/myFile.txt", - "activeEditorLong": "exemple : /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "par ex., myFolder1, myFolder2, myFolder3", - "rootPath": "exemple : /Users/Development/myProject", - "folderName": "par ex., myFolder", - "folderPath": "par ex., /Users/Development/myFolder", + "activeEditorShort": "le nom du fichier (ex: monfichier.txt)", + "activeEditorMedium": "le chemin d’accès du fichier relatif au dossier de l’espace de travail (ex: myFolder/myFile.txt)", + "activeEditorLong": "le chemin d’accès complet du fichier (ex: /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "nom de l’espace de travail (ex: monDossier ou monEspaceDeTravail)", + "rootPath": "chemin d’accès de l’espace de travail (ex: /Users/Development/myWorkspace)", + "folderName": "nom du dossier de l'espace de travail auquel le fichier appartient (ex: monDossier)", + "folderPath": "chemin d’accès du dossier de l'espace de travail auquel le fichier appartient (ex: /Users/Development/myFolder)", "appName": "exemple : VS Code", "dirty": "indicateur d'intégrité si l'intégrité de l'éditeur actif est compromise", "separator": "séparateur conditionnel (' - ') qui s'affiche uniquement quand il est entouré de variables avec des valeurs", diff --git a/i18n/fra/extensions/emmet/package.i18n.json b/i18n/fra/extensions/emmet/package.i18n.json index d9a0b979e40..3136f6135aa 100644 --- a/i18n/fra/extensions/emmet/package.i18n.json +++ b/i18n/fra/extensions/emmet/package.i18n.json @@ -28,13 +28,6 @@ "command.incrementNumberByTen": "Incrémenter de 10", "command.decrementNumberByTen": "Décrémenter de 10", "emmetSyntaxProfiles": "Définissez le profil pour la syntaxe spécifiée ou utilisez votre propre profil avec des règles spécifiques.", - "emmetExclude": "Ensemble de langages où les abréviations emmet ne doivent pas être développées.", - "emmetExtensionsPath": "Chemin d'un dossier contenant les profils et les extraits Emmet.", - "emmetShowExpandedAbbreviation": "Affiche les abréviations Emmet développées sous forme de suggestions.\nL’option \"inMarkupAndStylesheetFilesOnly\" s’applique à html, haml, jade, slim, xml, xsl, css, scss, sass, less et un stylet.\nL’option \"toujours\" s’applique à toutes les parties du fichier indépendamment du balisage/css.", - "emmetShowAbbreviationSuggestions": "Affiche les abréviations Emmet possibles sous forme de suggestions. Non applicable dans les feuilles de style ou quand emmet.showExpandedAbbreviation est défini sur \"jamais\".", - "emmetIncludeLanguages": "Active les abréviations Emmet dans les langages qui ne sont pas pris en charge par défaut. Ajoute un mappage ici entre le langage et le langage Emmet pris en charge .\n Par exemple : {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", - "emmetVariables": "Variables à utiliser dans les extraits Emmet", - "emmetTriggerExpansionOnTab": "Une fois les abréviations Emmet activées, elles se développent quand vous appuyez sur la touche Tab.", "emmetPreferences": "Préférences utilisées pour modifier le comportement de certaines actions et résolveurs d'Emmet.", "emmetPreferencesIntUnit": "Unité par défaut pour les valeurs entières", "emmetPreferencesFloatUnit": "Unité par défaut pour les valeurs float", @@ -44,5 +37,7 @@ "emmetPreferencesCssBetween": "Symbole à placer entre la propriété CSS et la valeur pendant le développement des abréviations CSS", "emmetPreferencesSassBetween": "Symbole à placer entre la propriété CSS et la valeur pendant le développement des abréviations CSS dans les fichiers Sass", "emmetPreferencesStylusBetween": "Symbole à placer entre la propriété CSS et la valeur pendant le développement des abréviations CSS dans les fichiers Stylus", - "emmetShowSuggestionsAsSnippets": "Si la valeur est True, les suggestions Emmet s'affichent sous forme d'extraits, ce qui vous permet de les ordonner conformément au paramètre editor.snippetSuggestions." + "emmetPreferencesFilterCommentBefore": "Une définition de commentaire qui doit être placée avant l’élément correspondant quand le filtre de commentaire est appliqué.", + "emmetPreferencesFilterCommentAfter": "Une définition de commentaire qui doit être placée après l’élément correspondant quand un filtre de commentaire est appliqué.", + "emmetPreferencesFilterCommentTrigger": "Une liste séparée par des virgules de noms d’attributs qui devraient exister en abrégé pour que le filtre de commentaire soit appliqué" } \ No newline at end of file diff --git a/i18n/fra/extensions/git/out/commands.i18n.json b/i18n/fra/extensions/git/out/commands.i18n.json index 72e09a4dac2..e0dab3e5a12 100644 --- a/i18n/fra/extensions/git/out/commands.i18n.json +++ b/i18n/fra/extensions/git/out/commands.i18n.json @@ -12,8 +12,9 @@ "cloning": "Clonage du dépôt git...", "openrepo": "Ouvrir le dépôt", "proposeopen": "Voulez-vous ouvrir le dépôt cloné ?", - "path to init": "Chemin du dossier", - "provide path": "Veuillez fournir un chemin de dossier pour initialiser un dépôt Git", + "init repo": "Initialiser le dépôt", + "create repo": "Initialiser le dépôt", + "are you sure": "Ceci va créer un dépôt Git dans '{0}'. Êtes-vous sûr de vouloir continuer ?", "HEAD not available": "La version HEAD de '{0}' n'est pas disponible.", "confirm stage files with merge conflicts": "Voulez-vous vraiment créer {0} fichiers avec des conflits de fusion ?", "confirm stage file with merge conflicts": "Voulez-vous vraiment créer {0} avec des conflits de fusion ?", diff --git a/i18n/fra/extensions/git/out/repository.i18n.json b/i18n/fra/extensions/git/out/repository.i18n.json index 75b81935d06..9f5e062bdb0 100644 --- a/i18n/fra/extensions/git/out/repository.i18n.json +++ b/i18n/fra/extensions/git/out/repository.i18n.json @@ -21,6 +21,8 @@ "deleted by us": "Supprimé par nos soins", "both added": "Tous deux ajoutés", "both modified": "Tous deux modifiés", + "untracked, short": "U", + "modified, short": "M", "commit": "Commit", "merge changes": "Fusionner les modifications", "staged changes": "Modifications en zone de transit", diff --git a/i18n/fra/extensions/git/package.i18n.json b/i18n/fra/extensions/git/package.i18n.json index 6253e6cf5fe..e5008fa48da 100644 --- a/i18n/fra/extensions/git/package.i18n.json +++ b/i18n/fra/extensions/git/package.i18n.json @@ -15,6 +15,8 @@ "command.stageAll": "Mettre en attente toutes les modifications", "command.stageSelectedRanges": "Mettre en attente les plages sélectionnées", "command.revertSelectedRanges": "Restaurer les portées sélectionnées", + "command.stageChange": "Mettre en attente la modification", + "command.revertChange": "Restaurer la modification", "command.unstage": "Annuler la mise en attente des modifications", "command.unstageAll": "Annuler la mise en attente de toutes les modifications", "command.unstageSelectedRanges": "Annuler la mise en attente des plages sélectionnées", diff --git a/i18n/fra/extensions/typescript/package.i18n.json b/i18n/fra/extensions/typescript/package.i18n.json index 8762fa61f04..848e776f0d6 100644 --- a/i18n/fra/extensions/typescript/package.i18n.json +++ b/i18n/fra/extensions/typescript/package.i18n.json @@ -44,7 +44,8 @@ "typescript.npm": "Spécifie le chemin de l'exécutable NPM utilisé pour l'acquisition de type automatique. Nécessite TypeScript >= 2.3.4.", "typescript.check.npmIsInstalled": "Vérifie si NPM est installé pour l'acquisition de type automatique.", "javascript.nameSuggestions": "Activez/désactivez l'inclusion de noms uniques à partir du fichier dans les listes de suggestions JavaScript.", - "typescript.tsc.autoDetect": "Contrôle si la détection automatique des tâches tsc est activée ou désactivée.", + "typescript.tsc.autoDetect": "Contrôle la détection automatique des tâches tsc. 'off' désactive cette fonctionnalité. 'build' crée uniquement des tâches de compilation à exécution unique. 'watch' crée uniquement des tâches de compilation et de watch. 'on' crée les deux les tâches build et watch. La valeur par défaut est 'on'.", "typescript.problemMatchers.tsc.label": "Problèmes liés à TypeScript", - "typescript.problemMatchers.tscWatch.label": "Problèmes liés à TypeScript (mode espion)" + "typescript.problemMatchers.tscWatch.label": "Problèmes liés à TypeScript (mode espion)", + "typescript.quickSuggestionsForPaths": "Activer/désactiver les suggestions rapides lorsque vous saisissez un chemin d’import." } \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/fra/src/vs/editor/contrib/find/browser/findWidget.i18n.json index e6ecb5ce261..35e6cb71d88 100644 --- a/i18n/fra/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/fra/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,6 @@ "label.replaceButton": "Remplacer", "label.replaceAllButton": "Tout remplacer", "label.toggleReplaceButton": "Changer le mode de remplacement", - "title.matchesCountLimit": "Seuls les 999 premiers résultats sont mis en surbrillance. Cependant, toutes les opérations de recherche sont appliquées à l'ensemble du texte.", "label.matchesLocation": "{0} sur {1}", "label.noResults": "Aucun résultat" } \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/fra/src/vs/editor/contrib/find/common/findController.i18n.json index 2176cea208c..21889b4123e 100644 --- a/i18n/fra/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/fra/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "Sélection suivante", "previousSelectionMatchFindAction": "Sélection précédente", "startReplace": "Remplacer", - "addSelectionToNextFindMatch": "Ajouter la sélection à la correspondance de recherche suivante", - "addSelectionToPreviousFindMatch": "Ajouter la sélection à la correspondance de recherche précédente", - "moveSelectionToNextFindMatch": "Déplacer la dernière sélection vers la correspondance de recherche suivante", - "moveSelectionToPreviousFindMatch": "Déplacer la dernière sélection à la correspondance de recherche précédente", - "selectAllOccurrencesOfFindMatch": "Sélectionner toutes les occurrences des correspondances de la recherche", - "changeAll.label": "Modifier toutes les occurrences", "showNextFindTermAction": "Afficher le terme de recherche suivant", "showPreviousFindTermAction": "Afficher le terme de recherche précédent" } \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/fra/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 081fbcf0bec..04e943155da 100644 --- a/i18n/fra/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/fra/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Ajouter un curseur au-dessus", "mutlicursor.insertBelow": "Ajouter un curseur en dessous", - "mutlicursor.insertAtEndOfEachLineSelected": "Ajouter des curseurs à la fin des lignes" + "mutlicursor.insertAtEndOfEachLineSelected": "Ajouter des curseurs à la fin des lignes", + "addSelectionToNextFindMatch": "Ajouter la sélection à la correspondance de recherche suivante", + "addSelectionToPreviousFindMatch": "Ajouter la sélection à la correspondance de recherche précédente", + "moveSelectionToNextFindMatch": "Déplacer la dernière sélection vers la correspondance de recherche suivante", + "moveSelectionToPreviousFindMatch": "Déplacer la dernière sélection à la correspondance de recherche précédente", + "selectAllOccurrencesOfFindMatch": "Sélectionner toutes les occurrences des correspondances de la recherche", + "changeAll.label": "Modifier toutes les occurrences" } \ No newline at end of file diff --git a/i18n/fra/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/fra/src/vs/platform/theme/common/colorRegistry.i18n.json index 1c47e156e38..2cfa0fbeab4 100644 --- a/i18n/fra/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/fra/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "Format de couleur non valide. Utilisez #RGB, #RGBA, #RRGGBB ou #RRGGBBAA", "schema.colors": "Couleurs utilisées dans le banc d'essai.", "foreground": "Couleur de premier plan globale. Cette couleur est utilisée si elle n'est pas remplacée par un composant.", "errorForeground": "Couleur principale de premier plan pour les messages d'erreur. Cette couleur est utilisée uniquement si elle n'est pas redéfinie par un composant.", diff --git a/i18n/fra/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/fra/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 857489eaa8f..778330402d3 100644 --- a/i18n/fra/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -9,14 +9,17 @@ "addFolderToWorkspace": "Ajouter un dossier à l'espace de travail...", "add": "&&Ajouter", "addFolderToWorkspaceTitle": "Ajouter un dossier à l'espace de travail", + "globalRemoveFolderFromWorkspace": "Supprimer le dossier d’espace de travail...", "newWorkspace": "Nouvel espace de travail...", "select": "&&Sélectionner", "selectWorkspace": "Sélectionner les dossiers pour l’espace de travail", "removeFolderFromWorkspace": "Supprimer le dossier de l'espace de travail", + "openFolderSettings": "Ouvrir le dossier Paramètres", "saveWorkspaceAsAction": "Enregistrer l’espace de travail sous...", "save": "&&Enregistrer", "saveWorkspace": "Enregistrer l’espace de travail", "openWorkspaceAction": "Ouvrir un espace de travail...", "openWorkspaceConfigFile": "Ouvrir le Fichier de Configuration d’espace de travail", + "openFolderAsWorkspaceInNewWindow": "Ouvrir le dossier en tant qu'espace de travail dans une nouvelle fenêtre", "workspaceFolderPickerPlaceholder": "Sélectionner le dossier de l’espace de travail" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index a04b897abfe..affef8547e2 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Masquer la barre d'activités", - "activityBarAriaLabel": "Sélecteur d'affichage actif", "globalActions": "Actions globales" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..ed052dd9d9c --- /dev/null +++ b/i18n/fra/src/vs/workbench/browser/parts/compositebar/compositeBar.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. +{ + "activityBarAriaLabel": "Sélecteur d'affichage actif" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..0935a1bd196 --- /dev/null +++ b/i18n/fra/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "Vues supplémentaires", + "numberBadge": "{0} ({1})", + "manageExtension": "Gérer l'extension", + "titleKeybinding": "{0} ({1})", + "toggle": "Afficher/masquer la vue épinglée" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index dc32ce2159e..4326e29e9e4 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "Afficher les éditeurs du deuxième groupe", "groupThreePicker": "Afficher les éditeurs du troisième groupe", "allEditorsPicker": "Afficher tous les éditeurs ouverts", - "view": "Affichage" + "view": "Affichage", + "file": "Fichier" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 6e9f1b4185b..d4a3eda558a 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "La commande '{0}' n'est pas activée et ne peut pas être exécutée.", "manageExtension": "Gérer l'extension" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/fra/src/vs/workbench/electron-browser/main.contribution.i18n.json index de18c2da7d0..32259e528e6 100644 --- a/i18n/fra/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,18 +10,15 @@ "workspaces": "Espaces de travail", "developer": "Développeur", "showEditorTabs": "Contrôle si les éditeurs ouverts doivent s'afficher ou non sous des onglets.", - "workbench.editor.labelFormat.default": "Affiche le nom du fichier. Lorsque les onglets sont activés et deux fichiers portent le même nom dans un groupe les sections distinctes du chemin de chaque fichier sont ajoutées. Lorsque les onglets sont désactivées, le chemin relatif à la racine d’espace de travail est affiché si l’éditeur est actif.", "workbench.editor.labelFormat.short": "Indiquer le nom du fichier suivi de son nom de répertoire.", - "workbench.editor.labelFormat.medium": "Indiquer le nom du fichier suivi de son chemin d’accès relatif à la racine de l’espace de travail.", "workbench.editor.labelFormat.long": "Indiquer le nom du fichier suivi de son chemin d’accès absolu.", "tabDescription": "Contrôle le format de l’étiquette d’un éditeur. La modification de ce paramètre peut par exemple rendre plus facile la compréhension de l’emplacement d’un fichier :\n- short: 'parent'\n- medium: 'workspace/src/parent'\n- long: '/home/user/workspace/src/parent'\n- default: '.../parent', quand un autre onglet partage le même titre, ou la chemin d’accès relatif à l'espace de travail si les onglets sont désactivés", "editorTabCloseButton": "Contrôle la position des boutons de fermeture des onglets de l'éditeur, ou les désactive quand le paramètre a la valeur 'off'.", "showIcons": "Contrôle si les éditeurs ouverts doivent s'afficher ou non avec une icône. Cela implique notamment l'activation d'un thème d'icône.", "enablePreview": "Contrôle si les éditeurs ouverts s'affichent en mode aperçu. Les éditeurs en mode aperçu sont réutilisés jusqu'à ce qu'ils soient conservés (par exemple, après un double-clic ou une modification) et apparaissent avec un style de police en italique.", "enablePreviewFromQuickOpen": "Contrôle si les éditeurs de Quick Open s'affichent en mode aperçu. Les éditeurs en mode aperçu sont réutilisés jusqu'à ce qu'ils soient conservés (par exemple, après un double-clic ou une modification).", - "editorOpenPositioning": "Contrôle l'emplacement de l'ouverture des éditeurs. Sélectionnez 'left' ou 'right' pour ouvrir les éditeurs à gauche ou à droite de l'éditeur actuellement actif. Sélectionnez 'first' ou 'last' pour ouvrir les éditeurs indépendamment de l'éditeur actuellement actif.", "revealIfOpen": "Contrôle si un éditeur est affiché dans l'un des groupes visibles, s'il est ouvert. Si cette option est désactivée, l'éditeur s'ouvre de préférence dans le groupe d'éditeurs actif. Si cette option est activée, tout éditeur déjà ouvert est affiché au lieu d'être rouvert dans le groupe d'éditeurs actif. Notez que dans certains cas, ce paramètre est ignoré, par exemple quand vous forcez un éditeur à s'ouvrir dans un groupe spécifique ou à côté du groupe actif.", - "commandHistory": "Contrôle le nombre de commandes récemment utilisées à conserver dans l'historique de la palette de commandes. Définissez cette valeur sur 0 pour désactiver l'historique de commandes.", + "commandHistory": "Contrôle le nombre de commandes récemment utilisées à retenir dans l’historique de la palette de commande. Spécifier la valeur 0 pour désactiver l’historique des commandes.", "preserveInput": "Contrôle si la dernière entrée tapée dans la palette de commandes doit être restaurée à la prochaine ouverture.", "closeOnFocusLost": "Contrôle si Quick Open doit se fermer automatiquement, une fois qu'il a perdu le focus.", "openDefaultSettings": "Contrôle si l'ouverture des paramètres entraîne également l'ouverture d'un éditeur qui affiche tous les paramètres par défaut.", @@ -50,7 +47,7 @@ "restoreWindows": "Contrôle comment les fenêtres seront rouvertes après un redémarrage. Sélectionner 'none' pour toujours démarrer avec un espace de travail vide, 'one' pour rouvrir la dernière fenêtre avec laquelle vous avez travaillé, 'folders' pour rouvrir toutes les fenêtres qui avaient des dossiers ouverts ou 'all' pour rouvrir toutes les fenêtres de votre dernière session.", "restoreFullscreen": "Contrôle si une fenêtre doit être restaurée en mode plein écran si elle a été fermée dans ce mode.", "zoomLevel": "Modifiez le niveau de zoom de la fenêtre. La taille d'origine est 0. Chaque incrément supérieur (exemple : 1) ou inférieur (exemple : -1) représente un zoom 20 % plus gros ou plus petit. Vous pouvez également entrer des décimales pour changer le niveau de zoom avec une granularité plus fine.", - "title": "Contrôle le titre de la fenêtre en fonction de l'éditeur actif. Les variables sont remplacées selon le contexte :\n${activeEditorShort} : par ex., myFile.txt\n${activeEditorMedium} : par ex., myFolder/myFile.txt\n${activeEditorLong} : par ex., /Users/Development/myProject/myFolder/myFile.txt\n${folderName} : par ex., myFolder\n${folderPath} : par ex., /Users/Development/myFolder\n${rootName} : par ex., myFolder1, myFolder2, myFolder3\n${rootPath} : par ex., /Users/Development/myWorkspace\n${appName} : par ex., VS Code\n${dirty} : indicateur d'intégrité si l'intégrité de l'éditeur actif est compromise\n${separator} : séparateur conditionnel (\" - \") qui s'affiche uniquement quand il est entouré de variables avec des valeurs", + "title": "Contrôle le titre de la fenêtre en fonction sur l’éditeur actif. Les variables sont remplacés selon le contexte : ${activeEditorShort} : le nom du fichier (ex: monFichier.txt) ${activeEditorMedium} : le chemin d’accès au fichier par rapport au dossier de l’espace de travail (ex: monDossier/monFichier.txt) ${activeEditorLong} : le chemin d’accès complet du fichier (par exemple / Users/Developpement/monDossier/monFichier.txt) ${folderName} : nom du dossier de l’espace de travail auquel le fichier appartient (ex: mondossier) ${folderPath} : chemin d’accès du dossier de l'espace de travail auquel le fichier appartient (ex: /Users/Developpement/monDossier) {$ rootName} : nom de l’espace de travail (:. monDossier ou monEspaceDeTravail) ${rootPath} : chemin d’accès de l’espace de travail (ex: /Users/Developpement/monEspaceDeTravail) ${appName} : ex. VS Code ${dirty} : un indicateur si l’éditeur actif est modifié ${separator} : un séparateur conditionnel (\" - \") qui ne s'affiche que quand ils sont entourés par des variables avec des valeurs", "window.newWindowDimensions.default": "Permet d'ouvrir les nouvelles fenêtres au centre de l'écran.", "window.newWindowDimensions.inherit": "Permet d'ouvrir les nouvelles fenêtres avec la même dimension que la dernière fenêtre active.", "window.newWindowDimensions.maximized": "Permet d'ouvrir les nouvelles fenêtres de manière agrandie.", diff --git a/i18n/fra/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 30c636b7769..914334d0401 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, débogage", "debugAriaLabel": "Tapez le nom d'une configuration de lancement à exécuter.", + "addConfigTo": "Ajouter une configuration ({0})...", + "addConfiguration": "Ajouter une configuration...", "noConfigurationsMatching": "Aucune configuration de débogage correspondante", "noConfigurationsFound": "Configurations de débogage introuvables. Créez un fichier 'launch.json'." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..449ccd606fe --- /dev/null +++ b/i18n/fra/src/vs/workbench/parts/debug/browser/debugStatus.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. +{ + "debug": "Déboguer" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..9782a892c46 --- /dev/null +++ b/i18n/fra/src/vs/workbench/parts/debug/browser/debugViewlet.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. +{ + "debugFocusVariablesView": "Focus sur les Variables", + "debugFocusWatchView": "Focus sur Watch", + "debugFocusCallStackView": "Focus sur CallStack", + "debugFocusBreakpointsView": "Focus sur les points d'arrêts" +} \ 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 8a1e2b50d5f..5a3987eaa76 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 @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "Configurations pour la génération du fichier 'launch.json' initial.", "vscode.extension.contributes.debuggers.languages": "Liste de langages pour lesquels l'extension de débogage peut être considérée comme \"débogueur par défaut\".", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Si l'extension VS Code spécifiée appelle cette commande pour déterminer le chemin de l'exécutable de l'adaptateur de débogage et les arguments à passer.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Si l'extension VS Code spécifiée appelle cette commande pour les actions \"debug\" ou \"run\" ciblées pour cette extension.", "vscode.extension.contributes.debuggers.configurationSnippets": "Extraits pour l'ajout de nouvelles configurations à 'launch.json'.", "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.", diff --git a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index d8dbd301b65..a5a92077a68 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,10 +12,10 @@ "breakpointRemoved": "Point d'arrêt supprimé, ligne {0}, fichier {1}", "compoundMustHaveConfigurations": "L'attribut \"configurations\" du composé doit être défini pour permettre le démarrage de plusieurs configurations.", "configMissing": "Il manque la configuration '{0}' dans 'launch.json'.", - "debugRequestNotSupported": "La configuration de débogage choisie a une valeur d’attribut non prise en charge `{0}` : `{1}`.", - "debugRequesMissing": "L’attribut `{0}` est introuvable dans la configuration de débogage choisie.", + "debugRequestNotSupported": "L’attribut '{0}' a une valeur '{1}' non prise en charge dans la configuration de débogage sélectionnée.", + "debugRequesMissing": "L’attribut '{0}' est introuvable dans la configuration de débogage sélectionnée.", "debugTypeNotSupported": "Le type de débogage '{0}' configuré n'est pas pris en charge.", - "debugTypeMissing": "Propriété 'type' manquante pour la configuration de lancement choisie.", + "debugTypeMissing": "La propriété 'type' est manquante pour la configuration de lancement sélectionnée.", "preLaunchTaskErrors": "Des erreurs de build ont été détectées durant le preLaunchTask '{0}'.", "preLaunchTaskError": "Une erreur de build a été détectée durant le preLaunchTask '{0}'.", "preLaunchTaskExitCode": "Le preLaunchTask '{0}' s'est terminé avec le code de sortie {1}.", diff --git a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 9fa5e84fe4a..93c9076aca7 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -8,5 +8,5 @@ "replVariableAriaLabel": "La variable {0} a la valeur {1}, boucle REPL (Read Eval Print Loop), débogage", "replExpressionAriaLabel": "L'expression {0} a la valeur {1}, boucle REPL (Read Eval Print Loop), débogage", "replValueOutputAriaLabel": "{0}, boucle REPL (Read Eval Print Loop), débogage", - "replKeyValueOutputAriaLabel": "La variable de sortie {0} a la valeur {1}, boucle REPL (Read Eval Print Loop), débogage" + "replRawObjectAriaLabel": "La variable Repl {0} a la valeur {1}, read eval print loop, débogage" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index 2a8a3d2e72c..c0057e5215c 100644 --- a/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "Fichiers", + "filesCategory": "Fichier", "revealInSideBar": "Afficher dans la barre latérale", "acceptLocalChanges": "Utiliser vos modifications et écraser les contenus du disque", "revertLocalChanges": "Ignorer les modifications et revenir au contenu sur le disque" diff --git a/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 78b61033acc..05c3150dcf4 100644 --- a/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "Voulez-vous vraiment supprimer '{0}' ?", "undoBin": "Vous pouvez effectuer une restauration à partir de la Corbeille.", "undoTrash": "Vous pouvez effectuer une restauration à partir de la Poubelle.", + "doNotAskAgain": "Ne plus me demander", "confirmDeleteMessageFolder": "Voulez-vous vraiment supprimer définitivement '{0}' et son contenu ?", "confirmDeleteMessageFile": "Voulez-vous vraiment supprimer définitivement '{0}' ?", "irreversible": "Cette action est irréversible !", @@ -37,8 +38,6 @@ "openToSide": "Ouvrir sur le côté", "compareSource": "Sélectionner pour comparer", "globalCompareFile": "Comparer le fichier actif à...", - "pickHistory": "Sélectionnez un fichier ouvert à comparer", - "unableToFileToCompare": "Impossible de comparer le fichier sélectionné à '{0}'.", "openFileToCompare": "Ouvrez d'abord un fichier pour le comparer à un autre fichier.", "compareWith": "Comparer '{0}' à '{1}'", "compareFiles": "Comparer des fichiers", @@ -47,7 +46,7 @@ "saveAs": "Enregistrer sous...", "saveAll": "Enregistrer tout", "saveAllInGroup": "Enregistrer tout dans le groupe", - "saveFiles": "Enregistrer les fichiers à l'intégrité compromise", + "saveFiles": "Enregistrer tous les fichiers", "revert": "Rétablir le fichier", "focusOpenEditors": "Mettre le focus sur la vue des éditeurs ouverts", "focusFilesExplorer": "Focus sur l'Explorateur de fichiers", diff --git a/i18n/fra/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 066934ce4c8..9693ca31c50 100644 --- a/i18n/fra/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -40,10 +40,14 @@ "dynamicHeight": "Contrôle si la hauteur de la section des éditeurs ouverts doit s'adapter dynamiquement ou non au nombre d'éléments.", "autoReveal": "Contrôle si l'Explorateur doit automatiquement afficher et sélectionner les fichiers à l'ouverture.", "enableDragAndDrop": "Contrôle si l'explorateur doit autoriser le déplacement de fichiers et de dossiers par glisser-déplacer.", + "confirmDragAndDrop": "Contrôle si l’Explorateur doit demander confirmation lors du déplacement de fichiers ou de dossiers via glisser-déposer.", + "confirmDelete": "Contrôle si l’explorateur doit demander confirmation lorsque vous supprimez un fichier via la corbeille.", "sortOrder.default": "Les fichiers et dossiers sont triés par nom, dans l’ordre alphabétique. Les dossiers sont affichés avant les fichiers.", "sortOrder.mixed": "Les fichiers et dossiers sont triés par nom, dans l’ordre alphabétique. Les fichiers sont imbriqués dans les dossiers.", "sortOrder.filesFirst": "Les fichiers et dossiers sont triés par nom, dans l’ordre alphabétique. Les fichiers sont affichés avant les dossiers.", "sortOrder.type": "Les fichiers et dossiers sont triés par extension, dans l’ordre alphabétique. Les dossiers sont affichés avant les fichiers.", "sortOrder.modified": "Les fichiers et dossiers sont triés par date de dernière modification, dans l’ordre décroissant. Les dossiers sont affichés avant les fichiers.", - "sortOrder": "Contrôle l'ordre de tri des fichiers et dossiers dans l'explorateur. En plus du tri par défaut, vous pouvez définir l'ordre sur 'mixed' (fichiers et dossiers triés combinés), 'type' (par type de fichier), 'modified' (par date de dernière modification) ou 'fileFirst' (trier les fichiers avant les dossiers)." + "sortOrder": "Contrôle l'ordre de tri des fichiers et dossiers dans l'explorateur. En plus du tri par défaut, vous pouvez définir l'ordre sur 'mixed' (fichiers et dossiers triés combinés), 'type' (par type de fichier), 'modified' (par date de dernière modification) ou 'fileFirst' (trier les fichiers avant les dossiers).", + "explorer.decorations.colors": "Contrôle si les décorations de fichier doivent utiliser des couleurs.", + "explorer.decorations.badges": "Contrôle si les décorations de fichier doivent utiliser des badges." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/fra/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 8d920cf85ed..a44dd00649c 100644 --- a/i18n/fra/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "Aucun dossier ouvert", "explorerSection": "Section de l'Explorateur de fichiers", - "noWorkspaceHelp": "Vous n'avez pas encore ouvert de dossier.", + "noWorkspaceHelp": "Vous n’avez pas encore ajouté un dossier à l’espace de travail.", + "addFolder": "Ajouter un dossier", + "noFolderHelp": "Vous n'avez pas encore ouvert de dossier.", "openFolder": "Ouvrir le dossier" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/fra/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index b4031885489..c30df4ecd5b 100644 --- a/i18n/fra/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -4,12 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "canNotResolve": "Impossible de résoudre le dossier {0}", "fileInputAriaLabel": "Tapez le nom du fichier. Appuyez sur Entrée pour confirmer ou sur Échap pour annuler.", "filesExplorerViewerAriaLabel": "{0}, Explorateur de fichiers", "dropFolders": "Voulez-vous ajouter les dossiers à l’espace de travail ?", "dropFolder": "Voulez-vous ajouter le dossier à l’espace de travail ?", "addFolders": "&&Ajouter les dossiers", "addFolder": "&&Ajouter le dossier", + "confirmMove": "Êtes-vous certain de vouloir déplacer '{0}' ?", + "doNotAskAgain": "Ne plus me demander", "confirmOverwriteMessage": "{0}' existe déjà dans le dossier de destination. Voulez-vous le remplacer ?", "irreversible": "Cette action est irréversible !", "replaceButtonLabel": "&&Remplacer" diff --git a/i18n/fra/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/fra/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..72ea24da7b8 --- /dev/null +++ b/i18n/fra/src/vs/workbench/parts/markers/browser/markersFileDecorations.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. +{ + "label": "Problèmes", + "tooltip.1": "1 problème dans ce fichier", + "tooltip.N": "{0} problèmes dans ce fichier", + "markers.showOnFile": "Afficher les erreurs & les avertissements sur les fichiers et dossiers." +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index 3684b913ba7..2c9bee3d6c2 100644 --- a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "Placer vos paramètres ici pour remplacer les paramètres par défaut.", - "errorInvalidConfiguration": "Impossible d'écrire les paramètres. Corrigez les erreurs/avertissements présents dans le fichier, puis réessayez.", "emptyWorkspaceSettingsHeader": "Placer vos paramètres ici pour remplacer les paramètres utilisateur.", "emptyFolderSettingsHeader": "Placer les paramètres de votre dossier ici pour remplacer ceux des paramètres de l’espace de travail.", "defaultFolderSettingsTitle": "Paramètres de dossier par défaut", diff --git a/i18n/fra/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/fra/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 1c20cdc1e83..9806bbb1795 100644 --- a/i18n/fra/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "La commande '{0}' n'est pas activée dans le contexte actuel.", "recentlyUsed": "récemment utilisées", "morecCommands": "autres commandes", - "commandLabel": "{0} : {1}", "cat.title": "{0} : {1}", "noCommandsMatching": "Aucune commande correspondante" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/fra/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index e9c5ba38792..9e292a57bbd 100644 --- a/i18n/fra/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,6 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "{0} sur {1} modifications", + "change": "{0} sur {1} modification", + "show previous change": "Voir la modification précédente", + "show next change": "Voir la modification suivante", "editorGutterModifiedBackground": "Couleur d'arrière-plan de la reliure de l'éditeur pour les lignes modifiées.", "editorGutterAddedBackground": "Couleur d'arrière-plan de la reliure de l'éditeur pour les lignes ajoutées.", "editorGutterDeletedBackground": "Couleur d'arrière-plan de la reliure de l'éditeur pour les lignes supprimées.", diff --git a/i18n/fra/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index a2647c9191c..079ee64e791 100644 --- a/i18n/fra/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -17,7 +17,7 @@ "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.", "exclude.when": "Vérification supplémentaire des frères d'un fichier correspondant. Utilisez $(basename) comme variable pour le nom de fichier correspondant.", - "useRipgrep": "Contrôle si ripgrep doit être utilisé dans la recherche de texte", + "useRipgrep": "Contrôle si ripgrep doit être utilisé dans la recherche de texte et de fichier", "useIgnoreFilesByDefault": "Indique s'il faut utiliser les fichiers .gitignore et .ignore par défaut en cas de recherche dans un nouvel espace de travail.", "search.quickOpen.includeSymbols": "Configurez l'ajout des résultats d'une recherche de symboles globale dans le fichier de résultats pour Quick Open." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/fra/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 2478230b806..e43ec2a86c7 100644 --- a/i18n/fra/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -19,7 +19,6 @@ "ClearSearchResultsAction.label": "Effacer les résultats de la recherche", "FocusNextSearchResult.label": "Focus sur le résultat de la recherche suivant", "FocusPreviousSearchResult.label": "Focus sur le résultat de la recherche précédent", - "RemoveAction.label": "Supprimer", "file.replaceAll.label": "Tout remplacer", "match.replace.label": "Remplacer" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index b340098147f..344eb79e2cd 100644 --- a/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,8 +10,8 @@ "vscode.extension.contributes.snippets": "Ajoute des extraits de code.", "vscode.extension.contributes.snippets-language": "Identificateur de langage pour lequel cet extrait de code est ajouté.", "vscode.extension.contributes.snippets-path": "Chemin du fichier d'extraits de code. Le chemin est relatif au dossier d'extensions et commence généralement par './snippets/'.", - "badFile": "Le fichier d’extrait \"{0}\" n’a pas pu être lu.", "badVariableUse": "L'extrait de code \"{0}\" confond très probablement les variables et les espaces réservés d'extrait de code. Consultez https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax pour plus d'informations.", + "badFile": "Le fichier d’extrait \"{0}\" n’a pas pu être lu.", "source.snippet": "Extrait de code utilisateur", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 0f3f74aef8d..abe24c7ec4d 100644 --- a/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -14,6 +14,7 @@ "runningTasks": "Afficher les tâches en cours d'exécution", "tasks": "Tâches", "TaskSystem.noHotSwap": "Changer le moteur d’exécution de tâches avec une tâche active en cours d’exécution nécessite de recharger la fenêtre", + "TaskServer.folderIgnored": "Le dossier {0} est ignoré car il utilise la version 0.1.0 de task", "TaskService.noBuildTask1": "Aucune tâche de build définie. Marquez une tâche avec 'isBuildCommand' dans le fichier tasks.json.", "TaskService.noBuildTask2": "Aucune tâche de génération définie. Marquez une tâche comme groupe 'build' dans le fichier tasks.json.", "TaskService.noTestTask1": "Aucune tâche de test définie. Marquez une tâche avec 'isTestCommand' dans le fichier tasks.json.", @@ -30,6 +31,7 @@ "TaskSystem.activeSame.noBackground": "La tâche '{0}' est déjà active. Pour la terminer, il utilise `Terminer la Tâche...` dans le menu Tâches.", "TaskSystem.active": "Une tâche est déjà en cours d'exécution. Terminez-la avant d'exécuter une autre tâche.", "TaskSystem.restartFailed": "Échec de la fin de l'exécution de la tâche {0}", + "TaskService.noConfiguration": "Erreur : La détection de la tâche {0} n’a pas contribué à une tâche pour la configuration suivante : {1}, la tâche sera ignorée.\n", "TaskSystem.configurationErrors": "Erreur : la configuration de tâche fournie comporte des erreurs de validation et ne peut pas être utilisée. Corrigez d'abord les erreurs.", "taskService.ignoreingFolder": "Les configurations de tâche seront ignorées pour le dossier de l’espace de travail {0}. Le support de la tâche d'espace de travail multi-dossier requiert que tous les dossiers utilisent task version 2.0.0\n", "TaskSystem.invalidTaskJson": "Erreur : le fichier tasks.json contient des erreurs de syntaxe. Corrigez-les avant d'exécuter une tâche.\n", diff --git a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index 8a455dbd3c0..8e54d84198f 100644 --- a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -17,6 +17,7 @@ "terminal.integrated.fontFamily": "Contrôle la famille de polices du terminal. La valeur par défaut est la valeur associée à editor.fontFamily.", "terminal.integrated.fontSize": "Contrôle la taille de police en pixels du terminal.", "terminal.integrated.lineHeight": "Contrôle la hauteur de ligne du terminal. La multiplication de ce nombre par la taille de police du terminal permet d'obtenir la hauteur de ligne réelle en pixels.", + "terminal.integrated.enableBold": "Indique s'il faut activer le texte en gras dans le terminal, notez que cela nécessite la prise en charge du terminal Shell.", "terminal.integrated.cursorBlinking": "Contrôle si le curseur du terminal clignote.", "terminal.integrated.cursorStyle": "Contrôle le style du curseur du terminal.", "terminal.integrated.scrollback": "Contrôle la quantité maximale de lignes que le terminal conserve dans sa mémoire tampon.", 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 c06b522fc53..b1d65f3e2d3 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 @@ -16,7 +16,6 @@ "workbench.action.terminal.new.short": "Nouveau terminal", "workbench.action.terminal.focus": "Focus sur le terminal", "workbench.action.terminal.focusNext": "Focus sur le terminal suivant", - "workbench.action.terminal.focusAtIndex": "Focus sur le terminal {0}", "workbench.action.terminal.focusPrevious": "Focus sur le terminal précédent", "workbench.action.terminal.paste": "Coller dans le terminal actif", "workbench.action.terminal.DefaultShell": "Sélectionner l'interpréteur de commandes par défaut", diff --git a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 7aeb29b6337..aa7d60b35db 100644 --- a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Copier", - "createNewTerminal": "Nouveau terminal", "paste": "Coller", "selectAll": "Tout Sélectionner", "clear": "Effacer" diff --git a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 4692e6dfcd1..d636f6886f8 100644 --- a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "OK, ne plus afficher", "terminal.integrated.chooseWindowsShell": "Sélectionnez votre interpréteur de commandes de terminal favori. Vous pouvez le changer plus tard dans vos paramètres", "terminalService.terminalCloseConfirmationSingular": "Il existe une session de terminal active. Voulez-vous la tuer ?", - "terminalService.terminalCloseConfirmationPlural": "Il existe {0} sessions de terminal actives. Voulez-vous les tuer ?", - "yes": "Oui" + "terminalService.terminalCloseConfirmationPlural": "Il existe {0} sessions de terminal actives. Voulez-vous les tuer ?" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/fra/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..c93a0aa18c9 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "Résumé des paramètres. Cette étiquette va être utilisée dans le fichier de paramètres en tant que commentaire de séparation.", + "vscode.extension.contributes.configuration.properties": "Description des propriétés de configuration.", + "scope.window.description": "Configuration spécifique de la fenêtre, qui peut être configurée dans les paramètres utilisateur ou de l'espace de travail.", + "scope.resource.description": "Configuration spécifique de la ressource, qui peut être configurée dans les paramètres utilisateur, de l'espace de travail ou du dossier.", + "scope.description": "Portée dans laquelle la configuration s’applique. Les portées disponibles sont `window` et `resource`.", + "vscode.extension.contributes.configuration": "Ajoute des paramètres de configuration.", + "invalid.title": "'configuration.title' doit être une chaîne", + "vscode.extension.contributes.defaultConfiguration": "Contribue aux paramètres de configuration d'éditeur par défaut en fonction du langage.", + "invalid.properties": "'configuration.properties' doit être un objet", + "invalid.allOf": "'configuration.allOf' est obsolète et ne doit plus être utilisé. Au lieu de cela, passez plusieurs sections de configuration sous forme de tableau au point de contribution 'configuration'.", + "workspaceConfig.folders.description": "Liste des dossiers à être chargés dans l’espace de travail.", + "workspaceConfig.path.description": "Un chemin de fichier, par exemple, '/root/folderA' ou './folderA' pour un chemin relatif résolu selon l’emplacement du fichier d’espace de travail.", + "unknownWorkspaceProperty": "Propriété de configuration d’espace de travail inconnue" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/fra/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/editor/common/editorService.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. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/fra/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index d9200a0b879..72ed7866243 100644 --- a/i18n/fra/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/fra/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -6,6 +6,7 @@ { "schema.token.settings": "Couleurs et styles du jeton.", "schema.token.foreground": "Couleur de premier plan du jeton.", + "schema.token.background.warning": "Les couleurs d’arrière-plan des tokens ne sont actuellement pas pris en charge.", "schema.token.fontStyle": "Style de police de la règle : 'italique', 'gras' ou 'souligné', ou une combinaison de ces styles", "schema.fontStyle.error": "Le style de police doit être une combinaison de 'italic', 'bold' et 'underline'", "schema.properties.name": "Description de la règle.", diff --git a/i18n/fra/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/fra/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index 47c337cef4b..d920cb0bcb8 100644 --- a/i18n/fra/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/fra/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "Quand une police est utilisée : taille de police en pourcentage par rapport à la police du texte. En l'absence de définition, la taille de la définition de police est utilisée par défaut.", "schema.fontId": "Quand une police est employée : ID de la police. En l'absence de définition, la première définition de police est utilisée par défaut.", "schema.light": "Associations facultatives des icônes de fichiers dans les thèmes de couleur claire.", - "schema.highContrast": "Associations facultatives des icônes de fichiers dans les thèmes de couleur à contraste élevé." + "schema.highContrast": "Associations facultatives des icônes de fichiers dans les thèmes de couleur à contraste élevé.", + "schema.hidesExplorerArrows": "Détermine si les flèches de l’Explorateur de fichier doivent être masquées lorsque ce thème est actif." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/fra/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..63c65b5f2e0 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.themes": "Contributes textmate color themes.", + "vscode.extension.contributes.themes.id": "ID du thème d'icône utilisé dans les paramètres utilisateur.", + "vscode.extension.contributes.themes.label": "Étiquette du thème de couleur comme indiqué dans l'interface utilisateur (IU).", + "vscode.extension.contributes.themes.uiTheme": "Thème de base définissant les couleurs autour de l'éditeur : 'vs' est le thème de couleur clair, 'vs-dark' est le thème de couleur sombre. 'hc-black' est le thème sombre à contraste élevé.", + "vscode.extension.contributes.themes.path": "Chemin du fichier tmTheme. Le chemin est relatif au dossier d'extensions et correspond généralement à './themes/themeFile.tmTheme'.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "Chaîne attendue dans 'contributes.{0}.path'. Valeur fournie : {1}", + "invalid.path.1": "'contributes.{0}.path' ({1}) est censé être inclus dans le dossier ({2}) de l'extension. Cela risque de rendre l'extension non portable." +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/fra/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..b0f9faf6b52 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.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. +{ + "error.cannotparseicontheme": "Problems parsing file icons file: {0}" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/fra/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..0c251843630 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "ID du thème d'icône utilisé dans les paramètres utilisateur.", + "vscode.extension.contributes.iconThemes.label": "Étiquette du thème d'icône indiqué dans l'IU (interface utilisateur).", + "vscode.extension.contributes.iconThemes.path": "Chemin du fichier de définitions de thèmes d'icônes. Le chemin est relatif au dossier d'extensions et correspond généralement à './icons/awesome-icon-theme.json'.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "Chaîne attendue dans 'contributes.{0}.path'. Valeur fournie : {1}", + "reqid": "Chaîne attendue dans 'contributes.{0}.id'. Valeur fournie : {1}", + "invalid.path.1": "'contributes.{0}.path' ({1}) est censé être inclus dans le dossier ({2}) de l'extension. Cela risque de rendre l'extension non portable." +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/fra/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index 8ca3299b2ba..234d5fb5a0e 100644 --- a/i18n/fra/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/fra/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,31 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "ID du thème d'icône utilisé dans les paramètres utilisateur.", - "vscode.extension.contributes.themes.label": "Étiquette du thème de couleur comme indiqué dans l'interface utilisateur (IU).", - "vscode.extension.contributes.themes.uiTheme": "Thème de base définissant les couleurs autour de l'éditeur : 'vs' est le thème de couleur clair, 'vs-dark' est le thème de couleur sombre. 'hc-black' est le thème sombre à contraste élevé.", - "vscode.extension.contributes.themes.path": "Chemin du fichier tmTheme. Le chemin est relatif au dossier d'extensions et correspond généralement à './themes/themeFile.tmTheme'.", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "ID du thème d'icône utilisé dans les paramètres utilisateur.", - "vscode.extension.contributes.iconThemes.label": "Étiquette du thème d'icône indiqué dans l'IU (interface utilisateur).", - "vscode.extension.contributes.iconThemes.path": "Chemin du fichier de définitions de thèmes d'icônes. Le chemin est relatif au dossier d'extensions et correspond généralement à './icons/awesome-icon-theme.json'.", "migration.completed": "De nouveaux paramètres de thème ont été ajoutés aux paramètres utilisateur. Sauvegarde disponible sur {0}.", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "Chaîne attendue dans 'contributes.{0}.path'. Valeur fournie : {1}", - "invalid.path.1": "'contributes.{0}.path' ({1}) est censé être inclus dans le dossier ({2}) de l'extension. Cela risque de rendre l'extension non portable.", - "reqid": "Chaîne attendue dans 'contributes.{0}.id'. Valeur fournie : {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "Spécifie le thème d'icône utilisé dans le banc d'essai ou 'null' pour n'afficher aucune icône de fichier.", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "Remplace les couleurs du thème de couleur sélectionné.", - "workbenchColors.deprecated": "Le paramètre n'est plus expérimental et a été renommé 'workbench.colorCustomizations'", - "workbenchColors.deprecatedDescription": "Utiliser 'workbench.colorCustomizations' à la place", "editorColors": "Remplace les couleurs et le style de la police de l’éditeur du thème par la couleur actuellement sélectionnée.", "editorColors.comments": "Définit les couleurs et les styles des commentaires", "editorColors.strings": "Définit les couleurs et les styles des littéraux de chaînes.", diff --git a/i18n/fra/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/fra/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..e6f04379725 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/workspace/node/workspaceEditingService.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. +{ + "openWorkspaceConfigurationFile": "Ouvrir le Fichier de Configuration d’espace de travail", + "close": "Fermer" +} \ No newline at end of file diff --git a/i18n/hun/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/hun/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index 73e2b227f47..b0baf1f7552 100644 --- a/i18n/hun/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/hun/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "pl.: myFile.txt", - "activeEditorMedium": "pl.: myFolder/myFile.txt", - "activeEditorLong": "pl.: /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "pl.: myFolder1, myFolder2, myFolder3", - "rootPath": "pl.: /Users/Development/myProject", - "folderName": "pl.: myFolder", - "folderPath": "pl.: /Users/Development/myProject", + "activeEditorShort": "a fájl neve (pl. myFile.txt)", + "activeEditorMedium": "a fájl relatív elérési útja a munkaterület mappájához képest (pl. myFolder/myFile.txt)", + "activeEditorLong": "a fájl teljes elérési útja (pl. /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "a munkaterület neve (pl. myFolder vagy myWorkspace)", + "rootPath": "a munkaterület elérési útja (pl. /Users/Development/myWorkspace)", + "folderName": "azon munkaterületi mappa a neve, amelyben a fájl található (pl. myFolder)", + "folderPath": "azon munkaterületi mappa elérési útja, amelyben a fájl található (pl. /Users/Development/myFolder)", "appName": "pl.: VS Code", "dirty": "módosításjelző, ami akkor jelenik meg, ha az aktív szerkesztőablak tartalma módosítva lett", "separator": "egy feltételes elválasztó (' - '), ami akkor jelenik meg, ha olyan változókkal van körülvéve, amelyeknek van értéke", diff --git a/i18n/hun/extensions/emmet/package.i18n.json b/i18n/hun/extensions/emmet/package.i18n.json index 576657ed646..e8dd71aabaa 100644 --- a/i18n/hun/extensions/emmet/package.i18n.json +++ b/i18n/hun/extensions/emmet/package.i18n.json @@ -28,13 +28,6 @@ "command.incrementNumberByTen": "Növelés 10-zel", "command.decrementNumberByTen": "Csökkentés 10-zel", "emmetSyntaxProfiles": "Konkrét szintaktika profiljának meghatározása vagy saját profil használata adott szabályokkal.", - "emmetExclude": "Azon nyelvek listája, ahol az Emmet-rövidítések ne legyenek kibontva.", - "emmetExtensionsPath": "Egy Emmet-profilokat és -kódtöredékeket tartalmazó mappa elérési útja.", - "emmetShowExpandedAbbreviation": "Kibontott emmet-rövidítések megjelenítése javaslatként. Az \"inMarkupAndStylesheetFilesOnly\" beállítás csak a html, haml, jade, slim, xml, xsl, css, scss, sass, less és stylus típusú tartalmat jelenti. Az \"always\" beállítás a fájl összes részére vonatkozik a jelölőnyelvtől/css-től függetlenül.", - "emmetShowAbbreviationSuggestions": "A lehetséges emmet-rövidítések megjelenítése javaslatként. Nem használható a stíluslapokon vagy ha az emmet.showExpandedAbbreviation értéke \"never\".", - "emmetIncludeLanguages": "Emmet-rövidítések engedélyezése olyan nyelvek esetében, amelyek alapértelmezés szerint nem támogatottak. Egy megfeleltetést kell felvenni a nyelv és egy emmet által támogatott nyelv között.\nPl.: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", - "emmetVariables": "Az emmet-kódrészletekben használt változók", - "emmetTriggerExpansionOnTab": "Ha engedélyezve van, akkor az Emmet-rövidítések a Tab billentyű lenyomásával bonthatók ki.", "emmetPreferences": "Beállítások, melyek módosítják az Emmet műveleteinek és feloldó algoritmusainak viselkedését.", "emmetPreferencesIntUnit": "Az egész számok alapértelmezett mértékegysége", "emmetPreferencesFloatUnit": "A lebegőpontos számok alapértelmezett mértékegysége", @@ -44,5 +37,7 @@ "emmetPreferencesCssBetween": "A CSS-tulajdonság és az érték közé helyezett szimbólum CSS-rövidítések kibontásánál", "emmetPreferencesSassBetween": "A CSS-tulajdonság és az érték közé helyezett szimbólum CSS-rövidítések kibontásánál Sass-fájlokban", "emmetPreferencesStylusBetween": "A CSS-tulajdonság és az érték közé helyezett szimbólum CSS-rövidítések kibontásánál Stylus-fájlokban", - "emmetShowSuggestionsAsSnippets": "Ha az értéke igaz, akkor az emmetes javaslatok kódrészletekként jelennek meg, ami lehetővé teszi az editor.snippetSuggestions beállítás alapján történő rendezésüket." + "emmetPreferencesFilterCommentBefore": "Annak a megjegyzésnek a definíciója, ami az illeszkedő elem elé kerül a megjegyzésszűrő alkalmazása esetén.", + "emmetPreferencesFilterCommentAfter": "Annak a megjegyzésnek a definíciója, ami az illeszkedő elem mögé kerül a megjegyzésszűrő alkalmazása esetén.", + "emmetPreferencesFilterCommentTrigger": "Attribútumnevek vesszővel elválasztott listája, amelyeknek léteznie kell a megjegyzésszűrő alkalmazásához." } \ No newline at end of file diff --git a/i18n/hun/extensions/git/out/commands.i18n.json b/i18n/hun/extensions/git/out/commands.i18n.json index e3a35609258..ed82f751b7f 100644 --- a/i18n/hun/extensions/git/out/commands.i18n.json +++ b/i18n/hun/extensions/git/out/commands.i18n.json @@ -12,8 +12,9 @@ "cloning": "Git-forráskódtár klónozása...", "openrepo": "Forráskódtár megnyitása", "proposeopen": "Szeretné megnyitni a klónozott forráskódtárat?", - "path to init": "Mappa elérési útja", - "provide path": "Git-forráskódtár inicializálásához adjon meg egy elérési utat!", + "init repo": "Forráskódtár előkészítése", + "create repo": "Forráskódtár előkészítése", + "are you sure": "A művelet egy Git forráskódtárat hoz létre a következő helyen: '{0}. Biztosan szeretné folytatni?", "HEAD not available": "A(z) '{0}' HEAD-verziója nem elérhető.", "confirm stage files with merge conflicts": "Biztosan elő szeretne jegyezni {0} ütközési konfliktussal rendelkező fájlt?", "confirm stage file with merge conflicts": "Biztosan elő szeretne jegyezni a következő, ütközési konfliktussal rendelkező fájlt: {0}?", diff --git a/i18n/hun/extensions/git/out/repository.i18n.json b/i18n/hun/extensions/git/out/repository.i18n.json index 360a4435ac6..386f0a265df 100644 --- a/i18n/hun/extensions/git/out/repository.i18n.json +++ b/i18n/hun/extensions/git/out/repository.i18n.json @@ -21,6 +21,8 @@ "deleted by us": "Általunk törölt", "both added": "Mindkettő hozzáadta", "both modified": "Mindkettő módosította", + "untracked, short": "N", + "modified, short": "M", "commit": "Commit", "merge changes": "Módosítások összeolvasztása", "staged changes": "Beadásra előjegyzett módosítások", diff --git a/i18n/hun/extensions/git/package.i18n.json b/i18n/hun/extensions/git/package.i18n.json index 3aff31e4cd7..81661105b4d 100644 --- a/i18n/hun/extensions/git/package.i18n.json +++ b/i18n/hun/extensions/git/package.i18n.json @@ -15,6 +15,8 @@ "command.stageAll": "Összes módosítás előjegyzése beadásra", "command.stageSelectedRanges": "Kijelölt területek előjegyzése beadásra", "command.revertSelectedRanges": "Kijelölt területek visszaállítása", + "command.stageChange": "Változás előjegyzése beadásra", + "command.revertChange": "Változtatás visszavonása", "command.unstage": "Módosítások előjegyzésének törlése", "command.unstageAll": "Minden módosítás előjegyzésének törlése", "command.unstageSelectedRanges": "Kijelölt területek előjegyzésének törlése", diff --git a/i18n/hun/extensions/typescript/package.i18n.json b/i18n/hun/extensions/typescript/package.i18n.json index 031efbd3fe4..3b45505e009 100644 --- a/i18n/hun/extensions/typescript/package.i18n.json +++ b/i18n/hun/extensions/typescript/package.i18n.json @@ -44,7 +44,8 @@ "typescript.npm": "Az automatikus típusdefiníció-letöltéshez használt NPM végrehajtható fájl elérési útja. TypeScript 2.3.4-et igényel.", "typescript.check.npmIsInstalled": "Ellenőrizze, hogy az NPM telepítve van-e az automatikus típusdefiníció-letöltéshez.", "javascript.nameSuggestions": "Egyedi nevek listázásának engedélyezése a javascriptes javaslati listákban.", - "typescript.tsc.autoDetect": "Meghatározza, hogy a tsc-feladatok automatikus felderítése be van-e kapcsolva.", + "typescript.tsc.autoDetect": "Meghatározza a tsc-s feladatok automatikus felderítésének működését. 'off' érték esetén a funkció ki van kapcsolva. 'build' esetén egyszer lefutó, fordítást végző feladatok jönnek létre. 'watch' esetén csak fordítást és figyelést végző feladatok jönnek létre. 'on' esetén buildelési és figyelési feladatok is keletkeznek. Az alapértelmezett érték: 'on'.", "typescript.problemMatchers.tsc.label": "TypeScript-problémák", - "typescript.problemMatchers.tscWatch.label": "TypeScript-problémák (figyelő módban)" + "typescript.problemMatchers.tscWatch.label": "TypeScript-problémák (figyelő módban)", + "typescript.quickSuggestionsForPaths": "Kiegészítési javaslatok engedélyezése importált elérési utak beírásakor." } \ No newline at end of file diff --git a/i18n/hun/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/hun/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 2e445d0ec2e..43d34e8aacc 100644 --- a/i18n/hun/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/hun/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,6 @@ "label.replaceButton": "Csere", "label.replaceAllButton": "Az összes előfordulás cseréje", "label.toggleReplaceButton": "Váltás csere módra", - "title.matchesCountLimit": "Csak az első 999 találat van kiemelve, de minden keresési művelet a teljes szöveggel dolgozik.", "label.matchesLocation": "{0} (összesen {1})", "label.noResults": "Nincs eredmény" } \ No newline at end of file diff --git a/i18n/hun/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/hun/src/vs/editor/contrib/find/common/findController.i18n.json index b502771aa98..6e1f33bceda 100644 --- a/i18n/hun/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/hun/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "Következő kijelölés", "previousSelectionMatchFindAction": "Előző kijelölés", "startReplace": "Csere", - "addSelectionToNextFindMatch": "Kijelölés hozzáadása a következő keresési találathoz", - "addSelectionToPreviousFindMatch": "Kijelölés hozzáadása az előző keresési találathoz", - "moveSelectionToNextFindMatch": "Utolsó kijelölés áthelyezése a következő keresési találatra", - "moveSelectionToPreviousFindMatch": "Utolsó kijelölés áthelyezése az előző keresési találatra", - "selectAllOccurrencesOfFindMatch": "Az összes keresési találat kijelölése", - "changeAll.label": "Minden előfordulás módosítása", "showNextFindTermAction": "Következő keresési kifejezés megjelenítése", "showPreviousFindTermAction": "Előző keresési kifejezés megjelenítése" } \ No newline at end of file diff --git a/i18n/hun/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/hun/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 8aa3dbca9ff..f50dc975843 100644 --- a/i18n/hun/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/hun/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Kurzor beszúrása egy sorral feljebb", "mutlicursor.insertBelow": "Kurzor beszúrása egy sorral lejjebb", - "mutlicursor.insertAtEndOfEachLineSelected": "Kurzor beszúrása a sorok végére" + "mutlicursor.insertAtEndOfEachLineSelected": "Kurzor beszúrása a sorok végére", + "addSelectionToNextFindMatch": "Kijelölés hozzáadása a következő keresési találathoz", + "addSelectionToPreviousFindMatch": "Kijelölés hozzáadása az előző keresési találathoz", + "moveSelectionToNextFindMatch": "Utolsó kijelölés áthelyezése a következő keresési találatra", + "moveSelectionToPreviousFindMatch": "Utolsó kijelölés áthelyezése az előző keresési találatra", + "selectAllOccurrencesOfFindMatch": "Az összes keresési találat kijelölése", + "changeAll.label": "Minden előfordulás módosítása" } \ No newline at end of file diff --git a/i18n/hun/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/hun/src/vs/platform/theme/common/colorRegistry.i18n.json index 8cfb21c1837..1d88bef987d 100644 --- a/i18n/hun/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/hun/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "Érvénytelen színformátum. Az #RGB, #RGBA, #RRGGBB vagy #RRGGBBAA formátum használható.", "schema.colors": "A munkaterületen használt színek.", "foreground": "Általános előtérszín. Csak akkor van használva, ha nem írja felül az adott komponens.", "errorForeground": "A hibaüzenetek általános előtérszíne. Csak akkor van használva, ha nem írja felül az adott komponens.", diff --git a/i18n/hun/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/hun/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 64c1ec455b3..854d2bb1a23 100644 --- a/i18n/hun/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/hun/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -9,14 +9,17 @@ "addFolderToWorkspace": "Mappa hozzáadása a munkaterülethez...", "add": "&&Hozzáadás", "addFolderToWorkspaceTitle": "Mappa hozzáadása a munkaterülethez", + "globalRemoveFolderFromWorkspace": "Mappa eltávolítása a munkaterületről...", "newWorkspace": "Új munkaterület...", "select": "&&Kiválasztás", "selectWorkspace": "Válassza ki a munkaterület mappáit!", "removeFolderFromWorkspace": "Mappa eltávolítása a munkaterületről", + "openFolderSettings": "Mappa beállításainak megnyitása", "saveWorkspaceAsAction": "Munkaterület mentése másként...", "save": "Menté&&s", "saveWorkspace": "Munkaterület mentése", "openWorkspaceAction": "Munkaterület megnyitása...", "openWorkspaceConfigFile": "Munkaterület konfigurációs fájljának megnyitása", + "openFolderAsWorkspaceInNewWindow": "Mappa megnyitása munkaterületként egy új ablakban", "workspaceFolderPickerPlaceholder": "Válasszon munkaterület-mappát!" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index 266ac56433e..3c81d54bd07 100644 --- a/i18n/hun/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/hun/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Tevékenységsáv elrejtése", - "activityBarAriaLabel": "Az aktív nézet váltása", "globalActions": "Globális műveletek" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..4fe5826df65 --- /dev/null +++ b/i18n/hun/src/vs/workbench/browser/parts/compositebar/compositeBar.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. +{ + "activityBarAriaLabel": "Az aktív nézet váltása" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..af96f733ba7 --- /dev/null +++ b/i18n/hun/src/vs/workbench/browser/parts/compositebar/compositeBarActions.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. +{ + "badgeTitle": "{0} – {1}", + "additionalViews": "További nézetek", + "numberBadge": "{0} ({1})", + "manageExtension": "Kiegészítő kezelése", + "titleKeybinding": "{0} ({1})", + "hide": "Elrejtés", + "toggle": "Nézet rögzítésének be- és kikapcsolása" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 186c2e66b64..05a3be82161 100644 --- a/i18n/hun/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "A második csoportban található szerkesztőablakok megjelenítése", "groupThreePicker": "A harmadik csoportban található szerkesztőablakok megjelenítése", "allEditorsPicker": "Összes megnyitott szerkesztőablak megjelenítése", - "view": "Nézet" + "view": "Nézet", + "file": "Fájl" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 3cc19480b62..dfd63a785b3 100644 --- a/i18n/hun/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/hun/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "A(z) '{0}' parancs jelenleg nem engedélyezett és nem futtatható.", "manageExtension": "Kiegészítő kezelése" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/hun/src/vs/workbench/electron-browser/main.contribution.i18n.json index 730c270e5d5..53babca5f63 100644 --- a/i18n/hun/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,18 +10,15 @@ "workspaces": "Munkaterületek", "developer": "Fejlesztői", "showEditorTabs": "Meghatározza, hogy a megnyitott szerkesztőablakok telején megjelenjenek-e a fülek", - "workbench.editor.labelFormat.default": "Fájl nevének megjelenítése. Ha a fülek engedélyezve vannak, és két egyező nevű fájl van egy csoportban, az elérési útjuk eltérő része lesz hozzáfűzve a névhez. Ha a fülek le vannak tiltva, a fájl munkaterület gyökérkönyvtárához képest relatív elérési útja jelenik meg, ha a szerkesztőablak aktív.", "workbench.editor.labelFormat.short": "A fájl nevének megjelenítése a könyvtár nevével együtt.", - "workbench.editor.labelFormat.medium": "Fájl nevének megjelenítése a fájl munkaterület gyökérkönyvtárához képest relatív elérési útjával együtt.", "workbench.editor.labelFormat.long": "Fájl nevének megjelenítése a fájl abszolút elérési útjával együtt.", "tabDescription": "Meghatározza a szerkesztőablakok címkéje formáját. A beállítás módosítása könnyebbé teheti a fájl helyének kiderítését:\n- short: 'parent'\n- medium: 'workspace/src/parent'\n- long: '/home/user/workspace/src/parent'\n- default: '.../parent', ha egy másik fülnek ugyanaz a címe, vagy a relatív elérési út, ha a fülek le vannak tiltva", "editorTabCloseButton": "Meghatározza a szerkesztőablakok fülein található bezárógomb pozícióját vagy eltávolítja őket, ha a beállítás értéke 'off'.", "showIcons": "Meghatározza, hogy a megnyitott szerkesztőablakok ikonnal együtt jelenjenek-e meg. A működéshez szükséges egy ikontéma engedélyezése is.", "enablePreview": "Meghatározza, hogy a megnyitott szerkesztőablakok előnézetként jelenjenek-e meg. Az előnézetként használt szerkesztőablakok újra vannak hasznosítva, amíg meg nem tartja őket a felhasználó (pl. dupla kattintás vagy szerkesztés esetén), és dőlt betűvel jelenik meg a címsoruk.", "enablePreviewFromQuickOpen": "Meghatározza, hogy a gyors megnyitás során megnyitott szerkesztőablakok előnézetként jelenjenek-e meg. Az előnézetként használt szerkesztőablakok újra vannak hasznosítva, amíg meg nem tartja őket a felhasználó (pl. dupla kattintás vagy szerkesztés esetén).", - "editorOpenPositioning": "Meghatározza, hogy hol nyíljanak meg a szerkesztőablakok. A 'left' vagy 'right' használata esetén az aktív szerkesztőablaktól jobbra vagy balra nyílnak meg az újak. A 'first' vagy 'last' esetén a szerkesztőablakok a jelenleg aktív ablaktól függetlenül nyílnak meg.", "revealIfOpen": "Meghatározza, hogy egy szerkesztőablak fel legyen-e fedve, ha már meg van nyitva a látható csoportok bármelyiképben. Ha le van tiltva, akkor egy új szerkesztőablak nyílik az aktív szerkesztőablak-csoportban. Ha engedélyezve van, akkor a már megnyitott szerkesztőablak lesz felfedve egy új megnyitása helyett. Megjegyzés: vannak esetek, amikor ez a beállítás figyelmen kívül van hagyva, pl. ha egy adott szerkesztőablak egy konkrét csoportban vagy a jelenleg aktív csoport mellett van menyitva.", - "commandHistory": "Meghatározza, hogy mennyi legutóbb használt parancs jelenjen meg a parancskatalógus előzményeinek listájában. Az előzmények kikapcsolásához állítsa az értéket 0-ra.", + "commandHistory": "Meghatározza, hogy hány legutóbb használt parancs jelenjen meg a parancskatalógus előzményeinek listájában. Az előzmények kikapcsolásához állítsa az értéket nullára.", "preserveInput": "Meghatározza, hogy a legutóbb beírt parancs automatikusan helyre legyen-e állítva a parancskatalógus következő megnyitása során.", "closeOnFocusLost": "Meghatározza, hogy a gyors megnyitás automatikusan bezáródjon-e amint elveszíti a fókuszt.", "openDefaultSettings": "Meghatározza, hogy a beállítások megnyitásakor megnyíljon-e egy szerkesztő az összes alapértelmezett beállítással.", @@ -50,7 +47,7 @@ "restoreWindows": "Meghatározza, hogy újraindítás után hogyan vannak ismét megnyitva az ablakok. A 'none' választása esetén mindig üres munkaterület indul, 'one' esetén a legutóbb használt ablak nyílik meg újra, a 'folders' megnyitja az összes megnyitott mappát, míg az 'all' újranyitja az összes ablakot az előző munkamenetből.", "restoreFullscreen": "Meghatározza, hogy az ablak teljesképernyős módban nyíljon-e meg, ha kilépéskor teljes képernyős módban volt.", "zoomLevel": "Meghatározza az ablak nagyítási szintjét. Az eredei méret 0, és minden egyes plusz (pl. 1) vagy mínusz (pl. -1) 20%-kal nagyobb vagy kisebb nagyítási szintet jelent. Tizedestört megadása esetén a nagyítási szint finomabban állítható.", - "title": "Meghatározza az ablak címét az aktív szerkesztőablak alapján. A változók a környezet alapján vannak behelyettesítve:\n${activeEditorShort}: pl. myFile.txt\n${activeEditorMedium}: pl. myFolder/myFile.txt\n${activeEditorLong}: pl. /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: pl. myFolder\n${folderPath}: pl. /Users/Development/myFolder\n${rootName}: pl. myFolder1, myFolder2, myFolder3\n${rootPath}: pl. /Users/Development/myWorkspace\n${appName}: pl. VS Code\n${dirty}: módosításjelző, ami jelzi, ha az aktív szerkesztőablak tartalma módosítva lett\n${separator}: feltételes elválasztó (\" - \"), ami akkor jelenik meg, ha olyan változókkal van körülvéve, amelyeknek van értéke\n", + "title": "Meghatározza az ablak címét az aktív szerkesztőablak alapján. A változók a környezet alapján vannak behelyettesítve:\n${activeEditorShort}: a fájl neve (pl. myFile.txt)\n${activeEditorMedium}: a fájl relatív elérési útja a munkaterület mappájához képest (pl. myFolder/myFile.txt)\n${activeEditorLong}: a fájl teljes elérési útja (pl. /Users/Development/myProject/myFolder/myFile.txt)\n${folderName}: azon munkaterületi mappa a neve, amelyben a fájl található (pl. myFolder)\n${folderPath}: azon munkaterületi mappa elérési útja, amelyben a fájl található (pl. /Users/Development/myFolder)\n${rootName}: a munkaterület neve (pl. myFolder vagy myWorkspace)\n${rootPath}: a munkaterület elérési útja (pl. /Users/Development/myWorkspace)\n${appName}: pl. VS Code\n${dirty}: módosításjelző, ami jelzi, ha az aktív szerkesztőablak tartalma módosítva lett\n${separator}: feltételes elválasztó (\" - \"), ami akkor jelenik meg, ha olyan változókkal van körülvéve, amelyeknek van értéke", "window.newWindowDimensions.default": "Az új ablakok a képernyő közepén nyílnak meg.", "window.newWindowDimensions.inherit": "Az új ablakok ugyanolyan méretben és ugyanazon a helyen jelennek meg, mint a legutoljára aktív ablak.", "window.newWindowDimensions.maximized": "Az új ablakok teljes méretben nyílnak meg.", diff --git a/i18n/hun/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/hun/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 4020242c40c..7c16965748a 100644 --- a/i18n/hun/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, hibakeresés", "debugAriaLabel": "Írja be a futtatandó konfiguráció nevét.", + "addConfigTo": "Konfiguráció hozzáadása ({0})...", + "addConfiguration": "Konfiguráció hozzáadása...", "noConfigurationsMatching": "Nincs illeszkedő hibakeresési konfiguráció", "noConfigurationsFound": "Nem található hibakeresési konfiguráció. Készítsen egy 'launch.json' fájlt." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/hun/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..1bd18dd9a99 --- /dev/null +++ b/i18n/hun/src/vs/workbench/parts/debug/browser/debugStatus.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. +{ + "debug": "Hibakeresés" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/hun/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..72630bc8424 --- /dev/null +++ b/i18n/hun/src/vs/workbench/parts/debug/browser/debugViewlet.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. +{ + "debugFocusVariablesView": "Váltás a változókra", + "debugFocusWatchView": "Váltás a figyelőlistára", + "debugFocusCallStackView": "Váltás a hívási veremre", + "debugFocusBreakpointsView": "Váltás a töréspontokra" +} \ No newline at end of file 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 fffc1aad27f..a54b3a8b776 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 @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "Konfigurációk a 'launch.json' első változatának elkészítéséhez.", "vscode.extension.contributes.debuggers.languages": "Azon nyelvek listája, amelyeknél ez a hibakeresési kiegészítő alapértelmezett hibakeresőnek tekinthető.", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Ha meg van adva, a VS Code ezt a parancsot fogja hívni a hibakeresési illesztő futtatható állománya elérési útjának és az átadandó argumentumok meghatározásához.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Ha meg van határozva, a VS Code ezt a parancsot fogja hívni az ennek a kiegészítőnek küldött \"debug\" vagy \"run\" parancsok esetén.", "vscode.extension.contributes.debuggers.configurationSnippets": "Kódtöredékek új 'launch.json'-konfigurációk hozzáadásához.", "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.", diff --git a/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 3945df51449..da4586921b6 100644 --- a/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,10 +12,10 @@ "breakpointRemoved": "Töréspont eltávoíltva, {0}. sor, fájl: {1}", "compoundMustHaveConfigurations": "A kombinációk \"configurations\" tulajdonságát be kell állítani több konfiguráció elindításához.", "configMissing": "A(z) '{0}' konfiguráció hiányzik a 'launch.json'-ból.", - "debugRequestNotSupported": "A kiválasztott hibakeresési konfigurációban a(z) `{0}` attribútum értéke nem támogatott: '{1}'.", - "debugRequesMissing": "A(z) '{0}' attribútum hiányzik a kiválasztott hibakeresési konfigurációból.", + "debugRequestNotSupported": "A(z) `{0}` attribútumnak nem támogatott értéke van ('{1}') a kiválasztott hibakeresési konfigurációban.", + "debugRequesMissing": "A(z) `{0}` attribútum hiányzik a kiválasztott hibakeresési konfigurációból.", "debugTypeNotSupported": "A megadott hibakeresési típus ('{0}') nem támogatott.", - "debugTypeMissing": "A kiválasztott indítási konfigurációnak hiányzik a 'type' tulajdonsága.", + "debugTypeMissing": "A kiválasztott indítási konfigurációnak hiányzik a `type` tulajdonsága.", "preLaunchTaskErrors": "Buildelési hibák léptek fel a(z) '{0}' preLaunchTask futása közben.", "preLaunchTaskError": "Buildelési hiba lépett fel a(z) '{0}' preLaunchTask futása közben.", "preLaunchTaskExitCode": "A(z) '{0}' preLaunchTask a következő hibakóddal fejeződött be: {1}.", diff --git a/i18n/hun/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/hun/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 929096a6c43..9c979492ec3 100644 --- a/i18n/hun/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -8,5 +8,5 @@ "replVariableAriaLabel": "A(z) {0} változó értéke: {1}, REPL, hibakeresés", "replExpressionAriaLabel": "A(z) {0} kifejezés értéke: {1}, REPL, hibakeresés", "replValueOutputAriaLabel": "{0}, REPL, hibakeresés", - "replKeyValueOutputAriaLabel": "A(z) {0} kimeneti változó értéke: {1}, REPL, hibakeresés" + "replRawObjectAriaLabel": "{0} repl-változó értéke: {1}, REPL, hibakeresés" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index 0992f340c4a..d032a29e684 100644 --- a/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "Fájlok", + "filesCategory": "Fájl", "revealInSideBar": "Megjelenítés az oldalsávon", "acceptLocalChanges": "A lemezen lévő tartalom felülírása a saját módosításokkal", "revertLocalChanges": "Saját módosítások elvetése és a lemezen lévő tartalom visszaállítása" diff --git a/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.i18n.json index b495b205cd5..2f76c2de05a 100644 --- a/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "Törli a(z) '{0}' nevű fájlt?", "undoBin": "Helyreállíthatja a lomtárból.", "undoTrash": "Helyreállíthatja a kukából.", + "doNotAskAgain": "Ne kérdezze meg újra", "confirmDeleteMessageFolder": "Törli a(z) {0} mappát és a teljes tartalmát?", "confirmDeleteMessageFile": "Véglegesen törli a következőt: {0}?", "irreversible": "A művelet nem vonható vissza!", @@ -37,8 +38,6 @@ "openToSide": "Megnyitás oldalt", "compareSource": "Kijelölés összehasonlításhoz", "globalCompareFile": "Aktív fájl összehasonlítása...", - "pickHistory": "Válasszon egy korábban megnyitott fájlt az összehasonlításhoz", - "unableToFileToCompare": "A kiválasztott fájl nem hasonlítható össze a következővel: '{0}'.", "openFileToCompare": "Fájlok összehasonlításához elősször nyisson meg egy fájlt.", "compareWith": "'{0}' összehasonlítása a következővel: '{1}'", "compareFiles": "Fájlok összehasonlítása", @@ -47,7 +46,7 @@ "saveAs": "Mentés másként...", "saveAll": "Összes mentése", "saveAllInGroup": "Összes mentése a csoportban", - "saveFiles": "Módosított fájlok mentése", + "saveFiles": "Összes fájl mentése", "revert": "Fájl visszaállítása", "focusOpenEditors": "Váltás a megnyitott szerkesztőablakok nézetre", "focusFilesExplorer": "Váltás a fájlkezelőre", diff --git a/i18n/hun/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 4cea0462d06..a6c7fe4eaef 100644 --- a/i18n/hun/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -40,10 +40,14 @@ "dynamicHeight": "Meghatározza, hogy a megnyitott szerkesztőablakok szakasz magassága automatikusan illeszkedjen a megnyitott elemek számához vagy sem.", "autoReveal": "Meghatározza, hogy a fájlkezelőben automatikusan fel legyenek fedve és ki legyenek jelölve a fájlok, amikor megnyitják őket.", "enableDragAndDrop": "Meghatározza, hogy a fájlkezelőben áthelyezhetők-e a fájlok és mappák húzással.", + "confirmDragAndDrop": "Meghatározza, hogy a fájlkezelő kérjen-e megerősítést fájlok és mappák húzással történő áthelyezése esetén.", + "confirmDelete": "Meghatározza, hogy a fájlkezelő kérjen-e megerősítést a fájlok lomtárba történő helyezése esetén.", "sortOrder.default": "A fájlok és mappák név szerint vannak rendezve, ABC-sorrendben. A mappák a fájlok előtt vannak listázva.", "sortOrder.mixed": "A fájlok és mappák név szerint vannak rendezve, ABC-sorrendben. A fájlok és a mappák közösen vannak rendezve.", "sortOrder.filesFirst": "A fájlok és mappák név szerint vannak rendezve, ABC-sorrendben. A fájlok a mappák előtt vannak listázva.", "sortOrder.type": "A fájlok és mappák a kiterjesztésük szerint vannak rendezve, ABC-sorrendben. A mappák a fájlok előtt vannak listázva.", "sortOrder.modified": "A fájlok és mappák a legutolsó módosítás dátuma szerint vannak rendezve, csökkenő sorrendben. A mappák a fájlok előtt vannak listázva.", - "sortOrder": "Meghatározza a fájlok és mappák rendezési módját a fájlkezelőben. Az alapértelmezett rendezésen túl beállítható 'mixed' (a fájlok és mappák közösen vannak rendezve), 'type' (rendezés fájltípus szerint), 'modified' (rendezés utolsó módosítási dátum szerint) vagy 'filesFirst' (fájlok a mappák elé vannak rendezve) is." + "sortOrder": "Meghatározza a fájlok és mappák rendezési módját a fájlkezelőben. Az alapértelmezett rendezésen túl beállítható 'mixed' (a fájlok és mappák közösen vannak rendezve), 'type' (rendezés fájltípus szerint), 'modified' (rendezés utolsó módosítási dátum szerint) vagy 'filesFirst' (fájlok a mappák elé vannak rendezve) is.", + "explorer.decorations.colors": "Meghatározza, hogy a fájldekorációk használjanak-e színeket.", + "explorer.decorations.badges": "Meghatározza, hogy a fájldekorációk használjanak-e jelvényeket." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/hun/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 924c7ac5593..30d6d309142 100644 --- a/i18n/hun/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "Nincs mappa megnyitva", "explorerSection": "Fájlkezelő szakasz", - "noWorkspaceHelp": "Még nem nyitott meg mappát", + "noWorkspaceHelp": "Még nem adott mappát a munkaterülethez.", + "addFolder": "Mappa hozzáadása", + "noFolderHelp": "Még nem nyitott meg mappát", "openFolder": "Mappa megnyitása" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/hun/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index 21ef2846403..07cd01d7b7a 100644 --- a/i18n/hun/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -4,12 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "canNotResolve": "Nem lehet feloldani a következő mappát: {0}", "fileInputAriaLabel": "Adja meg a fájl nevét. Nyomjon 'Enter'-t a megerősítéshez vagy 'Escape'-et a megszakításhoz.", "filesExplorerViewerAriaLabel": "{0}, Fájlkezelő", "dropFolders": "Szeretné hozzáadni a mappákat a munkaterülethez?", "dropFolder": "Szeretné hozzáadni a mappát a munkaterülethez?", "addFolders": "Mappák hozzá&&adása", "addFolder": "Mappa hozzá&&adása", + "confirmMove": "Biztosan át szeretné helyezni a következőt: '{0}'?", + "doNotAskAgain": "Ne kérdezze meg újra", "confirmOverwriteMessage": "A célmappában már létezik '{0}' nevű elem. Le szeretné cserélni?", "irreversible": "A művelet nem vonható vissza!", "replaceButtonLabel": "&&Csere" diff --git a/i18n/hun/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/hun/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..c9127f9169b --- /dev/null +++ b/i18n/hun/src/vs/workbench/parts/markers/browser/markersFileDecorations.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. +{ + "label": "Problémák", + "tooltip.1": "A fájlban 1 probléma található", + "tooltip.N": "A fájlban {0} probléma található", + "markers.showOnFile": "Fájlokban és mappákban található hibák és figyelmeztetések megjelenítése" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index ee0b9750f56..69b1a883b74 100644 --- a/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "Az ebben a fájlban elhelyezett beállítások felülírják az alapértelmezett beállításokat.", - "errorInvalidConfiguration": "Nem sikerült írni a beállításokba. Javítsa a fájlban található hibákat/figyelmeztetéseket, majd próbálja újra!", "emptyWorkspaceSettingsHeader": "Az ebben a fájlban elhelyezett beállítások felülírják a felhasználói beállításokat.", "emptyFolderSettingsHeader": "Az ebben a fájlban elhelyezett beállítások felülírják a munkaterületre vonatkozó beállításokat.", "defaultFolderSettingsTitle": "Alapértelmezett mappabeállítások", diff --git a/i18n/hun/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/hun/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 41ec82c33f7..949b0eb4dcf 100644 --- a/i18n/hun/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "Ebben a kontextusban nem engedélyezett a(z) {0} parancs futtatása.", "recentlyUsed": "legutóbb használt", "morecCommands": "további parancsok", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "Parancs nem található" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/hun/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index 8e8c7a2962e..165c4dd23c2 100644 --- a/i18n/hun/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,6 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "{0}. módosítás (összesen: {1})", + "change": "{0}. módosítás (összesen: {1})", + "show previous change": "Előző módosítás megjelenítése", + "show next change": "Következő módosítás megjelenítése", "editorGutterModifiedBackground": "A szerkesztőablak margójának háttérszíne a módosított soroknál.", "editorGutterAddedBackground": "A szerkesztőablak margójának háttérszíne a hozzáadott soroknál.", "editorGutterDeletedBackground": "A szerkesztőablak margójának háttérszíne a törölt soroknál.", diff --git a/i18n/hun/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index ed407924b94..9a084ee3454 100644 --- a/i18n/hun/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -17,7 +17,7 @@ "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.", "exclude.when": "További ellenőrzés elvégzése az illeszkedő fájlok testvérein. Az illeszkedő fájl nevéhez használja a $(basename) változót!", - "useRipgrep": "Meghatározza, hogy a szövegben való kereséshez a ripgrep van-e használva.", + "useRipgrep": "Meghatározza, hogy a szövegben és fájlokban való kereséshez a ripgrep van-e használva.", "useIgnoreFilesByDefault": "Meghatározza, hogy a .gitignore és .ignore fájlok használva vannak-e az új munkaterületeken a kereséshez.", "search.quickOpen.includeSymbols": "Meghatározza, hogy a fájlok gyors megnyitásánál megjelenjenek-e a globális szimbólumkereső találatai." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/hun/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 81ca25b06ea..3fe3f8642b4 100644 --- a/i18n/hun/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -19,7 +19,6 @@ "ClearSearchResultsAction.label": "Keresési eredmények törlése", "FocusNextSearchResult.label": "Váltás a következő keresési eredményre", "FocusPreviousSearchResult.label": "Váltás az előző keresési eredményre", - "RemoveAction.label": "Eltávolítás", "file.replaceAll.label": "Összes cseréje", "match.replace.label": "Csere" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/hun/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 94cfdc9e1d9..94208b9eca9 100644 --- a/i18n/hun/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,8 +10,8 @@ "vscode.extension.contributes.snippets": "Kódrészleteket szolgáltat.", "vscode.extension.contributes.snippets-language": "Azon nyelv azonosítója, amely számára szolgáltatva van ez a kódrészlet.", "vscode.extension.contributes.snippets-path": "A kódrészlet-fájl elérési útja. Az elérési út relatív a kiegészítő mappájához, és általában a következővel kezdődik: './snippets/',", - "badFile": "A(z) \"{0}\" kódrészletet tartalmazó fájlt nem sikerült beolvasni.", "badVariableUse": "A(z) \"{0}\" kódrészlet nagy valószínűséggel keveri a kódrészletváltozók és a kódrészlet-helyjelölők fogalmát. További információ a következő oldalon található: https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax", + "badFile": "A(z) \"{0}\" kódrészletet tartalmazó fájlt nem sikerült beolvasni.", "source.snippet": "Felhasználói kódrészlet", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 26736788a2f..ad07b544ef3 100644 --- a/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -14,6 +14,7 @@ "runningTasks": "Futó feladatok megjelenítése", "tasks": "Feladatok", "TaskSystem.noHotSwap": "A feladatvégrehajtó motor megváltoztatása egy futó, aktív feladat esetén az ablak újraindítását igényli.", + "TaskServer.folderIgnored": "A(z) {0} mappa figyelmen kívül van hagyva, mert 0.1.0-s verziójú feladatkonfigurációt használ.", "TaskService.noBuildTask1": "Nincs buildelési feladat definiálva. Jelöljön meg egy feladatot az 'isBuildCommand' tulajdonsággal a tasks.json fájlban!", "TaskService.noBuildTask2": "Nincs buildelési feladat definiálva. Jelöljön meg egy feladatot a 'build' csoporttal a tasks.json fájlban!", "TaskService.noTestTask1": "Nincs tesztelési feladat definiálva. Jelöljön meg egy feladatot az 'isTestCommand' tulajdonsággal a tasks.json fájlban!", @@ -30,6 +31,7 @@ "TaskSystem.activeSame.noBackground": "A(z) '{0}' feladat már aktív. A feladat befejezéséhez használja `Feladat megszakítása` parancsot a Feladatok menüből!", "TaskSystem.active": "Már fut egy feladat. Szakítsa meg, mielőtt egy másik feladatot futtatna.", "TaskSystem.restartFailed": "Nem sikerült a(z) {0} feladat befejezése és újraindítása.", + "TaskService.noConfiguration": "Hiba: a(z) {0} feladatok felderítése nem szolgáltatott feladatot a következő konfigurációhoz:\n{1}\nA feladat figyelmen kívül lesz hagyva.\n", "TaskSystem.configurationErrors": "Hiba: a megadott feladatkonfigurációban validációs hibák vannak, és nem használható. Először javítsa ezeket a hibákat!", "taskService.ignoreingFolder": "Feladatkonfiguráció figyelmen kívül hagyva a munkaterület {0} nevű mappája esetében. Több mappás munkaterületen a feladatok támogatásához az összes mappának a 2.0-s verziójú feladatkonfigurációt kell használni.\n", "TaskSystem.invalidTaskJson": "Hiba. A tasks.json fájlban szintaktikai hibák találhatók. Javítsa ezeket a hibákat feladatvégrehajtás előtt.\n", diff --git a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index edc638fe092..9abe5fcaf6f 100644 --- a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -17,6 +17,7 @@ "terminal.integrated.fontFamily": "Meghatározza a terminál betűtípusát. Alapértelmezett értéke az editor.fontFamily értéke.", "terminal.integrated.fontSize": "Meghatározza a terminálban használt betű méretét, pixelekben.", "terminal.integrated.lineHeight": "Meghatározza a sormagasságot a terminálban. A tényleges méret a megadott szám és a terminál betűméretének szorzatából jön ki.", + "terminal.integrated.enableBold": "Engedélyezve van-e a félkövér szöveg a terminálban. A működéshez szükséges, hogy a terminál shell támogassa a félkövér betűket.", "terminal.integrated.cursorBlinking": "Meghatározza, hogy a terminál kurzora villog-e.", "terminal.integrated.cursorStyle": "Meghatározza a terminál kurzorának stílusát.", "terminal.integrated.scrollback": "Meghatározza, hogy a terminál legfeljebb hány sort tárol a pufferben.", diff --git a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 9883a94a201..c671a91c989 100644 --- a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -16,7 +16,6 @@ "workbench.action.terminal.new.short": "Új terminál", "workbench.action.terminal.focus": "Váltás a terminálra", "workbench.action.terminal.focusNext": "Váltás a következő terminálra", - "workbench.action.terminal.focusAtIndex": "Váltás a(z) {0}. terminálra", "workbench.action.terminal.focusPrevious": "Váltás az előző terminálra", "workbench.action.terminal.paste": "Beillesztés az aktív terminálba", "workbench.action.terminal.DefaultShell": "Alapértelmezett shell kiválasztása", diff --git a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 15f0f130a04..1f792eaa3ac 100644 --- a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Másolás", - "createNewTerminal": "Új terminál", "paste": "Beillesztés", "selectAll": "Összes kijelölése", "clear": "Törlés" diff --git a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index babb2962c46..45f5c16180a 100644 --- a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "Rendben, ne jelenítse meg újra", "terminal.integrated.chooseWindowsShell": "Válassza ki a preferált terminál shellt! Ez később módosítható a beállításokban.", "terminalService.terminalCloseConfirmationSingular": "Van egy aktív terminálmunkamenet. Szeretné megszakítani?", - "terminalService.terminalCloseConfirmationPlural": "{0} aktív terminálmunkamenet van. Szeretné megszakítani?", - "yes": "Igen" + "terminalService.terminalCloseConfirmationPlural": "{0} aktív terminálmunkamenet van. Szeretné megszakítani?" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/hun/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..209303272b7 --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "A beállítások összefoglaló leírása. Ez a címke jelenik meg a beállítások fájlban egy különálló megjegyzésként.", + "vscode.extension.contributes.configuration.properties": "A konfigurációs tulajdonságok leírása.", + "scope.window.description": "Ablakspecifikus beállítás, ami konfigurálható a felhasználói vagy munkaterületi beállításokban.", + "scope.resource.description": "Erőforrásspecifikus beállítás, ami beállítható a felhasználói, munkaterületi és mappaszintű beállításokban.", + "scope.description": "A hatókör, amire a beállítás vonatkozik. Az elérhető hatókörök: `window` és `resource`.", + "vscode.extension.contributes.configuration": "Konfigurációs beállításokat szolgáltat.", + "invalid.title": "a 'configuration.title' értékét karakterláncként kell megadni", + "vscode.extension.contributes.defaultConfiguration": "Adott nyelvre vonatkozóan szerkesztőbeállításokat szolgáltat.", + "invalid.properties": "A 'configuration.properties' értékét egy objektumként kell megadni", + "invalid.allOf": "A 'configuration.allOf' elavult, és használata nem javasolt. Helyette több konfigurációs szakaszt kell átadni tömbként a 'configuration' értékeként.", + "workspaceConfig.folders.description": "A munkaterületre betöltött mappák listája.", + "workspaceConfig.path.description": "Egy fájl elérési útja, pl. `/root/folderA` vagy `./folderA` relatív elérési út esetén, ami a munkaterületfájl helye alapján lesz feloldva.", + "workspaceConfig.name.description": "A mappa neve. Nem kötelező megadni.", + "workspaceConfig.uri.description": "A mappa URI-ja", + "workspaceConfig.settings.description": "Munkaterület-beállítások", + "workspaceConfig.extensions.description": "Munkaterület-kiegészítők", + "unknownWorkspaceProperty": "Ismeretlen munkaterület-konfigurációs tulajdonság" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/hun/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/editor/common/editorService.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. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/hun/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index c20612f1980..c5c7acc39f4 100644 --- a/i18n/hun/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/hun/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -6,6 +6,7 @@ { "schema.token.settings": "A token színe és stílusa.", "schema.token.foreground": "A token előtérszíne.", + "schema.token.background.warning": "A tokenek háttérszíne jelenleg nem támogatott.", "schema.token.fontStyle": "A szabály betűtípusának stílusa: 'italic', 'bold', 'underline', vagy ezek kombinációja", "schema.fontStyle.error": "A betűtípus stílusa 'italic', 'bold', 'underline', vagy ezek kombinációja lehet.", "schema.properties.name": "A szabály leírása.", diff --git a/i18n/hun/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/hun/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index b93f26958fa..1a824863bdd 100644 --- a/i18n/hun/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/hun/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "Betűkészlet használata esetén a betűkészlet mérete a szöveg betűkészletének méretéhez képest, százalékban. Ha nincs megadva, akkor a betűkészlet-definícióban megadott érték van használva.", "schema.fontId": "Betűkészlet használata esetén a betűkészlet azonosítója. Ha nincs megadva, akkor az első betűkészlet-definíció van használva.", "schema.light": "Fájlikon-társítások világos témák használata esetén. Nem kötelező megadni.", - "schema.highContrast": "Fájlikon-társítások nagy kontrasztú témák használata esetén. Nem kötelező megadni." + "schema.highContrast": "Fájlikon-társítások nagy kontrasztú témák használata esetén. Nem kötelező megadni.", + "schema.hidesExplorerArrows": "Meghatározza, hogy a fájlkezelőben megjelenő nyilak el legyenek-e rejtve, amikor ez a téma aktív." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/hun/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..4dace3f126c --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.themes": "TextMate-színtémákat szolgáltat.", + "vscode.extension.contributes.themes.id": "Az ikontéma felhasználói beállításokban használt azonosítója.", + "vscode.extension.contributes.themes.label": "A színtéma felhasználói felületen megjelenő neve.", + "vscode.extension.contributes.themes.uiTheme": "A szerkesztőablak körül megjelenő elemek alaptémája. A 'vs' a világos, a 'vs-dark' a sötét színtéma, a 'hc-black' pedig a sötét, nagy kontrasztú téma.", + "vscode.extension.contributes.themes.path": "A tmTheme-fájl elérési útja. Az elérési út relatív a kiegészítő mappájához képest, és általában './themes/themeFile.tmTheme'.", + "reqarray": "a(z) `{0}` kiegszítési pontot tömbként kell megadni", + "reqpath": "Hiányzó karakterlánc a `contributes.{0}.path`-ban. A megadott érték: {1}", + "invalid.path.1": "A `contributes.{0}.path` ({1}) nem a kiegészítő mappáján belül található ({2}). Emiatt előfordulhat, hogy a kiegészítő nem lesz hordozható." +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/hun/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..91291d589e7 --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.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. +{ + "error.cannotparseicontheme": "Hiba a fájlikonokat leíró fájl feldolgozása közben: {0}" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/hun/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..bdbe180864e --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.iconThemes": "Fájlikontémákat szolgáltat.", + "vscode.extension.contributes.iconThemes.id": "Az ikontéma felhasználói beállításokban használt azonosítója.", + "vscode.extension.contributes.iconThemes.label": "Az ikontéma felhasználói felületen megjelenő neve.", + "vscode.extension.contributes.iconThemes.path": "A témadefiníciós fájl elérési útja. Az elérési út relatív a kiegészítő mappájához képest, és általában ./icons/awesome-icon-theme.json'.", + "reqarray": "a(z) `{0}` kiegszítési pontot tömbként kell megadni", + "reqpath": "Hiányzó karakterlánc a `contributes.{0}.path`-ban. A megadott érték: {1}", + "reqid": "Hiányzó karakterlánc a `contributes.{0}.id`-ben. A megadott érték: {1}", + "invalid.path.1": "A `contributes.{0}.path` ({1}) nem a kiegészítő mappáján belül található ({2}). Emiatt előfordulhat, hogy a kiegészítő nem lesz hordozható." +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/hun/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index c1c24477811..f65a2da76bc 100644 --- a/i18n/hun/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/hun/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,31 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "TextMate-színtémákat szolgáltat.", - "vscode.extension.contributes.themes.id": "A téma felhasználói beállításokban használt azonosítója.", - "vscode.extension.contributes.themes.label": "A színtéma felhasználói felületen megjelenő neve.", - "vscode.extension.contributes.themes.uiTheme": "A szerkesztőablak körül megjelenő elemek alaptémája. A 'vs' a világos, a 'vs-dark' a sötét színtéma, a 'hc-black' pedig a sötét, nagy kontrasztú téma.", - "vscode.extension.contributes.themes.path": "A tmTheme-fájl elérési útja. Az elérési út relatív a kiegészítő mappájához képest, és általában './themes/themeFile.tmTheme'.", - "vscode.extension.contributes.iconThemes": "Fájlikontémákat szolgáltat.", - "vscode.extension.contributes.iconThemes.id": "Az ikontéma felhasználói beállításokban használt azonosítója.", - "vscode.extension.contributes.iconThemes.label": "Az ikontéma felhasználói felületen megjelenő neve.", - "vscode.extension.contributes.iconThemes.path": "A témadefiníciós fájl elérési útja. Az elérési út relatív a kiegészítő mappájához képest, és általában ./icons/awesome-icon-theme.json'.", "migration.completed": "Új témabeállítások lettek hozzáadva a felhasználói beállításokhoz. Biztonsági mentés a következő helyen érhető el: {0}.", "error.cannotloadtheme": "Nem sikerült betölteni a(z) '{0}' témát: {1}.", - "reqarray": "a(z) `{0}` kiegszítési pontot tömbként kell megadni", - "reqpath": "Hiányzó karakterlánc a `contributes.{0}.path`-ban. A megadott érték: {1}", - "invalid.path.1": "A `contributes.{0}.path` ({1}) nem a kiegészítő mappáján belül található ({2}). Emiatt előfordulhat, hogy a kiegészítő nem lesz hordozható.", - "reqid": "Hiányzó karakterlánc a `contributes.{0}.id`-ben. A megadott érték: {1}", "error.cannotloadicontheme": "Nem sikerült megnyitni a(z) '{0}' témát", - "error.cannotparseicontheme": "Hiba a fájlikonokat leíró fájl feldolgozása közben: {0}", "colorTheme": "Meghatározza a munkaterületen használt színtémát.", "colorThemeError": "A téma ismeretlen vagy nincs telepítve.", "iconTheme": "Meghatározza a munkaterületen használt ikontémát. 'null' érték esetén nem jelenik meg egyetlen fájlikon sem.", "noIconThemeDesc": "Nincsenek fájlikonok", "iconThemeError": "A fájlikontéma ismeretlen vagy nincs telepítve.", "workbenchColors": "Felülírja az aktuális színtémában definiált színeket.", - "workbenchColors.deprecated": "A beállítás már nem kísérleti, és át lett nevezve 'workbench.colorCustomizations'-re.", - "workbenchColors.deprecatedDescription": "Használja a 'workbench.colorCustomizations' tulajdonságot helyette.", "editorColors": "Felülírja az aktuális színtémában definiált, szerkesztőablakhoz kapcsolódó színeket és betűstílusokat.", "editorColors.comments": "Meghatározza a megjegyzések színét és stílusát.", "editorColors.strings": "Meghatározza a sztringliterálok színét és stílusát.", diff --git a/i18n/hun/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/hun/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..dbbe55dc9e3 --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/workspace/node/workspaceEditingService.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. +{ + "openWorkspaceConfigurationFile": "Munkaterület konfigurációs fájljának megnyitása", + "close": "Bezárás" +} \ No newline at end of file diff --git a/i18n/ita/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/ita/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index da8de5ed00e..f99b5799775 100644 --- a/i18n/ita/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/ita/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "ad esempio myFile.txt", - "activeEditorMedium": "ad esempio myFolder/myFile.txt", - "activeEditorLong": "ad esempio /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "ad es. myFolder1, myFolder2, myFolder3", - "rootPath": "ad esempio /Users/Development/myProject", - "folderName": "ad es. myFolder", - "folderPath": "ad es. /Users/Development/myFolder", + "activeEditorShort": "il nome del file (ad esempio MyFile.txt)", + "activeEditorMedium": "il percorso del file relativo alla cartella dell'area di lavoro (ad es. myFolder/myFile.txt)", + "activeEditorLong": "il percorso completo del file (ad es. /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "nome dell'area di lavoro (ad es. myFolder o myWorkspace)", + "rootPath": "percorso dell'area di lavoro (ad es. /Users/Development/myWorkspace)", + "folderName": "nome della cartella dell'area di lavoro in cui è contenuto il file (ad es. myFolder)", + "folderPath": "percorso della cartella dell'area di lavoro in cui è contenuto il file (ad es. /Users/Development/myFolder)", "appName": "ad esempio VS Code", "dirty": "un indicatore dirty se l'editor attivo è dirty", "separator": "un separatore condizionale (' - ') visualizzato solo se circondato da variabili con valori", diff --git a/i18n/ita/extensions/emmet/package.i18n.json b/i18n/ita/extensions/emmet/package.i18n.json index 6d5829bd5ff..f232e705ff6 100644 --- a/i18n/ita/extensions/emmet/package.i18n.json +++ b/i18n/ita/extensions/emmet/package.i18n.json @@ -28,13 +28,6 @@ "command.incrementNumberByTen": "Aumenta di 10", "command.decrementNumberByTen": "Riduci di 10", "emmetSyntaxProfiles": "Consente di definire il profilo per la sintassi specificata oppure di usare un profilo personalizzato con regole specifiche.", - "emmetExclude": "Matrice di linguaggi in cui le abbreviazioni Emmet non devono essere espanse.", - "emmetExtensionsPath": "Percorso di una cartella contenente snippet e profili Emmet.'", - "emmetShowExpandedAbbreviation": "Mostra le abbreviazioni emmet espanse come suggerimenti.\nL'opzione \"inMarkupAndStylesheetFilesOnly\" si applica a html, haml, jade, slim, xml, xsl, css, scss, sass, less e stylus.\nL'opzione \"sempre\" (always) si applica a tutte le parti del file indipendentemente dal markup/css.", - "emmetShowAbbreviationSuggestions": "Mostra possibili abbreviazioni emmet come suggerimenti. Non si applica a fogli di stile o quando emmet.showExpandedAbbreviation è impostata a \"mai\" (never).", - "emmetIncludeLanguages": "Abilita le abbreviazioni emmet in linguaggi che non sono normalmente supportati. Aggiungere un mapping tra il linguaggio ed il linguaggio supportato da emmet.\n Ad esempio: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", - "emmetVariables": "Variabili da utilizzare nei frammenti di emmet", - "emmetTriggerExpansionOnTab": "Se abilitate, le abbreviazioni Emmet vengono espanse quando si preme TAB.", "emmetPreferences": "Preferenze usate per modificare il comportamento di alcune azioni e i resolver di Emmet.", "emmetPreferencesIntUnit": "Unità di misura predefinita per i valori integer", "emmetPreferencesFloatUnit": "Unità di misura predefinita per i valori float", @@ -44,5 +37,7 @@ "emmetPreferencesCssBetween": "Simbolo da inserire tra la proprietà CSS e il valore quando si espandono le abbreviazioni CSS", "emmetPreferencesSassBetween": "Simbolo da inserire tra la proprietà CSS e il valore quando si espandono le abbreviazioni CSS nei file Sass", "emmetPreferencesStylusBetween": "Simbolo da inserire tra la proprietà CSS e il valore quando si espandono le abbreviazioni CSS nei file Stylus", - "emmetShowSuggestionsAsSnippets": "Se è true, i suggerimenti Emmet verranno visualizzati come frammenti consentendo di ordinarli in base all'impostazione editor.snippetSuggestions." + "emmetPreferencesFilterCommentBefore": "Una definizione di commento che deve essere inserita prima dell'elemento corrispondente quando viene applicato il filtro commenti.", + "emmetPreferencesFilterCommentAfter": "Una definizione di commento che deve essere posizionato dopo l'elemento corrispondente quando viene applicato il filtro commenti.", + "emmetPreferencesFilterCommentTrigger": "Un elenco delimitato da virgole di nomi di attributi che dovrebbero esistere come abbreviazione per il filtro commenti da applicare" } \ No newline at end of file diff --git a/i18n/ita/extensions/git/out/commands.i18n.json b/i18n/ita/extensions/git/out/commands.i18n.json index 16a12505d76..09e5850f8cd 100644 --- a/i18n/ita/extensions/git/out/commands.i18n.json +++ b/i18n/ita/extensions/git/out/commands.i18n.json @@ -12,8 +12,9 @@ "cloning": "Clonazione del repository GIT...", "openrepo": "Apri repository", "proposeopen": "Aprire il repository clonato?", - "path to init": "Percorso della cartella", - "provide path": "Specificare un percorso di cartella per inizializzare un repository GIT", + "init repo": "Inizializza repository", + "create repo": "Inizializza repository", + "are you sure": "Questo creerà un repository Git in '{0}'. Sei sicuro di voler continuare?", "HEAD not available": "La versione HEAD di '{0}' non è disponibile.", "confirm stage files with merge conflicts": "Preparare per il commit {0} file con conflitti di merge?", "confirm stage file with merge conflicts": "Preparare per il commit {0} con conflitti di merge?", diff --git a/i18n/ita/extensions/git/out/repository.i18n.json b/i18n/ita/extensions/git/out/repository.i18n.json index 0b2210016a0..9088cc9c340 100644 --- a/i18n/ita/extensions/git/out/repository.i18n.json +++ b/i18n/ita/extensions/git/out/repository.i18n.json @@ -21,6 +21,8 @@ "deleted by us": "Eliminato da noi", "both added": "Entrambi aggiunti", "both modified": "Entrambi modificati", + "untracked, short": "U", + "modified, short": "M", "commit": "Esegui commit", "merge changes": "Esegui merge delle modifiche", "staged changes": "Modifiche preparate per il commit", diff --git a/i18n/ita/extensions/git/package.i18n.json b/i18n/ita/extensions/git/package.i18n.json index fd78ff2a50b..8844282381c 100644 --- a/i18n/ita/extensions/git/package.i18n.json +++ b/i18n/ita/extensions/git/package.i18n.json @@ -15,6 +15,8 @@ "command.stageAll": "Prepara tutte le modifiche per commit", "command.stageSelectedRanges": "Prepara per il commit intervalli selezionati", "command.revertSelectedRanges": "Ripristina intervalli selezionati", + "command.stageChange": "Prepara modifica per commit", + "command.revertChange": "Annulla modifica", "command.unstage": "Annulla preparazione modifiche per commit", "command.unstageAll": "Annulla preparazione di tutte le modifiche per commit", "command.unstageSelectedRanges": "Annulla preparazione per il commit di intervalli selezionati", diff --git a/i18n/ita/extensions/typescript/package.i18n.json b/i18n/ita/extensions/typescript/package.i18n.json index 21866260c71..e881e2dc9e0 100644 --- a/i18n/ita/extensions/typescript/package.i18n.json +++ b/i18n/ita/extensions/typescript/package.i18n.json @@ -44,7 +44,8 @@ "typescript.npm": "Specifica il percorso dell'eseguibile NPM utilizzato per l'acquisizione automatica delle definizioni di tipi. Richiede TypeScript >= 2.3.4.", "typescript.check.npmIsInstalled": "Controlla se NPM è installato per l'acquisizione automatica delle definizioni di tipi", "javascript.nameSuggestions": "Abilita/disabilita l'inclusione di nomi univoci dal file negli elenchi di suggerimento di JavaScript.", - "typescript.tsc.autoDetect": "Controlla se la rilevazione automatica di attività tsc è on/off.", + "typescript.tsc.autoDetect": "Controlla l'auto-rilevazione di attività di tsc. 'off' disabilita questa funzionalità. 'build' crea solo attività di singola compilazione esecuzione. 'watch' crea solo attività di compilazione e controllo. 'on' crea attività sia di tipo 'build' che 'watch'. Il valore predefinito è 'on'.", "typescript.problemMatchers.tsc.label": "Problemi TypeScript", - "typescript.problemMatchers.tscWatch.label": "Problemi TypeScript (modalità espressione di controllo)" + "typescript.problemMatchers.tscWatch.label": "Problemi TypeScript (modalità espressione di controllo)", + "typescript.quickSuggestionsForPaths": "Attiva/Disattiva suggerimenti rapidi quando si digita un percorso di importazione." } \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/ita/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 76cf5a81fb0..97a23bba223 100644 --- a/i18n/ita/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/ita/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,6 @@ "label.replaceButton": "Sostituisci", "label.replaceAllButton": "Sostituisci tutto", "label.toggleReplaceButton": "Attiva/Disattiva modalità sostituzione", - "title.matchesCountLimit": "Vengono evidenziati solo i primi 999 risultati, ma tutte le operazioni di ricerca funzionano sull'intero testo.", "label.matchesLocation": "{0} di {1}", "label.noResults": "Nessun risultato" } \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/ita/src/vs/editor/contrib/find/common/findController.i18n.json index 0b6e1248aab..753c08a072a 100644 --- a/i18n/ita/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/ita/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "Trova selezione successiva", "previousSelectionMatchFindAction": "Trova selezione precedente", "startReplace": "Sostituisci", - "addSelectionToNextFindMatch": "Aggiungi selezione a risultato ricerca successivo", - "addSelectionToPreviousFindMatch": "Aggiungi selezione a risultato ricerca precedente", - "moveSelectionToNextFindMatch": "Sposta ultima selezione a risultato ricerca successivo", - "moveSelectionToPreviousFindMatch": "Sposta ultima selezione a risultato ricerca precedente", - "selectAllOccurrencesOfFindMatch": "Seleziona tutte le occorrenze del risultato ricerca", - "changeAll.label": "Cambia tutte le occorrenze", "showNextFindTermAction": "Mostra il termine di ricerca successivo", "showPreviousFindTermAction": "Mostra il termine di ricerca precedente" } \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/ita/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 732a2e19079..af2b081d453 100644 --- a/i18n/ita/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/ita/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Aggiungi cursore sopra", "mutlicursor.insertBelow": "Aggiungi cursore sotto", - "mutlicursor.insertAtEndOfEachLineSelected": "Aggiungi cursore alla fine delle righe" + "mutlicursor.insertAtEndOfEachLineSelected": "Aggiungi cursore alla fine delle righe", + "addSelectionToNextFindMatch": "Aggiungi selezione a risultato ricerca successivo", + "addSelectionToPreviousFindMatch": "Aggiungi selezione a risultato ricerca precedente", + "moveSelectionToNextFindMatch": "Sposta ultima selezione a risultato ricerca successivo", + "moveSelectionToPreviousFindMatch": "Sposta ultima selezione a risultato ricerca precedente", + "selectAllOccurrencesOfFindMatch": "Seleziona tutte le occorrenze del risultato ricerca", + "changeAll.label": "Cambia tutte le occorrenze" } \ 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 8e09cda877c..1d0c0c88c61 100644 --- a/i18n/ita/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/ita/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "Formato colore non valido. Usare #RGB, #RGBA, #RRGGBB o #RRGGBBAA", "schema.colors": "Colori usati nell'area di lavoro.", "foreground": "Colore primo piano. Questo colore è utilizzato solo se non viene sovrascritto da un componente.", "errorForeground": "Colore primo piano globale per i messaggi di errore. Questo colore è utilizzato solamente se non viene sottoposto a override da un componente.", diff --git a/i18n/ita/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/ita/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 4d31bf1f0c4..91e26eba907 100644 --- a/i18n/ita/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -13,6 +13,7 @@ "select": "&&Seleziona", "selectWorkspace": "Seleziona cartelle per l'area di lavoro", "removeFolderFromWorkspace": "Rimuovi cartella dall'area di lavoro", + "openFolderSettings": "Apri impostazioni cartella", "saveWorkspaceAsAction": "Salva area di lavoro come...", "save": "&&Salva", "saveWorkspace": "Salva area di lavoro", diff --git a/i18n/ita/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index d8cbee32bd5..bee5fb6341a 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Nascondi barra attività", - "activityBarAriaLabel": "Cambio visualizzazione attiva", "globalActions": "Azioni globali" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..33e0b7a1979 --- /dev/null +++ b/i18n/ita/src/vs/workbench/browser/parts/compositebar/compositeBar.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. +{ + "activityBarAriaLabel": "Cambio visualizzazione attiva" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..427b8914624 --- /dev/null +++ b/i18n/ita/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "Visualizzazioni aggiuntive", + "numberBadge": "{0} ({1})", + "manageExtension": "Gestisci estensione", + "titleKeybinding": "{0} ({1})", + "toggle": "Attiva/Disattiva visualizzazione bloccata" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 766b02a726a..aa914d12c1d 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "Mostra editor nel secondo gruppo", "groupThreePicker": "Mostra editor nel terzo gruppo", "allEditorsPicker": "Mostra tutti gli editor aperti", - "view": "Visualizza" + "view": "Visualizza", + "file": "File" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 9b0548995db..358f121a809 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "Il comando '{0}' non è attualmente abilitato e non può essere eseguito.", "manageExtension": "Gestisci estensione" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/ita/src/vs/workbench/electron-browser/main.contribution.i18n.json index 52b4f223124..f17ae8d5fa8 100644 --- a/i18n/ita/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,18 +10,14 @@ "workspaces": "Aree di lavoro", "developer": "Sviluppatore", "showEditorTabs": "Controlla se visualizzare o meno gli editor aperti in schede.", - "workbench.editor.labelFormat.default": "Visualizza il nome del file. Quando le schede sono abilitate e due file presentano lo stesso nome in un unico gruppo, vengono aggiunte le sezioni distintive del percorso di ciascun file. Quando le schede sono disabilitate, viene visualizzato il percorso relativo alla radice dell'area di lavoro se l'editor è attivo.", "workbench.editor.labelFormat.short": "Visualizza il nome del file seguito dal relativo nome di directory.", - "workbench.editor.labelFormat.medium": "Visualizza il nome del file seguito dal percorso corrispondente relativo alla radice dell'area di lavoro.", "workbench.editor.labelFormat.long": "Visualizza il nome del file seguito dal relativo percorso assoluto.", "tabDescription": "Controlla il formato dell'etichetta per un editor. Se si modifica questa impostazione, ad esempio, risulterà più agevole individuare il percorso di un file:\n- short: 'parent'\n- medium: 'workspace/src/parent'\n- long: '/home/user/workspace/src/parent'\n- default: '.../parent', quando un'altra scheda condivide lo stesso titolo, oppure il percorso relativo dell'area di lavoro se le schede sono disabilitate", "editorTabCloseButton": "Controlla la posizione dei pulsanti di chiusura delle schede dell'editor oppure li disabilita quando è impostata su 'off'.", "showIcons": "Controlla se visualizzare o meno un'icona per gli editor aperti. Richiede l'abilitazione anche di un tema dell'icona.", "enablePreview": "Controlla se gli editor aperti vengono visualizzati come anteprima. Le anteprime editor vengono riutilizzate finché vengono mantenute (ad esempio tramite doppio clic o modifica) e vengono visualizzate in corsivo.", "enablePreviewFromQuickOpen": "Controlla se gli editor aperti da Quick Open vengono visualizzati come anteprima. Le anteprime editor vengono riutilizzate finché vengono mantenute, ad esempio tramite doppio clic o modifica.", - "editorOpenPositioning": "Controlla la posizione in cui vengono aperti gli editor. Selezionare 'left' o 'right' per aprire gli editor a sinistra o a destra di quello attualmente attivo. Selezionare 'first' o 'last' per aprire gli editor indipendentemente da quello attualmente attivo.", "revealIfOpen": "Controlla se un editor viene visualizzato in uno qualsiasi dei gruppi visibili se viene aperto. Se l'opzione è disabilitata, un editor verrà aperto preferibilmente nel gruppo di editor attualmente attivo. Se è abilitata, un editor già aperto verrà visualizzato e non aperto di nuovo nel gruppo di editor attualmente attivo. Nota: in alcuni casi questa impostazione viene ignorata, ad esempio quando si forza l'apertura di un editor in un gruppo specifico oppure a lato del gruppo attualmente attivo.", - "commandHistory": "Controlla il numero di comandi usati di recente da mantenere nella cronologia per il riquadro comandi. Impostare su 0 per disabilitare la cronologia dei comandi.", "preserveInput": "Controlla se l'ultimo input digitato nel riquadro comandi deve essere ripristinato alla successiva riapertura del riquadro.", "closeOnFocusLost": "Controlla se Quick Open deve essere chiuso automaticamente quando perde lo stato attivo.", "openDefaultSettings": "Controlla se all'apertura delle impostazioni viene aperto anche un editor che mostra tutte le impostazioni predefinite.", @@ -50,7 +46,6 @@ "restoreWindows": "Controlla la modalità di riapertura delle finestre dopo un riavvio. Selezionare 'none' per iniziare sempre con un'area di lavoro vuota, 'one' per riaprire l'ultima finestra usata, 'folders' per riaprire tutte le finestre con cartelle aperte oppure 'all' per riaprire tutte le finestre dell'ultima sessione.", "restoreFullscreen": "Controlla se una finestra deve essere ripristinata a schermo intero se è stata chiusa in questa modalità.", "zoomLevel": "Consente di modificare il livello di zoom della finestra. Il valore originale è 0 e ogni incremento superiore (ad esempio 1) o inferiore (ad esempio -1) rappresenta un aumento o una diminuzione del 20% della percentuale di zoom. È anche possibile immettere valori decimali per modificare il livello di zoom con maggiore granularità.", - "title": "Controlla il titolo della finestra in base all'editor attivo. Le variabili vengono sostituite in base al contesto:\n${activeEditorShort}: ad esempio myFile.txt\n${activeEditorMedium}: ad esempio myFolder/myFile.txt\n${activeEditorLong}: ad esempio /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: ad esempio myFolder\n${folderPath}: ad esempio /Users/Development/myFolder\n${rootName}: ad esempio myFolder1, myFolder2, myFolder3\n${rootPath}: ad esempio /Users/Development/myWorkspace\n${appName}: ad esempio VS Code\n${dirty}: indicatore dirty se l'editor attivo è dirty\n${separator}: separatore condizionale (\" - \") visualizzato solo quando è racchiuso tra variabili con valori", "window.newWindowDimensions.default": "Apre nuove finestre al centro della schermata.", "window.newWindowDimensions.inherit": "Apre nuove finestre le cui dimensioni sono uguali a quelle dell'ultima finestra attiva.", "window.newWindowDimensions.maximized": "Apre nuove finestre ingrandite a schermo intero.", diff --git a/i18n/ita/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index b3b797b17a0..cd95d333b64 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, debug", "debugAriaLabel": "Digitare il nome di una configurazione di avvio da eseguire.", + "addConfigTo": "Aggiungi configurazione ({0})...", + "addConfiguration": "Aggiungi configurazione...", "noConfigurationsMatching": "Non esistono configurazioni di debug corrispondenti", "noConfigurationsFound": "Non è stata trovata alcuna configurazione di debug. Creare un file 'launch.json'." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..8eeb71caf1a --- /dev/null +++ b/i18n/ita/src/vs/workbench/parts/debug/browser/debugStatus.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. +{ + "debug": "Debug" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/ita/src/vs/workbench/parts/debug/browser/debugViewlet.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/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 2b0ce6dfdf4..7729690837e 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 @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "Configurazioni per generare la versione iniziale di 'launch.json'.", "vscode.extension.contributes.debuggers.languages": "Elenco dei linguaggi. per cui l'estensione di debug può essere considerata il \"debugger predefinito\".", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Se è specificato, Visual Studio Code chiamerà questo comando per determinare il percorso eseguibile della scheda di debug e gli argomenti da passare.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Se è specificato, Visual Studio Code chiamerà questo comando per le azioni \"debug\" o \"run\" previste come destinazione di questa estensione.", "vscode.extension.contributes.debuggers.configurationSnippets": "Frammenti per l'aggiunta di nuove configurazioni in 'launch.json'.", "vscode.extension.contributes.debuggers.configurationAttributes": "Configurazioni dello schema JSON per la convalida di 'launch.json'.", "vscode.extension.contributes.debuggers.windows": "Impostazioni specifiche di Windows.", diff --git a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 70ec9c0d711..c70e4e525c6 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,10 +12,7 @@ "breakpointRemoved": "Rimosso un punto di interruzione a riga {0} del file {1}", "compoundMustHaveConfigurations": "Per avviare più configurazioni, deve essere impostato l'attributo \"configurations\" dell'elemento compounds.", "configMissing": "In 'launch.json' manca la configurazione '{0}'.", - "debugRequestNotSupported": "La configurazione di debug scelta contiene un valore di attributo `{0}` che non è supportato: '{1}'.", - "debugRequesMissing": "Nella configurazione di debug scelta manca l'attributo '{0}'.", "debugTypeNotSupported": "Il tipo di debug configurato '{0}' non è supportato.", - "debugTypeMissing": "Manca la proprietà 'type' per la configurazione di avvio scelta.", "preLaunchTaskErrors": "Sono stati rilevati errori di compilazione durante preLaunchTask '{0}'.", "preLaunchTaskError": "È stato rilevato un errore di compilazione durante preLaunchTask '{0}'.", "preLaunchTaskExitCode": "L'attività di preavvio '{0}' è stata terminata ed è stato restituito il codice di uscita {1}.", diff --git a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index fff7cbcba9e..2740934029a 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -7,6 +7,5 @@ "stateCapture": "Lo stato dell'oggetto viene acquisito dalla prima valutazione", "replVariableAriaLabel": "Il valore della variabile {0} è {1}, ciclo Read Eval Print, debug", "replExpressionAriaLabel": "Il valore dell'espressione {0} è {1}, ciclo Read Eval Print, debug", - "replValueOutputAriaLabel": "{0}, ciclo Read Eval Print, debug", - "replKeyValueOutputAriaLabel": "Il valore della variabile di output {0} è {1}, ciclo Read Eval Print, debug" + "replValueOutputAriaLabel": "{0}, ciclo Read Eval Print, debug" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/ita/src/vs/workbench/parts/files/browser/fileActions.i18n.json index f1f608e1731..d68d405085a 100644 --- a/i18n/ita/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -37,8 +37,6 @@ "openToSide": "Apri lateralmente", "compareSource": "Seleziona per il confronto", "globalCompareFile": "Confronta file attivo con...", - "pickHistory": "Selezionare un file aperto in precedenza per il confronto", - "unableToFileToCompare": "Non è possibile confrontare il file selezionato con '{0}'.", "openFileToCompare": "Aprire prima un file per confrontarlo con un altro file.", "compareWith": "Confronta '{0}' con '{1}'", "compareFiles": "Confronta file", @@ -47,7 +45,6 @@ "saveAs": "Salva con nome...", "saveAll": "Salva tutto", "saveAllInGroup": "Salva tutto nel gruppo", - "saveFiles": "Salva file modificati ma non salvati", "revert": "Ripristina file", "focusOpenEditors": "Stato attivo su visualizzazione editor aperti", "focusFilesExplorer": "Stato attivo su Esplora file", diff --git a/i18n/ita/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/ita/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 9ae2216ff99..586895b4e44 100644 --- a/i18n/ita/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,6 @@ { "noWorkspace": "Nessuna cartella aperta", "explorerSection": "Sezione Esplora file", - "noWorkspaceHelp": "Non ci sono ancora cartelle aperte.", + "noFolderHelp": "Non ci sono ancora cartelle aperte.", "openFolder": "Apri cartella" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/ita/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..bcb8c50044f --- /dev/null +++ b/i18n/ita/src/vs/workbench/parts/markers/browser/markersFileDecorations.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. +{ + "label": "Problemi" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index 237ebccfb39..36b2ac76a3a 100644 --- a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "Inserire le impostazioni qui per sovrascrivere quelle predefinite.", - "errorInvalidConfiguration": "Impossibile scrivere nelle impostazioni. Correggere eventuali errori o avvisi nel file e riprovare.", "emptyWorkspaceSettingsHeader": "Inserire le impostazioni qui per sovrascrivere le impostazioni utente.", "emptyFolderSettingsHeader": "Inserire le impostazioni cartella qui per sovrascrivere quelle dell'area di lavoro.", "defaultFolderSettingsTitle": "Impostazioni cartella predefinite", diff --git a/i18n/ita/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/ita/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 28964d0cf5c..543c602df83 100644 --- a/i18n/ita/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "Il comando '{0}' non è abilitato nel contesto corrente.", "recentlyUsed": "usate di recente", "morecCommands": "altri comandi", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "Non ci sono comandi corrispondenti" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index 7b4843f3a16..65fd721bb17 100644 --- a/i18n/ita/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -17,7 +17,6 @@ "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.", "exclude.when": "Controllo aggiuntivo sugli elementi di pari livello di un file corrispondente. Usare $(basename) come variabile del nome file corrispondente.", - "useRipgrep": "Controlla se usare ripgrep durante la ricerca di testo", "useIgnoreFilesByDefault": "Controlla se utilizzare i file .gitignore e .ignore come impostazione predefinita durante la ricerca in una nuova area di lavoro", "search.quickOpen.includeSymbols": "Configurare questa opzione per includere i risultati di una ricerca di simboli globale nei risultati dei file per Quick Open." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/ita/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 942721004df..7faf8ff218a 100644 --- a/i18n/ita/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -19,7 +19,6 @@ "ClearSearchResultsAction.label": "Cancella risultati della ricerca", "FocusNextSearchResult.label": "Sposta lo stato attivo sul risultato della ricerca successivo", "FocusPreviousSearchResult.label": "Sposta lo stato attivo sul risultato della ricerca precedente", - "RemoveAction.label": "Rimuovi", "file.replaceAll.label": "Sostituisci tutto", "match.replace.label": "Sostituisci" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/ita/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 09e4993b61b..8b2ae57561b 100644 --- a/i18n/ita/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,8 +10,8 @@ "vscode.extension.contributes.snippets": "Frammenti per contributes.", "vscode.extension.contributes.snippets-language": "Identificatore di linguaggio per cui si aggiunge come contributo questo frammento.", "vscode.extension.contributes.snippets-path": "Percorso del file snippets. È relativo alla cartella delle estensioni e in genere inizia con './snippets/'.", - "badFile": "Non è stato possibile leggere il file di frammento \"{0}\".", "badVariableUse": "Il frammento \"{0}\" molto probabilmente confonde variabili-frammento con segnaposti-frammento. Vedere https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax per ulteriori dettagli.", + "badFile": "Non è stato possibile leggere il file di frammento \"{0}\".", "source.snippet": "Frammento utente", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index ad495da28bf..9941d145008 100644 --- a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -16,7 +16,6 @@ "workbench.action.terminal.new.short": "Nuovo terminale", "workbench.action.terminal.focus": "Sposta stato attivo su terminale", "workbench.action.terminal.focusNext": "Sposta stato attivo su terminale successivo", - "workbench.action.terminal.focusAtIndex": "Sposta stato attivo su terminale {0}", "workbench.action.terminal.focusPrevious": "Sposta stato attivo su terminale precedente", "workbench.action.terminal.paste": "Incolla nel terminale attivo", "workbench.action.terminal.DefaultShell": "Selezionare la Shell di Default", diff --git a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index e32834163e9..adc0b4440da 100644 --- a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Copia", - "createNewTerminal": "Nuovo terminale", "paste": "Incolla", "selectAll": "Seleziona tutto", "clear": "Cancella" diff --git a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index e21d2d1aaf0..6055f7da096 100644 --- a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "OK, non visualizzare più", "terminal.integrated.chooseWindowsShell": "Seleziona la shell di terminale preferita - è possibile modificare questa impostazione dopo", "terminalService.terminalCloseConfirmationSingular": "C'è una sessione di terminale attiva. Terminarla?", - "terminalService.terminalCloseConfirmationPlural": "Ci sono {0} sessioni di terminale attive. Terminarle?", - "yes": "Sì" + "terminalService.terminalCloseConfirmationPlural": "Ci sono {0} sessioni di terminale attive. Terminarle?" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/ita/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..afd8ffa11fc --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "Riepilogo delle impostazioni. Questa etichetta verrà usata nel file di impostazioni come commento di separazione.", + "vscode.extension.contributes.configuration.properties": "Descrizione delle proprietà di configurazione.", + "scope.window.description": "Configurazione specifica della finestra, che può essere configurata nelle impostazioni dell'utente o dell'area di lavoro.", + "scope.resource.description": "Configurazione specifica di risorse, che possono essere configurate nelle impostazioni utente, in quelle dell'area di lavoro o di una cartella.", + "vscode.extension.contributes.configuration": "Impostazioni di configurazione di contributes.", + "invalid.title": "'configuration.title' deve essere una stringa", + "vscode.extension.contributes.defaultConfiguration": "Aggiunge come contributo le impostazioni di configurazione predefinite dell'editor in base al linguaggio.", + "invalid.properties": "'configuration.properties' deve essere un oggetto", + "invalid.allOf": "'configuration.allOf' è deprecato e non deve più essere usato. Passare invece una matrice di sezioni di configurazione al punto di aggiunta contributo 'configuration'.", + "workspaceConfig.folders.description": "Elenco di cartelle da caricare nell'area di lavoro.", + "workspaceConfig.path.description": "Percorso di file, ad esempio `/root/folderA` o `./folderA` per un percorso relativo che verrà risolto in base alla posizione del file dell'area di lavoro.", + "workspaceConfig.name.description": "Nome facoltativo per la cartella. ", + "unknownWorkspaceProperty": "La proprietà di configurazione dell'area di lavoro è sconosciuta" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/ita/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/editor/common/editorService.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. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/ita/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..34e0bc8f5e8 --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.themes": "Contributes textmate color themes.", + "vscode.extension.contributes.themes.id": "ID del tema dell'icona usato nelle impostazioni utente.", + "vscode.extension.contributes.themes.label": "Etichetta del tema colori visualizzata nell'interfaccia utente.", + "vscode.extension.contributes.themes.uiTheme": "Tema di base che definisce i colori nell'editor: 'vs' è il tema colori chiaro, mentre 'vs-dark' è il tema colori scuro e 'hc-black' è il tema a contrasto elevato scuro.", + "vscode.extension.contributes.themes.path": "Percorso del file tmTheme. È relativo alla cartella delle estensioni e corrisponde in genere a './themes/themeFile.tmTheme'.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "È previsto un valore stringa in `contributes.{0}.path`. Valore specificato: {1}", + "invalid.path.1": "Valore previsto di `contributes.{0}.path` ({1}) da includere nella cartella dell'estensione ({2}). L'estensione potrebbe non essere più portatile." +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/ita/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..b0f9faf6b52 --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.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. +{ + "error.cannotparseicontheme": "Problems parsing file icons file: {0}" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/ita/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..53cc79371c9 --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "ID del tema dell'icona usato nelle impostazioni utente.", + "vscode.extension.contributes.iconThemes.label": "Etichetta del tema dell'icona visualizzata nell'interfaccia utente.", + "vscode.extension.contributes.iconThemes.path": "Percorso del file di definizione del tema dell'icona. È relativo alla cartella delle estensioni e corrisponde in genere a './icons/awesome-icon-theme.json'.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "È previsto un valore stringa in `contributes.{0}.path`. Valore specificato: {1}", + "reqid": "È previsto un valore stringa in `contributes.{0}.id`. Valore specificato: {1}", + "invalid.path.1": "Valore previsto di `contributes.{0}.path` ({1}) da includere nella cartella dell'estensione ({2}). L'estensione potrebbe non essere più portatile." +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/ita/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index d6ed75ea2e1..97d1cdc1754 100644 --- a/i18n/ita/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/ita/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,31 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "ID del tema dell'icona usato nelle impostazioni utente.", - "vscode.extension.contributes.themes.label": "Etichetta del tema colori visualizzata nell'interfaccia utente.", - "vscode.extension.contributes.themes.uiTheme": "Tema di base che definisce i colori nell'editor: 'vs' è il tema colori chiaro, mentre 'vs-dark' è il tema colori scuro e 'hc-black' è il tema a contrasto elevato scuro.", - "vscode.extension.contributes.themes.path": "Percorso del file tmTheme. È relativo alla cartella delle estensioni e corrisponde in genere a './themes/themeFile.tmTheme'.", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "ID del tema dell'icona usato nelle impostazioni utente.", - "vscode.extension.contributes.iconThemes.label": "Etichetta del tema dell'icona visualizzata nell'interfaccia utente.", - "vscode.extension.contributes.iconThemes.path": "Percorso del file di definizione del tema dell'icona. È relativo alla cartella delle estensioni e corrisponde in genere a './icons/awesome-icon-theme.json'.", "migration.completed": "Sono state aggiunte nuove impostazioni tema alle impostazioni utente. Backup disponibile in {0}.", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "È previsto un valore stringa in `contributes.{0}.path`. Valore specificato: {1}", - "invalid.path.1": "Valore previsto di `contributes.{0}.path` ({1}) da includere nella cartella dell'estensione ({2}). L'estensione potrebbe non essere più portatile.", - "reqid": "È previsto un valore stringa in `contributes.{0}.id`. Valore specificato: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "Specifica il tema dell'icona usato nell'area di lavoro oppure 'null' se non viene visualizzato alcun icona di file.", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "Sostituisce i colori del tema colori attualmente selezionato.", - "workbenchColors.deprecated": "L'impostazione non è più sperimentale ed è stata rinominata in 'workbench.colorCustomizations'", - "workbenchColors.deprecatedDescription": "In alternativa, usare 'workbench.colorCustomizations'", "editorColors": "Sostituisce i colori dell'editor e lo stile dei font nel tema colori attualmente selezionato.", "editorColors.comments": "Imposta i colori e gli stili per i commenti", "editorColors.strings": "Imposta i colori e gli stili per i valori letterali stringa.", diff --git a/i18n/ita/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/ita/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..5cfa730d8ff --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/workspace/node/workspaceEditingService.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. +{ + "openWorkspaceConfigurationFile": "Apri file di configurazione dell'area di lavoro", + "close": "Chiudi" +} \ No newline at end of file diff --git a/i18n/jpn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/jpn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index 7c9fffc491f..f8b65e69685 100644 --- a/i18n/jpn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/jpn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "例: myFile.txt", - "activeEditorMedium": "例: myFolder/myFile.txt", - "activeEditorLong": "例: /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "例: myFolder1, myFolder2, myFolder3", - "rootPath": "例: /Users/Development/myProject", - "folderName": "例: myFolder", - "folderPath": "例: /Users/Development/myFolder", + "activeEditorShort": "ファイル名 (例: myFile.txt)", + "activeEditorMedium": "ワークスペース フォルダーに相対的なファイルのパス (例: myFolder/myFile.txt)", + "activeEditorLong": "ファイルの完全なパス (例: /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "ワークスペースの名前 (例: myFolder または myWorkspace)", + "rootPath": "ワークスペースのファイル パス (例: /Users/Development/myWorkspace)", + "folderName": "ファイルが含まれているワークスペース フォルダーの名前 (例: myFolder)", + "folderPath": "ファイルが含まれているワークスペース フォルダーのファイル パス (例: /Users/Development/myFolder)", "appName": "例: VS Code", "dirty": "アクティブなエディターがダーティである場合のダーティ インジケーター", "separator": "値のある変数で囲まれた場合にのみ表示される条件付き区切り記号 (' - ')", diff --git a/i18n/jpn/extensions/emmet/package.i18n.json b/i18n/jpn/extensions/emmet/package.i18n.json index d8400d06d02..01629a8bcec 100644 --- a/i18n/jpn/extensions/emmet/package.i18n.json +++ b/i18n/jpn/extensions/emmet/package.i18n.json @@ -28,13 +28,6 @@ "command.incrementNumberByTen": "10 ずつ増加", "command.decrementNumberByTen": "10 ずつ減少", "emmetSyntaxProfiles": "指定した構文に対してプロファイルを定義するか、特定の規則がある独自のプロファイルをご使用ください。", - "emmetExclude": "Emmet 省略記法を展開すべきでない言語の配列。", - "emmetExtensionsPath": "Emmet のプロファイルとスニペットを含むフォルダーへのパス。", - "emmetShowExpandedAbbreviation": "候補として、展開された Emmet 省略記法を表示します。\n\"inMarkupAndStylesheetFilesOnly\" オプションは、html、haml、jade、slim、xml、xsl、css、scss、sass、less、および stylus に適用されます。\n\"always\" オプションは、マークアップ / css に関係なく、ファイルのすべての部分に適用されます。", - "emmetShowAbbreviationSuggestions": "候補として考えられる Emmet 省略記法を表示します。 スタイルシートや emmet.showExpandedAbbreviation が \"never\" に設定されている場合は適用されません。", - "emmetIncludeLanguages": "既定でサポートされていない言語で Emmet 省略記法を有効にします。 言語と Emmet がサポートする言語の間にマッピングを追加します。\n例: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", - "emmetVariables": "Emmet のスニペットで使用される変数 ", - "emmetTriggerExpansionOnTab": "これをオンにすると、TAB キーを押したときに emmet 省略記法が展開されます.", "emmetPreferences": "Emmet の一部のアクションやリゾルバーの動作の変更に使用される基本設定。", "emmetPreferencesIntUnit": "整数値に使用する既定の単位", "emmetPreferencesFloatUnit": "float 値に使用する既定の単位", @@ -44,5 +37,7 @@ "emmetPreferencesCssBetween": "CSS の略語を展開するときに CSS プロパティと値の間に配置されるシンボル ", "emmetPreferencesSassBetween": "Sass ファイルで CSS の略語を展開するときに CSS プロパティと値の間に配置されるシンボル ", "emmetPreferencesStylusBetween": "Stylus ファイルで CSS の略語を展開するときに CSS プロパティと値の間に配置されるシンボル ", - "emmetShowSuggestionsAsSnippets": "true の場合、emmet 候補では、editor.snippetSuggestions 設定に従ってそれらを並べてスニペットとして表示されます。" + "emmetPreferencesFilterCommentBefore": "コメント フィルター使用時、一致した要素の前に配置するコメントの定義。 ", + "emmetPreferencesFilterCommentAfter": "コメント フィルター使用時、一致した要素の後に配置するコメントの定義。", + "emmetPreferencesFilterCommentTrigger": "コメント フィルターに適用される略語に存在する属性名のカンマ区切りのリスト" } \ No newline at end of file diff --git a/i18n/jpn/extensions/git/out/commands.i18n.json b/i18n/jpn/extensions/git/out/commands.i18n.json index af7b32febd1..e825de0716d 100644 --- a/i18n/jpn/extensions/git/out/commands.i18n.json +++ b/i18n/jpn/extensions/git/out/commands.i18n.json @@ -12,8 +12,9 @@ "cloning": "Git リポジトリを複製しています...", "openrepo": "リポジトリを開く", "proposeopen": "複製したリポジトリを開きますか?", - "path to init": "フォルダーのパス", - "provide path": "初期化する Git リポジトリへのフォルダー パスを入力してください", + "init repo": "リポジトリの初期化", + "create repo": "リポジトリの初期化", + "are you sure": "'{0}' に Git リポジトリを作成します。続行してもよろしいですか?", "HEAD not available": "'{0}' の HEAD バージョンは利用できません。", "confirm stage files with merge conflicts": "マージの競合がある {0} 個のファイルをステージしてもよろしいですか?", "confirm stage file with merge conflicts": "マージの競合がある {0} をステージしてもよろしいですか? ", diff --git a/i18n/jpn/extensions/git/out/repository.i18n.json b/i18n/jpn/extensions/git/out/repository.i18n.json index 553e8a8277f..11c4d9a6d7f 100644 --- a/i18n/jpn/extensions/git/out/repository.i18n.json +++ b/i18n/jpn/extensions/git/out/repository.i18n.json @@ -21,6 +21,8 @@ "deleted by us": "こちら側による削除", "both added": "双方とも追加", "both modified": "双方とも変更", + "untracked, short": "U", + "modified, short": "M", "commit": "コミット", "merge changes": "変更のマージ", "staged changes": "ステージング済みの変更", diff --git a/i18n/jpn/extensions/git/package.i18n.json b/i18n/jpn/extensions/git/package.i18n.json index ffdb7e9c5a1..e176e6c6ec0 100644 --- a/i18n/jpn/extensions/git/package.i18n.json +++ b/i18n/jpn/extensions/git/package.i18n.json @@ -12,12 +12,14 @@ "command.openFile": "ファイルを開く", "command.openHEADFile": "HEAD のファイルを開く", "command.stage": "変更のステージング", - "command.stageAll": "すべての変更のステージング", - "command.stageSelectedRanges": "選択した範囲をステージする", + "command.stageAll": "すべての変更をステージ", + "command.stageSelectedRanges": "選択した範囲をステージ", "command.revertSelectedRanges": "選択範囲を元に戻す", + "command.stageChange": "変更のステージング", + "command.revertChange": "変更を元に戻す", "command.unstage": "変更のステージング解除", "command.unstageAll": "すべての変更のステージング解除", - "command.unstageSelectedRanges": "選択した範囲をアンステージする", + "command.unstageSelectedRanges": "選択した範囲のステージを解除", "command.clean": "変更を破棄", "command.cleanAll": "すべての変更を破棄", "command.commit": "Commit", diff --git a/i18n/jpn/extensions/typescript/package.i18n.json b/i18n/jpn/extensions/typescript/package.i18n.json index 7d6417ebf7d..48300f99d35 100644 --- a/i18n/jpn/extensions/typescript/package.i18n.json +++ b/i18n/jpn/extensions/typescript/package.i18n.json @@ -44,7 +44,8 @@ "typescript.npm": "型定義の自動取得に使用される NPM 実行可能ファイルへのパスを指定します。TypeScript 2.3.4 以上が必要です。", "typescript.check.npmIsInstalled": "型定義の自動取得に NPM がインストールされているかどうかを確認します。", "javascript.nameSuggestions": "JavaScript の候補リスト内でファイルから一意の名前を含むかどうかを有効/無効にします。", - "typescript.tsc.autoDetect": "tsc タスクの自動検出をオンにするかオフにするかを制御します。", + "typescript.tsc.autoDetect": "tsc タスクの自動検出を制御します。'off' はこの機能を無効にします。'build' は 1 つのコンパイル実行タスクのみを表示します。'watch' はコンパイルとウォッチ タスクのみを表示します。'on' はビルド タスクとウォッチ タスクの両方を表示します。既定値は 'on' です。", "typescript.problemMatchers.tsc.label": "TypeScript の問題", - "typescript.problemMatchers.tscWatch.label": "TypeScript の問題 (ウォッチ モード)" + "typescript.problemMatchers.tscWatch.label": "TypeScript の問題 (ウォッチ モード)", + "typescript.quickSuggestionsForPaths": "Import パスを入力するときのクイック候補を有効/無効にします。" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/jpn/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 17c146860ec..b91635cb4cd 100644 --- a/i18n/jpn/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/jpn/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,6 @@ "label.replaceButton": "置換", "label.replaceAllButton": "すべて置換", "label.toggleReplaceButton": "置換モードの切り替え", - "title.matchesCountLimit": "最初の 999 の結果だけを強調表示しますが、テキスト全体を検索します。", - "label.matchesLocation": "{1} の {0}", + "label.matchesLocation": "{0} / {1} 件", "label.noResults": "結果なし" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/jpn/src/vs/editor/contrib/find/common/findController.i18n.json index c8149938eee..93947cdf9ce 100644 --- a/i18n/jpn/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/jpn/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "次の選択項目を検索", "previousSelectionMatchFindAction": "前の選択項目を検索", "startReplace": "置換", - "addSelectionToNextFindMatch": "選択した項目を次の一致項目に追加", - "addSelectionToPreviousFindMatch": "選んだ項目を前の一致項目に追加する", - "moveSelectionToNextFindMatch": "最後に選択した項目を次の一致項目に移動", - "moveSelectionToPreviousFindMatch": "最後に選んだ項目を前の一致項目に移動する", - "selectAllOccurrencesOfFindMatch": "一致するすべての出現箇所を選択します", - "changeAll.label": "すべての出現箇所を変更", "showNextFindTermAction": "次の検索語句を表示", "showPreviousFindTermAction": "前の検索語句を表示" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/jpn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 47f31c8a681..0df6dca88c6 100644 --- a/i18n/jpn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/jpn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "カーソルを上に挿入", "mutlicursor.insertBelow": "カーソルを下に挿入", - "mutlicursor.insertAtEndOfEachLineSelected": "カーソルを行末に挿入" + "mutlicursor.insertAtEndOfEachLineSelected": "カーソルを行末に挿入", + "addSelectionToNextFindMatch": "選択した項目を次の一致項目に追加", + "addSelectionToPreviousFindMatch": "選んだ項目を前の一致項目に追加する", + "moveSelectionToNextFindMatch": "最後に選択した項目を次の一致項目に移動", + "moveSelectionToPreviousFindMatch": "最後に選んだ項目を前の一致項目に移動する", + "selectAllOccurrencesOfFindMatch": "一致するすべての出現箇所を選択します", + "changeAll.label": "すべての出現箇所を変更" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/jpn/src/vs/platform/theme/common/colorRegistry.i18n.json index 69cc08c144e..55a15149aaf 100644 --- a/i18n/jpn/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/jpn/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "無効な色形式です。 #RGB、#RGBA、#RRGGBB、#RRGGBBAA のいずれかを使用してください", "schema.colors": "ワークベンチで使用する色。", "foreground": "全体の前景色。この色は、コンポーネントによってオーバーライドされていない場合にのみ使用されます。", "errorForeground": "エラー メッセージ全体の前景色。この色は、コンポーネントによって上書きされていない場合にのみ使用されます。", diff --git a/i18n/jpn/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/jpn/src/vs/workbench/browser/actions/workspaceActions.i18n.json index a72aa05e5aa..cf2a58db97a 100644 --- a/i18n/jpn/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -9,14 +9,17 @@ "addFolderToWorkspace": "ワークスペースにフォルダーを追加...", "add": "追加(&&A)", "addFolderToWorkspaceTitle": "ワークスペースにフォルダーを追加", + "globalRemoveFolderFromWorkspace": "ワークスペースからフォルダーを削除...", "newWorkspace": "新しいワークスペース...", "select": "選択(&&S)", "selectWorkspace": "ワークスペースのフォルダーを選択", "removeFolderFromWorkspace": "ワークスペースからフォルダーを削除", + "openFolderSettings": "フォルダーの設定を開く", "saveWorkspaceAsAction": "名前を付けてワークスペースを保存...", "save": "保存(&&S)", "saveWorkspace": "ワークスペースを保存", "openWorkspaceAction": "ワークスペースを開く...", "openWorkspaceConfigFile": "ワークスペースの構成ファイルを開く", + "openFolderAsWorkspaceInNewWindow": "新しいウィンドウでワークスペースとしてフォルダーを開く", "workspaceFolderPickerPlaceholder": "ワークスペース フォルダーを選択" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index b9c158c0786..85e7c1f4a9c 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "アクティビティ バーを非表示にする", - "activityBarAriaLabel": "アクティブなビュー スイッチャー", "globalActions": "グローバル操作" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..23e9cfae128 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/browser/parts/compositebar/compositeBar.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. +{ + "activityBarAriaLabel": "アクティブなビュー スイッチャー" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..9edd21a8c9a --- /dev/null +++ b/i18n/jpn/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "その他のビュー", + "numberBadge": "{0} ({1})", + "manageExtension": "拡張機能を管理", + "titleKeybinding": "{0} ({1})", + "toggle": "ビューのピン留めの切り替え" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 198f105b057..86cc5cdfa14 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "2 番目のグループでエディターを表示する", "groupThreePicker": "3 番目のグループのエディターを表示する", "allEditorsPicker": "開いているエディターをすべて表示する", - "view": "表示" + "view": "表示", + "file": "ファイル" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 8056b34fd1f..e750906b858 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "コマンド '{0}' は現在有効ではなく、実行できません。", "manageExtension": "拡張機能を管理" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/jpn/src/vs/workbench/electron-browser/main.contribution.i18n.json index 880049ace58..a4a1c53595c 100644 --- a/i18n/jpn/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,16 +10,13 @@ "workspaces": "ワークスペース", "developer": "開発者", "showEditorTabs": "開いているエディターをタブに表示するかどうかを制御します。", - "workbench.editor.labelFormat.default": "ファイルの名前を表示します。タブが有効かつ1 つのグループの2 つの同名ファイルに各ファイルのパスの区切り記号が追加されます。タブを無効にすると、エディターがアクティブな時にワークスペースのルートへの相対パスが表示されます。", "workbench.editor.labelFormat.short": "ディレクトリ名に続けてファイル名を表示します。", - "workbench.editor.labelFormat.medium": "ワークスペース ルートからの相対パスに続けてファイル名を表示します。", "workbench.editor.labelFormat.long": "絶対パスに続けてファイル名を表示します。", "tabDescription": "エディターのラベルの書式を制御します。例としてこの設定を変更することでファイルの場所を理解しやすくなります:\n- short: 'parent'\n- medium: 'workspace/src/parent'\n- long: '/home/user/workspace/src/parent'\n- default: '.../parent',  別タブで、同じタイトルを共有する場合や、相対的なワークスペース パス タブが無効になっている場合", "editorTabCloseButton": "エディター タブの閉じるボタンの位置を制御するか、[off] に設定した場合に無効にします。", "showIcons": "開いているエディターをアイコンで表示するかどうかを制御します。これには、アイコンのテーマを有効にする必要もあります。", "enablePreview": "開かれるエディターをプレビューとして表示するかどうかを制御します。プレビュー エディターは (例: ダブル クリックまたは編集などによって) 変更される時まで再利用し、斜体で表示します。", "enablePreviewFromQuickOpen": "Quick Open で開いたエディターをプレビューとして表示するかどうかを制御します。プレビュー エディターは、保持されている間、再利用されます (ダブルクリックまたは編集などによって)。", - "editorOpenPositioning": "エディターを開く場所を制御します。[左] または [右] を選択して、現在アクティブになっているエディターの左または右にエディターを開きます。[最初] または [最後] を選択して、現在アクティブになっているエディターとは別個にエディターを開きます。", "revealIfOpen": "任意の表示グループが開かれた場合に、そこにエディターを表示するかどうかを制御します。無効にした場合、エディターは現在のアクティブなエディター グループに優先して開かれます。有効にした場合は、現在のアクティブなエディター グループにもう一度開くのではなく、既に開いているエディターが表示されます。特定のグループ内や現在アクティブなグループの横に強制的にエディターを開いた場合などに、この設定が無視される場合もあることにご注意ください。", "commandHistory": "コマンド パレットで最近使用したコマンド履歴を保持する数を制御します。0 に設定するとコマンド履歴を無効にします。", "preserveInput": "次回開いたとき、コマンド パレットの最後の入力を復元するかどうかを制御します。", @@ -50,7 +47,7 @@ "restoreWindows": "再起動後にワークスペースを再度開く方法を制御します。'none' を選択すると常に空のワークスペースで開始します。'one' を選択すると最後に使用したウィンドウを再度開きます。'folders' を選択すると開かれていたフォルダーとすべてのウィンドウを再度開きます。'all' を選択すると前回のセッションのすべてのウィンドウを再度開きます。", "restoreFullscreen": "全画面表示モードで終了した場合に、ウィンドウを全画面表示モードに復元するかどうかを制御します。", "zoomLevel": "ウィンドウのズーム レベルを調整します。元のサイズは 0 で、1 つ上げるごとに (1 など) 20% ずつ拡大することを表し、1 つ下げるごとに (-1 など) 20% ずつ縮小することを表します。小数点以下の桁数を入力して、さらに細かくズーム レベルを調整することもできます。", - "title": "アクティブなエディターに基づいてウィンドウのタイトルを制御します。変数は、コンテキストに基づいて置換されます:\n${activeEditorShort}: 例: myFile.txt\n${activeEditorMedium}: 例: myFolder/myFile.txt\n${activeEditorLong}: 例: /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: 例: myFolder\n${folderPath}: 例: /Users/Development/myFolder\n${rootName}: 例: myFolder1, myFolder2, myFolder3\n${rootPath}: 例: /Users/Development/myWorkspace\n${appName}: 例: VS Code\n${dirty}: アクティブなエディターがダーティである場合のダーティ インジゲーター\n${separator}: 値のある変数で囲まれた場合にのみ表示される条件付き区切り記号 (\" - \")", + "title": "アクティブなエディターに基づいてウィンドウのタイトルを制御します。変数は、コンテキストに基づいて置換されます:\n${activeEditorShort}: ファイル名 (例: myFile.txt)\n${activeEditorMedium}: ワークスペース フォルダーへの相対パス (例: myFolder/myFile.txt)\n${activeEditorLong}: ファイルの完全なパス (例: /Users/Development/myProject/myFolder/myFile.txt)\n${folderName}: ファイルが含まれているワークスペース フォルダー名 (例: myFolder)\n${folderPath}: ァイルが含まれているワークスペース フォルダーのファイルパス (例: /Users/Development/myFolder)\n${rootName}: ワークスペースの名前 (例: myFolder や myWorkspace)\n${rootPath}: ワークスペースのファイル パス (例: /Users/Development/myWorkspace)\n${appName}: 例: VS Code\n${dirty}: アクティブなエディターがダーティである場合のダーティ インジゲーター\n${separator}: 値のある変数で囲まれた場合にのみ表示される条件付き区切り記号 (\" - \")", "window.newWindowDimensions.default": "新しいウィンドウを画面の中央に開きます。", "window.newWindowDimensions.inherit": "新しいウィンドウを、最後にアクティブだったウィンドウと同じサイズで開きます。", "window.newWindowDimensions.maximized": "新しいウィンドウを最大化した状態で開きます。", diff --git a/i18n/jpn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 24b30de36ed..f9530ecfb90 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}、デバッグ", "debugAriaLabel": "実行する起動構成の名前を入力してください。", + "addConfigTo": "設定 ({0}) の追加 ...", + "addConfiguration": "構成の追加...", "noConfigurationsMatching": "一致するデバッグ構成はありません", "noConfigurationsFound": "デバッグ構成が見つかりません。'launch.json' ファイルを作成してください。" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..9465d938566 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugStatus.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. +{ + "debug": "デバッグ" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..b317922a971 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugViewlet.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. +{ + "debugFocusVariablesView": "変数にフォーカス", + "debugFocusWatchView": "ウォッチにフォーカス", + "debugFocusCallStackView": "コールスタックにフォーカス", + "debugFocusBreakpointsView": "ブレークポイントにフォーカス" +} \ No newline at end of file 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 03f52be8c47..84777c482b2 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 @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "初期 'launch.json' を生成するための構成。", "vscode.extension.contributes.debuggers.languages": "デバッグ拡張機能が \"既定のデバッガー\" とされる言語の一覧。", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "指定されている場合、VS Code はこのコマンドを呼び出し、デバッグ アダプターの実行可能パスと、渡す引数を決定します。", - "vscode.extension.contributes.debuggers.startSessionCommand": "VS Code が指定されている場合、この拡張機能を対象とする \"デバッグ\" または \"実行\" アクションにこのコマンドが呼び出されます。", "vscode.extension.contributes.debuggers.configurationSnippets": "'launch.json' に新しい構成を追加するためのスニペット。", "vscode.extension.contributes.debuggers.configurationAttributes": "'launch.json' を検証するための JSON スキーマ構成。", "vscode.extension.contributes.debuggers.windows": "Windows 固有の設定。", diff --git a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 86136d977a5..37262b21f31 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,10 +12,10 @@ "breakpointRemoved": "ブレークポイントを削除しました。行 {0}、ファイル {1}", "compoundMustHaveConfigurations": "複合構成を開始するには、複合に \"configurations\" 属性が設定されている必要があります。", "configMissing": "構成 '{0}' が 'launch.json' 内にありません。", - "debugRequestNotSupported": "選択したデバッグ構成ではサポートされていない属性値 `{0}` : '{1}'。", - "debugRequesMissing": "選択しているデバッグ構成に '{0}' 属性が含まれていません ", + "debugRequestNotSupported": "選択しているデバッグ構成で `{0}` 属性はサポートされない値 '{1}' を指定しています。", + "debugRequesMissing": "選択しているデバッグ構成に `{0}` 属性が含まれていません。", "debugTypeNotSupported": "構成されているデバッグの種類 '{0}' はサポートされていません。", - "debugTypeMissing": "選択された起動構成のプロパティ 'type' がありません。", + "debugTypeMissing": "選択している起動構成の `type` プロパティがありません。", "preLaunchTaskErrors": "preLaunchTask '{0}' の実行中にビルド エラーが検出されました。", "preLaunchTaskError": "preLaunchTask '{0}' の実行中にビルド エラーが検出されました。", "preLaunchTaskExitCode": "preLaunchTask '{0}' が終了コード {1} で終了しました。", diff --git a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 38c84790727..57032e9d668 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -8,5 +8,5 @@ "replVariableAriaLabel": "変数 {0} に値 {1} があります、Read Eval Print Loop、デバッグ", "replExpressionAriaLabel": "式 {0} に値 {1} があります、Read Eval Print Loop、デバッグ", "replValueOutputAriaLabel": "{0}、Read Eval Print Loop、デバッグ", - "replKeyValueOutputAriaLabel": "出力変数 {0} に値 {1} があります、Read Eval Print Loop、デバッグ" + "replRawObjectAriaLabel": "Repl 変数 {0} に値 {1} があります、Read Eval Print Loop、デバッグ" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/jpn/src/vs/workbench/parts/files/browser/fileActions.i18n.json index b11053bec02..c73b9e75a7e 100644 --- a/i18n/jpn/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "'{0}' を削除しますか?", "undoBin": "ごみ箱から復元できます。", "undoTrash": "ゴミ箱から復元できます。", + "doNotAskAgain": "再度表示しない", "confirmDeleteMessageFolder": "'{0}' とその内容を完全に削除してもよろしいですか?", "confirmDeleteMessageFile": "'{0}' を完全に削除してもよろしいですか?", "irreversible": "このアクションは元に戻すことができません。", @@ -37,8 +38,6 @@ "openToSide": "横に並べて開く", "compareSource": "比較対象の選択", "globalCompareFile": "アクティブ ファイルを比較しています...", - "pickHistory": "比較対象として、以前に開いたファイルを選択する", - "unableToFileToCompare": "選択されたファイルを '{0}' と比較できません。", "openFileToCompare": "まずファイルを開いてから別のファイルと比較してください", "compareWith": "'{0}' と '{1}' を比較", "compareFiles": "ファイルの比較", @@ -47,7 +46,7 @@ "saveAs": "名前を付けて保存...", "saveAll": "すべて保存", "saveAllInGroup": "グループ内のすべてを保存する", - "saveFiles": "ダーティ ファイルを保存", + "saveFiles": "すべてのファイルを保存", "revert": "ファイルを元に戻す", "focusOpenEditors": "開いているエディターのビューにフォーカスする", "focusFilesExplorer": "ファイル エクスプローラーにフォーカスを置く", @@ -58,7 +57,7 @@ "openFile": "ファイルを開く...", "openFileInNewWindow": "新しいウィンドウでアクティブ ファイルを開く", "openFileToShowInNewWindow": "まずファイルを開いてから新しいウィンドウで開きます", - "revealInWindows": "エクスプローラーで表示します", + "revealInWindows": "エクスプローラーで表示", "revealInMac": "Finder で表示します", "openContainer": "このアイテムのフォルダーを開く", "revealActiveFileInWindows": "Windows エクスプローラーでアクティブ ファイルを表示する", diff --git a/i18n/jpn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index c1dd7969f73..a34064cb71f 100644 --- a/i18n/jpn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -40,10 +40,14 @@ "dynamicHeight": "開いているエディターのセクションの高さを要素の数に合わせて動的に調整するかどうかを制御します。", "autoReveal": "エクスプローラーでファイルを開くとき、自動的にファイルの内容を表示して選択するかどうかを制御します。", "enableDragAndDrop": "ドラッグ アンド ドロップを使用したファイルとフォルダーの移動をエクスプローラーが許可するかどうかを制御します。", + "confirmDragAndDrop": "ドラッグ アンド ドロップによるファイルやフォルダーの移動時にエクスプローラーが確認を求めるかどうかを制御します。", + "confirmDelete": "ごみ箱を経由したファイル削除時にエクスプローラーが確認を求めるかどうかを制御します。", "sortOrder.default": "ファイルとフォルダーをアルファベット順に名前で並び替えます。フォルダーはファイルの前に表示されます。", "sortOrder.mixed": "ファイルとフォルダーをアルファベット順に名前で並び替えます。ファイルはフォルダーと混交して表示されます。", "sortOrder.filesFirst": "ファイルとフォルダーをアルファベット順に名前で並び替えます。ファイルはフォルダーの前に表示されます。", "sortOrder.type": "ファイルとフォルダーをアルファベット順に拡張子で並び替えます。フォルダーはファイルの前に表示されます。", "sortOrder.modified": "ファイルとフォルダーを降順に最終更新日で並び替えます。フォルダーはファイルの前に表示されます。", - "sortOrder": "エクスプローラー内のファイルとフォルダーの並び順を制御します。既定の並び順に加えて、'mixed' (ファイルとフォルダーを混交した並び順)、' type' (ファイルの種類順)、' modified' (最終更新日時順)、または 'filesFirst' (フォルダーの前にファイルを並べる) のいずれかの並び順に設定できます。 " + "sortOrder": "エクスプローラー内のファイルとフォルダーの並び順を制御します。既定の並び順に加えて、'mixed' (ファイルとフォルダーを混交した並び順)、' type' (ファイルの種類順)、' modified' (最終更新日時順)、または 'filesFirst' (フォルダーの前にファイルを並べる) のいずれかの並び順に設定できます。 ", + "explorer.decorations.colors": "ファイルの装飾に配色を使用するかどうかを制御します。", + "explorer.decorations.badges": "ファイルの装飾にバッジを使用するかどうかを制御します。" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/jpn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 93f172ab424..ac152686d08 100644 --- a/i18n/jpn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "開いているフォルダーがありません", "explorerSection": "ファイル エクスプローラー セクション", - "noWorkspaceHelp": "まだフォルダーを開いていません。", + "noWorkspaceHelp": "まだフォルダーをワークスペースに追加していません。", + "addFolder": "フォルダーの追加", + "noFolderHelp": "まだフォルダーを開いていません。", "openFolder": "フォルダーを開く" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/jpn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index 2199fe2e71e..2a38faa864f 100644 --- a/i18n/jpn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -4,12 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "canNotResolve": "{0} フォルダーを解決できません", "fileInputAriaLabel": "ファイル名を入力します。Enter キーを押して確認するか、Esc キーを押して取り消します。", "filesExplorerViewerAriaLabel": "{0}、ファイル エクスプローラー", "dropFolders": "ワークスペースにフォルダーを追加しますか?", "dropFolder": "ワークスペースにフォルダーを追加しますか?", "addFolders": "フォルダーの追加(&&A)", "addFolder": "フォルダーの追加(&&A)", + "confirmMove": "'{0}' を移動しますか?", + "doNotAskAgain": "再度表示しない", "confirmOverwriteMessage": "'{0}' は保存先フォルダーに既に存在します。置き換えてもよろしいですか。", "irreversible": "このアクションは元に戻すことができません。", "replaceButtonLabel": "置換(&&R)" diff --git a/i18n/jpn/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/jpn/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..1f12247ced5 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/parts/markers/browser/markersFileDecorations.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. +{ + "label": "問題", + "tooltip.1": "このファイルに 1 つの問題", + "tooltip.N": "このファイルに {0} 個の問題", + "markers.showOnFile": "ファイルとフォルダーにエラーと警告を表示します。" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index 72cb0a9b0ae..c087aadd823 100644 --- a/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "既定の設定を上書きするには、このファイル内に設定を挿入します。", - "errorInvalidConfiguration": "設定を書き込めません。ファイル内のエラー/警告を修正してからもう一度お試しください。", "emptyWorkspaceSettingsHeader": "ユーザー設定を上書きするには、このファイル内に設定を挿入します。", "emptyFolderSettingsHeader": "ワークスペースの設定を上書きするには、このファイル内にフォルダーの設定を挿入します。", "defaultFolderSettingsTitle": "既定のフォルダー設定", diff --git a/i18n/jpn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/jpn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index b0aca24403e..306d7198a6b 100644 --- a/i18n/jpn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "コマンド '{0}' は現在のコンテキストでは無効です。", "recentlyUsed": "最近使用したもの", "morecCommands": "その他のコマンド", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "一致するコマンドはありません" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index 3eaaf1477f2..043a0f4014f 100644 --- a/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,6 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "{1} 個のうち {0} 個の変更", + "change": "{1} 個のうち {0} 個の変更 ", + "show previous change": "前の変更箇所を表示", + "show next change": "次の変更箇所を表示", "editorGutterModifiedBackground": "編集された行を示すエディター余白の背景色。", "editorGutterAddedBackground": "追加された行を示すエディター余白の背景色。", "editorGutterDeletedBackground": "削除された行を示すエディター余白の背景色。", diff --git a/i18n/jpn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index d39ad81f948..68c9699706e 100644 --- a/i18n/jpn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -17,7 +17,7 @@ "exclude": "検索でファイルとフォルダーを除外するために glob パターンを構成します。files.exclude 設定からすべての glob パターンを継承します。", "exclude.boolean": "ファイル パスの照合基準となる glob パターン。これを true または false に設定すると、パターンがそれぞれ有効/無効になります。", "exclude.when": "一致するファイルの兄弟をさらにチェックします。一致するファイル名の変数として $(basename) を使用します。", - "useRipgrep": "テキスト検索で ripgrep を使用するかどうかを制御します", + "useRipgrep": "テキストとファイル検索で ripgrep を使用するかどうかを制御します", "useIgnoreFilesByDefault": "新しいワークスペースで検索するときに、既定で .gitignore ファイルを使用するか .ignore ファイルを使用するかを制御します。", "search.quickOpen.includeSymbols": "グローバル シンボル検索の結果を、Quick Open の結果ファイルに含めるように構成します。" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/jpn/src/vs/workbench/parts/search/browser/searchActions.i18n.json index ab57a31ce38..1aa0dfacb0e 100644 --- a/i18n/jpn/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -19,7 +19,6 @@ "ClearSearchResultsAction.label": "検索結果のクリア", "FocusNextSearchResult.label": "次の検索結果にフォーカス", "FocusPreviousSearchResult.label": "前の検索結果にフォーカス", - "RemoveAction.label": "削除", "file.replaceAll.label": "すべて置換", "match.replace.label": "置換" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index adb4b5b9a1d..057c918a74d 100644 --- a/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,8 +10,8 @@ "vscode.extension.contributes.snippets": "スニペットを提供します。", "vscode.extension.contributes.snippets-language": "このスニペットの提供先の言語識別子です。", "vscode.extension.contributes.snippets-path": "スニペット ファイルのパス。拡張機能フォルダーの相対パスであり、通常 './snippets/' で始まります。", - "badFile": "スニペット ファイル \"{0}\" を読み込むことができませんでした。", "badVariableUse": "スニペット \"{0}\" は、スニペット変数とスニペット プレースホルダーを混乱させる可能性が非常にあります。詳細については https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax をご覧ください。", + "badFile": "スニペット ファイル \"{0}\" を読み込むことができませんでした。", "source.snippet": "ユーザー スニペット", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index b93c884904a..ec353f855bf 100644 --- a/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -14,6 +14,7 @@ "runningTasks": "実行中のタスクを表示", "tasks": "タスク", "TaskSystem.noHotSwap": "アクティブなタスクを実行しているタスク実行エンジンを変更するには、ウィンドウの再読み込みが必要です", + "TaskServer.folderIgnored": "{0} フォルダーはタスク バージョン 0.1.0 を使用しているために無視されます", "TaskService.noBuildTask1": "ビルド タスクが定義されていません。tasks.json ファイルでタスクに 'isBuildCommand' というマークを付けてください。", "TaskService.noBuildTask2": "ビルド タスクが定義されていません。tasks.json ファイルでタスクに 'build' グループとしてマークを付けてください。", "TaskService.noTestTask1": "テスト タスクが定義されていません。tasks.json ファイルでタスクに 'isTestCommand' というマークを付けてください。", @@ -30,6 +31,7 @@ "TaskSystem.activeSame.noBackground": "'{0}' タスクは既にアクティブです。タスクを終了するにはタスク メニューから`タスクの終了...` を使用してください。 ", "TaskSystem.active": "既に実行中のタスクがあります。まずこのタスクを終了してから、別のタスクを実行してください。", "TaskSystem.restartFailed": "タスク {0} を終了して再開できませんでした", + "TaskService.noConfiguration": "エラー: {0} タスク検出は次の構成に対してタスクを提供していません:\n{1}\nこのタスクは無視されます。\n", "TaskSystem.configurationErrors": "エラー: 指定したタスク構成に検証エラーがあり、使用できません。最初にエラーを修正してください。", "taskService.ignoreingFolder": "ワークスペース フォルダー {0} のタスク構成を無視します。マルチ フォルダー ワークスペース タスクのサポートには、すべてのフォルダーがタスク バージョン 2.0.0 を使用する必要があります。\n", "TaskSystem.invalidTaskJson": "エラー: tasks.json ファイルの内容に構文エラーがあります。訂正してからタスクを実行してください。\n", 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 4d0ecdd18b0..76dbf9d84f0 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 @@ -17,6 +17,7 @@ "terminal.integrated.fontFamily": "端末のフォント ファミリを制御します。既定値は editor.fontFamily になります。", "terminal.integrated.fontSize": "ターミナルのフォント サイズをピクセル単位で制御します。", "terminal.integrated.lineHeight": "ターミナルの行の高さを制御します。この数値にターミナルのフォント サイズを乗算すると、実際の行の高さ (ピクセル単位) になります。", + "terminal.integrated.enableBold": "ターミナル内でテキストを太字にするかどうか。ターミナル シェルのサポートが必要なことに注意してください。", "terminal.integrated.cursorBlinking": "ターミナルのカーソルを点滅させるかどうかを制御します。", "terminal.integrated.cursorStyle": "端末のカーソルのスタイルを制御します。", "terminal.integrated.scrollback": "端末がそのバッファーに保持できる最大行数を制御します。", 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 3c51dcd1d5d..6015fb400ae 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 @@ -16,7 +16,6 @@ "workbench.action.terminal.new.short": "新しいターミナル", "workbench.action.terminal.focus": "端末にフォーカス", "workbench.action.terminal.focusNext": "次の端末にフォーカス", - "workbench.action.terminal.focusAtIndex": "ターミナル {0} にフォーカス", "workbench.action.terminal.focusPrevious": "前のターミナルにフォーカス", "workbench.action.terminal.paste": "アクティブなターミナルに貼り付け", "workbench.action.terminal.DefaultShell": "既定のシェルの選択", diff --git a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 0c5802f9502..acbc00bf882 100644 --- a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "コピー", - "createNewTerminal": "新しいターミナル", "paste": "貼り付け", "selectAll": "すべて選択", "clear": "クリア" diff --git a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 0303f610bb0..42ec3aff619 100644 --- a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "OK、今後は表示しない", "terminal.integrated.chooseWindowsShell": "優先するターミナル シェルを選択します。これは後で設定から変更できます", "terminalService.terminalCloseConfirmationSingular": "アクティブなターミナル セッションが 1 つあります。中止しますか?", - "terminalService.terminalCloseConfirmationPlural": "アクティブなターミナル セッションが {0} 個あります。中止しますか?", - "yes": "はい" + "terminalService.terminalCloseConfirmationPlural": "アクティブなターミナル セッションが {0} 個あります。中止しますか?" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/jpn/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..d93af154acf --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "設定の概要です。このラベルは、設定ファイルでコメントの区切り文字として使用します。", + "vscode.extension.contributes.configuration.properties": "構成のプロパティの説明です。", + "scope.window.description": "ウィンドウ固有の構成。ユーザーまたはワークスペースの設定で構成できます。", + "scope.resource.description": "リソース固有の構成。ユーザー、ワークスペース、またはフォルダーの設定で構成できます。", + "scope.description": "構成が適用される範囲。 使用可能なスコープは `window` と ` resource` です。", + "vscode.extension.contributes.configuration": "構成の設定を提供します。", + "invalid.title": "'configuration.title' は、文字列である必要があります", + "vscode.extension.contributes.defaultConfiguration": "言語ごとに既定のエディター構成の設定を提供します。", + "invalid.properties": "'configuration.properties' は、オブジェクトである必要があります", + "invalid.allOf": "'configuration.allOf' は非推奨で使用できなくなります。代わりに 'configuration' コントリビューション ポイントに複数の構成セクションを配列として渡します。", + "workspaceConfig.folders.description": "ワークスペースで読み込まれるフォルダーのリスト。", + "workspaceConfig.path.description": "ファイルパス。例: `/root/folderA` または `./folderA` のようなワークスペース ファイルの場所に対して解決される相対パス。", + "workspaceConfig.name.description": "フォルダーにつけるオプションの名前。" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/jpn/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/editor/common/editorService.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. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/jpn/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index 2773e1cc1be..31dd84eaa5c 100644 --- a/i18n/jpn/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/jpn/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -6,6 +6,7 @@ { "schema.token.settings": "トークンの色とスタイル。", "schema.token.foreground": "トークンの前景色。", + "schema.token.background.warning": "トークンの背景色は、現在サポートされていません。", "schema.token.fontStyle": "ルールのフォント スタイル: '斜体'、'太字'、'下線' のいずれかまたはこれらの組み合わせ", "schema.fontStyle.error": "フォント スタイルは '斜体'、'太字'、'下線'を組み合わせる必要があります。", "schema.properties.name": "ルールの説明。", diff --git a/i18n/jpn/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/jpn/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index a38d55a5642..335b53c2495 100644 --- a/i18n/jpn/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/jpn/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "フォントを使用する場合: テキスト フォントに対するフォントサイズの割合。設定されていない場合、既定値はフォント定義のサイズになります。", "schema.fontId": "フォントを使用する場合: フォントの ID。設定されていない場合、既定値は最初のフォント定義になります。", "schema.light": "明るい配色テーマでのファイル アイコンの任意の関連付け。", - "schema.highContrast": "ハイ コントラスト配色テーマでのファイル アイコンの任意の関連付け。" + "schema.highContrast": "ハイ コントラスト配色テーマでのファイル アイコンの任意の関連付け。", + "schema.hidesExplorerArrows": "このテーマがアクティブな時に、エクスプローラーの矢印を非表示にするかどうかを構成します。" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..c985a8de47f --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.themes": "TextMate の配色テーマを提供します。", + "vscode.extension.contributes.themes.id": "ユーザー設定で使用されるアイコン テーマの ID。", + "vscode.extension.contributes.themes.label": "UI で表示される配色テーマのラベル。", + "vscode.extension.contributes.themes.uiTheme": "エディターの周囲の色を定義する基本テーマ: 'vs' は明るい色のテーマで、'vs-dark' は濃い色のテーマです。'hc-black' は濃い色のハイ コントラストのテーマです。", + "vscode.extension.contributes.themes.path": "tmTheme ファイルのパス。拡張機能フォルダーに対する相対パスで、通常 './themes/themeFile.tmTheme' です。", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "`contributes.{0}.path` に文字列が必要です。提供された値: {1}", + "invalid.path.1": "拡張機能のフォルダー ({2}) の中に `contributes.{0}.path` ({1}) が含まれている必要があります。これにより拡張を移植できなくなる可能性があります。" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..26366aa3de6 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.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. +{ + "error.cannotparseicontheme": "アイコン ファイルの解析中に問題が発生しました: {0}" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..b9a14b3199a --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "ユーザー設定で使用されるアイコン テーマの ID。", + "vscode.extension.contributes.iconThemes.label": "UI に表示されるアイコン テーマのラベル。", + "vscode.extension.contributes.iconThemes.path": "アイコン テーマの定義ファイルのパス。このパスは拡張フォルダーの相対パスであり、通常は './icons/awesome-icon-theme.json' です。", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "`contributes.{0}.path` に文字列が必要です。提供された値: {1}", + "reqid": "`contributes.{0}.id` に文字列が必要です。提供された値: {1}", + "invalid.path.1": "拡張機能のフォルダー ({2}) の中に `contributes.{0}.path` ({1}) が含まれている必要があります。これにより拡張を移植できなくなる可能性があります。" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index 18938fb3a92..db40a8ef3c1 100644 --- a/i18n/jpn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,31 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "TextMate の配色テーマを提供します。", - "vscode.extension.contributes.themes.id": "ユーザー設定で使用されるアイコン テーマの ID。", - "vscode.extension.contributes.themes.label": "UI で表示される配色テーマのラベル。", - "vscode.extension.contributes.themes.uiTheme": "エディターの周囲の色を定義する基本テーマ: 'vs' は明るい色のテーマで、'vs-dark' は濃い色のテーマです。'hc-black' は濃い色のハイ コントラストのテーマです。", - "vscode.extension.contributes.themes.path": "tmTheme ファイルのパス。拡張機能フォルダーに対する相対パスで、通常 './themes/themeFile.tmTheme' です。", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "ユーザー設定で使用されるアイコン テーマの ID。", - "vscode.extension.contributes.iconThemes.label": "UI に表示されるアイコン テーマのラベル。", - "vscode.extension.contributes.iconThemes.path": "アイコン テーマの定義ファイルのパス。このパスは拡張フォルダーの相対パスであり、通常は './icons/awesome-icon-theme.json' です。", "migration.completed": "ユーザー設定に新しいテーマの設定が追加されました。{0} に利用可能なバックアップがあります。", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "`contributes.{0}.path` に文字列が必要です。提供された値: {1}", - "invalid.path.1": "拡張機能のフォルダー ({2}) の中に `contributes.{0}.path` ({1}) が含まれている必要があります。これにより拡張を移植できなくなる可能性があります。", - "reqid": "`contributes.{0}.id` に文字列が必要です。提供された値: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "アイコン ファイルの解析中に問題が発生しました: {0}", "colorTheme": "ワークベンチで使用する配色テーマを指定します。", "colorThemeError": "テーマが不明、またはインストールされていません。", "iconTheme": "ワークベンチで使用するアイコンのテーマを指定します。'null' を指定するとファイル アイコンが表示されなくなります。", "noIconThemeDesc": "ファイル アイコンがありません", "iconThemeError": "ファイル アイコンのテーマが不明、またはインストールされていません。", "workbenchColors": "現在選択している配色テーマで配色を上書きします。", - "workbenchColors.deprecated": "この設定はもう試験的なものではなく、名前が 'workbench.colorCustomizations' に変更されています", - "workbenchColors.deprecatedDescription": "代わりに 'workbench.colorCustomizations' を使用してください", "editorColors": "現在選択している配色テーマで配色とフォント スタイルを上書きします。", "editorColors.comments": "コメントの色とスタイルを設定します", "editorColors.strings": "文字列リテラルの色とスタイルを設定します。", diff --git a/i18n/jpn/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/jpn/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..963427aa46c --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/workspace/node/workspaceEditingService.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. +{ + "openWorkspaceConfigurationFile": "ワークスペースの構成ファイルを開く", + "close": "閉じる" +} \ No newline at end of file diff --git a/i18n/kor/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/kor/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index c2b4c21ed25..3fd8cdf57b3 100644 --- a/i18n/kor/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/kor/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "예: myFile.txt", - "activeEditorMedium": "예: myFolder/myFile.txt", - "activeEditorLong": "예: /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "예: myFolder1, myFolder2, myFolder3", - "rootPath": "예: /Users/Development/myProject", - "folderName": "예: myFolder", - "folderPath": "예: /Users/Development/myFolder", "appName": "예: VS Code", "dirty": "활성 편집기가 더티인 경우 더티 표시기", "separator": "값이 있는 변수로 둘러싸인 경우에만 표시되는 조건부 구분 기호 (' - ')", diff --git a/i18n/kor/extensions/emmet/package.i18n.json b/i18n/kor/extensions/emmet/package.i18n.json index 0576d669667..7b41ed8ca2a 100644 --- a/i18n/kor/extensions/emmet/package.i18n.json +++ b/i18n/kor/extensions/emmet/package.i18n.json @@ -28,13 +28,6 @@ "command.incrementNumberByTen": "10씩 증가", "command.decrementNumberByTen": "10씩 감소", "emmetSyntaxProfiles": "지정된 구문에 대한 프로필을 정의하거나 특정 규칙이 포함된 고유한 프로필을 사용하세요.", - "emmetExclude": "Emmet 약어를 확장하면 안 되는 언어의 배열입니다.", - "emmetExtensionsPath": "Emmet 프로필 및 코드 조각이 포함된 폴더의 경로입니다.'", - "emmetShowExpandedAbbreviation": "확장된 emmet 약어를 제안으로 표시합니다.\n\"inMarkupAndStylesheetFilesOnly\" 옵션이 html, haml, jade, slim, xml, xsl, css, scss, sass, less 및 stylus에 적용됩니다.\n\"always\" 옵션이 마크업/css에 관계없이 파일의 모든 부분에 적용됩니다.", - "emmetShowAbbreviationSuggestions": "가능한 emmet 약어를 제안으로 표시합니다. 스타일시트에는 적용되지 않고 emmet.showExpandedAbbreviation이 \"never\"로 설정되어 있을 때도 적용되지 않습니다.", - "emmetIncludeLanguages": "기본 지원되지 않는 언어에서 emmet 약어를 사용합니다. 언어와 emmet 지원 언어 사이에 매핑을 추가합니다.\n예: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", - "emmetVariables": "emmet 조각에 사용되는 변수", - "emmetTriggerExpansionOnTab": "사용하도록 설정하면 emmet 약어는 키를 눌렀을 때 확장됩니다.", "emmetPreferences": "Emmet의 일부 작업 및 해결 프로그램의 동작을 수정하는 데 사용되는 기본 설정입니다.", "emmetPreferencesIntUnit": "정수 값의 기본 단위", "emmetPreferencesFloatUnit": "부동 소수점 값의 기본 단위", @@ -43,6 +36,5 @@ "emmetPreferencesStylusAfter": "Stylus 파일에서 CSS 약어를 확장할 때 CSS 속성의 끝에 배치할 기호", "emmetPreferencesCssBetween": "CSS 약어를 확장할 때 CSS 속성 및 값 사이에 배치할 기호", "emmetPreferencesSassBetween": "Sass 파일에서 CSS 약어를 확장할 때 CSS 속성 및 값 사이에 배치할 기호", - "emmetPreferencesStylusBetween": "Stylus 파일에서 CSS 약어를 확장할 때 CSS 속성 및 값 사이에 배치할 기호", - "emmetShowSuggestionsAsSnippets": "True이면 emmet 제안이 코드 조각으로 표시되며 editor.snippetSuggestions 설정에 따라 코드 조각을 정렬할 수 있습니다." + "emmetPreferencesStylusBetween": "Stylus 파일에서 CSS 약어를 확장할 때 CSS 속성 및 값 사이에 배치할 기호" } \ No newline at end of file diff --git a/i18n/kor/extensions/git/out/commands.i18n.json b/i18n/kor/extensions/git/out/commands.i18n.json index 74283128949..1e7920f8a21 100644 --- a/i18n/kor/extensions/git/out/commands.i18n.json +++ b/i18n/kor/extensions/git/out/commands.i18n.json @@ -12,8 +12,8 @@ "cloning": "Git 리포지토리를 복제하는 중...", "openrepo": "리포지토리 열기", "proposeopen": "복제된 리포지토리를 여시겠습니까?", - "path to init": "폴더 경로", - "provide path": "Git 리포지토리를 초기화할 폴더 경로를 입력하세요.", + "init repo": "리포지토리 초기화", + "create repo": "리포지토리 초기화", "HEAD not available": "'{0}'의 HEAD 버전이 없습니다.", "confirm stage files with merge conflicts": "병합 충돌이 있는 {0} 파일을 스테이징하시겠습니까?", "confirm stage file with merge conflicts": "병합 충돌이 있는 {0}을(를) 스테이징하시겠습니까?", diff --git a/i18n/kor/extensions/git/out/repository.i18n.json b/i18n/kor/extensions/git/out/repository.i18n.json index c5c45af0062..6334a9e47ef 100644 --- a/i18n/kor/extensions/git/out/repository.i18n.json +++ b/i18n/kor/extensions/git/out/repository.i18n.json @@ -21,6 +21,8 @@ "deleted by us": "본인이 삭제함", "both added": "둘 다 추가됨", "both modified": "둘 다 수정됨", + "untracked, short": "U", + "modified, short": "M", "commit": "커밋", "merge changes": "변경 내용 병합", "staged changes": "스테이징된 변경 내용", diff --git a/i18n/kor/extensions/typescript/package.i18n.json b/i18n/kor/extensions/typescript/package.i18n.json index 9024eb3187d..7077f24ff61 100644 --- a/i18n/kor/extensions/typescript/package.i18n.json +++ b/i18n/kor/extensions/typescript/package.i18n.json @@ -44,7 +44,6 @@ "typescript.npm": "자동 입력 인식에 사용된 NPM 실행 파일 경로를 지정합니다. TypeScript >= 2.3.4가 필요합니다.", "typescript.check.npmIsInstalled": "자동 입력 인식에 대해 NPM이 설치되어 있는지 확인합니다.", "javascript.nameSuggestions": "JavaScript 제안 목록의 파일에서 고유한 이름 포함을 사용/사용 안 함으로 설정합니다.", - "typescript.tsc.autoDetect": "tsc 작업의 자동 검색을 켜거나 끕니다.", "typescript.problemMatchers.tsc.label": "TypeScript 문제", "typescript.problemMatchers.tscWatch.label": "TypeScript 문제(감시 모드)" } \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/kor/src/vs/editor/contrib/find/browser/findWidget.i18n.json index c60d6d54352..e90c793f848 100644 --- a/i18n/kor/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/kor/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,6 @@ "label.replaceButton": "바꾸기", "label.replaceAllButton": "모두 바꾸기", "label.toggleReplaceButton": "바꾸기 모드 설정/해제", - "title.matchesCountLimit": "처음 999개의 결과가 강조 표시되지만 모든 찾기 작업은 전체 텍스트에 대해 수행됩니다.", "label.matchesLocation": "{0}/{1}", "label.noResults": "결과 없음" } \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/kor/src/vs/editor/contrib/find/common/findController.i18n.json index d0e58fa206e..7201d1ab08f 100644 --- a/i18n/kor/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/kor/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "다음 선택 찾기", "previousSelectionMatchFindAction": "이전 선택 찾기", "startReplace": "바꾸기", - "addSelectionToNextFindMatch": "다음 일치 항목 찾기에 선택 항목 추가", - "addSelectionToPreviousFindMatch": "이전 일치 항목 찾기에 선택 항목 추가", - "moveSelectionToNextFindMatch": "다음 일치 항목 찾기로 마지막 선택 항목 이동", - "moveSelectionToPreviousFindMatch": "마지막 선택 항목을 이전 일치 항목 찾기로 이동", - "selectAllOccurrencesOfFindMatch": "일치 항목 찾기의 모든 항목 선택", - "changeAll.label": "모든 항목 변경", "showNextFindTermAction": "다음 검색어 표시", "showPreviousFindTermAction": "이전 검색어 표시" } \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/kor/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 2cd42573465..af6f5d6235c 100644 --- a/i18n/kor/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/kor/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "위에 커서 추가", "mutlicursor.insertBelow": "아래에 커서 추가", - "mutlicursor.insertAtEndOfEachLineSelected": "줄 끝에 커서 추가" + "mutlicursor.insertAtEndOfEachLineSelected": "줄 끝에 커서 추가", + "addSelectionToNextFindMatch": "다음 일치 항목 찾기에 선택 항목 추가", + "addSelectionToPreviousFindMatch": "이전 일치 항목 찾기에 선택 항목 추가", + "moveSelectionToNextFindMatch": "다음 일치 항목 찾기로 마지막 선택 항목 이동", + "moveSelectionToPreviousFindMatch": "마지막 선택 항목을 이전 일치 항목 찾기로 이동", + "selectAllOccurrencesOfFindMatch": "일치 항목 찾기의 모든 항목 선택", + "changeAll.label": "모든 항목 변경" } \ No newline at end of file diff --git a/i18n/kor/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/kor/src/vs/platform/theme/common/colorRegistry.i18n.json index 98c0d356e83..8e8997c7ddf 100644 --- a/i18n/kor/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/kor/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "잘못된 색 형식입니다. #RGB, #RGBA, #RRGGBB 또는 #RRGGBBAA를 사용하세요.", "schema.colors": "워크벤치에서 사용되는 색입니다.", "foreground": "전체 전경색입니다. 이 색은 구성 요소에서 재정의하지 않은 경우에만 사용됩니다.", "errorForeground": "오류 메시지에 대한 전체 전경색입니다. 이 색은 구성 요소에서 재정의하지 않은 경우에만 사용됩니다.", diff --git a/i18n/kor/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/kor/src/vs/workbench/browser/actions/workspaceActions.i18n.json index b414854fcac..b3a4fc27abc 100644 --- a/i18n/kor/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -13,6 +13,7 @@ "select": "선택(&&S)", "selectWorkspace": "작업 영역 폴더 선택", "removeFolderFromWorkspace": "작업 영역에서 폴더 삭제", + "openFolderSettings": "폴더 설정 열기", "saveWorkspaceAsAction": "작업 영역을 다른 이름으로 저장", "save": "저장(&&S)", "saveWorkspace": "작업 영역 저장", diff --git a/i18n/kor/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index 775ac027185..6ab66076b97 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "작업 막대 숨기기", - "activityBarAriaLabel": "활성 뷰 전환기", "globalActions": "전역 작업" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..f515e983418 --- /dev/null +++ b/i18n/kor/src/vs/workbench/browser/parts/compositebar/compositeBar.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. +{ + "activityBarAriaLabel": "활성 뷰 전환기" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..882b528591a --- /dev/null +++ b/i18n/kor/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "추가 뷰", + "numberBadge": "{0}({1})", + "manageExtension": "확장 관리", + "titleKeybinding": "{0}({1})", + "toggle": "뷰 고정 전환" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 29467820136..32f439e8de1 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "두 번째 그룹에 편집기 표시", "groupThreePicker": "세 번째 그룹에 편집기 표시", "allEditorsPicker": "열려 있는 모든 편집기 표시", - "view": "보기" + "view": "보기", + "file": "파일" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 1b2e94b2c53..1a622afa7d4 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "'{0}' 명령은 현재 사용하도록 설정되지 않아 실행할 수 없습니다.", "manageExtension": "확장 관리" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/kor/src/vs/workbench/electron-browser/main.contribution.i18n.json index 7c9f66647d9..22baa2ccddf 100644 --- a/i18n/kor/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,18 +10,14 @@ "workspaces": "작업 영역", "developer": "개발자", "showEditorTabs": "열려 있는 편집기를 탭에서 표시할지 여부를 제어합니다.", - "workbench.editor.labelFormat.default": "파일 이름을 표시합니다. 탭이 사용하도록 설정되어 있고 하나의 그룹에서 파일 2개의 이름이 동일하면, 각 파일 경로의 특정 섹션이 추가됩니다. 탭이 사용하도록 설정되어 있지 않으면, 작업 영역 루트에 대한 경로는 편집기가 활성 상태일 때 표시됩니다.", "workbench.editor.labelFormat.short": "디렉터리 이름 앞에 오는 파일의 이름을 표시합니다.", - "workbench.editor.labelFormat.medium": "작업 영역 루트를 기준으로 하는 상대 경로 앞에 오는 파일의 이름을 표시합니다.", "workbench.editor.labelFormat.long": "절대 경로 앞에 오는 파일의 이름을 표시합니다.", "tabDescription": "편집기의 레이블 형식을 제어합니다. 예를 들어 이 설정을 변경하면 파일의 위치를 더 쉽게 파악할 수 있습니다.:\n- 짧게: 'parent'\n- 중간: 'workspace/src/parent'\n- 길게: '/home/user/workspace/src/parent'\n- 기본값: '.../parent', 다른 탭이 동일한 제목을 공유하거나, 탭을 사용하지 않도록 설정한 경우 작업 영역 상대 경로", "editorTabCloseButton": "편집기의 탭 닫기 단추의 위치를 제어하거나 'off'로 설정된 경우 이 단추를 사용하지 않도록 설정합니다.", "showIcons": "열린 편집기를 아이콘과 함께 표시할지 여부를 제어합니다. 이를 위해서는 아이콘 테마도 사용하도록 설정해야 합니다.", "enablePreview": "열려 있는 편집기를 미리 보기로 표시할지 여부를 제어합니다. 미리 보기 편집기는 유지된 상태까지(예: 두 번 클릭 또는 편집을 통해) 다시 사용되며 기울임꼴 글꼴 스타일로 표시됩니다.", "enablePreviewFromQuickOpen": "Quick Open에서 연 편집기를 미리 보기로 표시할지 여부를 제어합니다. 미리 보기 편집기는 유지된 상태까지(예: 두 번 클릭 또는 편집을 통해) 다시 사용됩니다.", - "editorOpenPositioning": "편집기가 열리는 위치를 제어합니다. 현재 활성 편집기의 왼쪽 또는 오른쪽에서 편집기를 열려면 '왼쪽' 또는 '오른쪽'을 선택합니다. 현재 활성 편집기와 독립적으로 편집기를 열려면 '처음' 또는 '마지막'을 선택합니다.", "revealIfOpen": "편집기를 여는 경우 보이는 그룹 중 하나에 표시할지 여부를 제어합니다. 사용하지 않도록 설정할 경우 편집기가 기본적으로 현재 활성 편집기 그룹에 열립니다. 사용하도록 설정할 경우 현재 활성 편집기 그룹에서 편집기가 다시 열리지 않고 이미 열린 편집기가 표시됩니다. 강제로 편집기가 특정 그룹에서 열리거나 현재 활성 그룹 옆에 열리도록 하는 등의 일부 경우에는 이 설정이 무시됩니다.", - "commandHistory": "명령 팔레트 기록에 최근 사용 명령을 몇 개 유지할지 결정합니다. 0으로 설정하면 명령 기록을 사용하지 않습니다.", "preserveInput": "다음에 열 때 마지막으로 명령 팔레트에 입력한 내용을 복원할지 결정합니다.", "closeOnFocusLost": "Quick Open가 포커스를 잃으면 자동으로 닫을지 여부를 제어합니다.", "openDefaultSettings": "설정을 열면 모든 기본 설정을 표시하는 편집기도 열리는지 여부를 제어합니다.", @@ -50,7 +46,6 @@ "restoreWindows": "다시 시작한 이후에 창을 다시 여는 방법을 설정합니다. 'none'을 선택하면 항상 빈 작업 영역으로 시작하고 'one'을 선택하면 마지막으로 작업한 창이 다시 열리고 'folders'를 선택하면 열었던 폴더가 포함된 모든 창이 다시 열리며 'all'을 선택하면 지난 세션의 모든 창이 다시 열립니다.", "restoreFullscreen": "창이 전체 화면 모드에서 종료된 경우 창을 전체 화면 모드로 복원할지 여부를 제어합니다.", "zoomLevel": "창의 확대/축소 수준을 조정합니다. 원래 크기는 0이고 각 상한 증분(예: 1) 또는 하한 증분(예: -1)은 20% 더 크거나 더 작게 확대/축소하는 것을 나타냅니다. 10진수를 입력하여 확대/축소 수준을 세부적으로 조정할 수도 있습니다.", - "title": "활성 편집기를 기반으로 창 제목을 제어합니다. 변수는 컨텍스트를 기반으로 대체됩니다. \n${activeEditorShort}: 예: myFile.txt\n${activeEditorMedium}: 예: myFolder/myFile.txt\n${activeEditorLong}: 예: /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: 예: myFolder\n${folderPath}: 예: /Users/Development/myFolder\n${rootName}: 예: myFolder1, myFolder2, myFolder3\n${rootPath}: 예: /Users/Development/myWorkspace\n${appName}: 예: VS Code\n${dirty}: 활성 편집기가 더티인 경우 더티 표시기\n${separator}: 값이 있는 변수로 둘러싸인 경우에만 표시되는 조건부 구분 기호(\" - \")", "window.newWindowDimensions.default": "화면 가운데에서 새 창을 엽니다.", "window.newWindowDimensions.inherit": "마지막 활성 창과 동일한 크기로 새 창을 엽니다.", "window.newWindowDimensions.maximized": "최대화된 새 창을 엽니다.", diff --git a/i18n/kor/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 674839cc069..753a861d411 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, 디버그", "debugAriaLabel": "실행할 시작 구성의 이름을 입력하세요.", + "addConfigTo": "구성 추가 ({0})...", + "addConfiguration": "구성 추가...", "noConfigurationsMatching": "일치하는 디버그 구성 없음", "noConfigurationsFound": "디버그 구성을 찾을 수 없습니다. 'launch.json' 파일을 만드세요." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..416944e28fd --- /dev/null +++ b/i18n/kor/src/vs/workbench/parts/debug/browser/debugStatus.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. +{ + "debug": "디버그" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/kor/src/vs/workbench/parts/debug/browser/debugViewlet.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/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 2b0632b1635..0db91f83b2f 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 @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "초기 'launch.json'을 생성하기 위한 구성입니다.", "vscode.extension.contributes.debuggers.languages": "디버그 확장이 \"기본 디버거\"로 간주될 수 있는 언어 목록입니다.", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "지정하는 경우 VS Code에서 이 명령을 호출하여 디버그 어댑터의 실행 파일 경로 및 전달할 인수를 확인합니다.", - "vscode.extension.contributes.debuggers.startSessionCommand": "지정하는 경우 VS Code에서 이 확장을 대상으로 하는 \"디버그\" 또는 \"실행\" 작업에 대해 이 명령을 호출합니다.", "vscode.extension.contributes.debuggers.configurationSnippets": "'launch.json'에 새 구성을 추가하는 코드 조각입니다.", "vscode.extension.contributes.debuggers.configurationAttributes": "'launch.json'의 유효성 검사를 위한 JSON 스키마 구성입니다.", "vscode.extension.contributes.debuggers.windows": "Windows 특정 설정", diff --git a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 7b4fa4d91c9..13125eab426 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,10 +12,7 @@ "breakpointRemoved": "파일 {1}, 줄 {0}에서 중단점이 제거되었습니다.", "compoundMustHaveConfigurations": "여러 구성을 시작하려면 복합에 \"configurations\" 특성 집합이 있어야 합니다.", "configMissing": "'{0}' 구성이 'launch.json'에 없습니다.", - "debugRequestNotSupported": "선택한 디버그 구성에 지원되지 않는 특성 값 `{0}`: '{1}'이(가) 있습니다.", - "debugRequesMissing": "선택한 디버그 구성에 특성 '{0}'이(가) 없습니다.", "debugTypeNotSupported": "구성된 디버그 형식 '{0}'은(는) 지원되지 않습니다.", - "debugTypeMissing": "선택한 시작 구성에 대한 'type' 속성이 없습니다.", "preLaunchTaskErrors": "preLaunchTask '{0}' 진행 중에 빌드 오류가 감지되었습니다.", "preLaunchTaskError": "preLaunchTask '{0}' 진행 중에 빌드 오류가 감지되었습니다.", "preLaunchTaskExitCode": "preLaunchTask '{0}'이(가) {1} 종료 코드와 함께 종료되었습니다.", diff --git a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 9c417b8c7dd..1da0363bd93 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -7,6 +7,5 @@ "stateCapture": "개체 상태는 첫 번재 평가에서 캡처됩니다.", "replVariableAriaLabel": "{0} 변수에 {1} 값이 있습니다. 읽기 평가 인쇄 루프, 디버그", "replExpressionAriaLabel": "{0} 식에 {1} 값이 있습니다. 읽기 평가 인쇄 루프, 디버그", - "replValueOutputAriaLabel": "{0}, 읽기 평가 인쇄 루프, 디버그", - "replKeyValueOutputAriaLabel": "출력 변수 {0}에 {1} 값이 있습니다. 읽기 평가 인쇄 루프, 디버그" + "replValueOutputAriaLabel": "{0}, 읽기 평가 인쇄 루프, 디버그" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/kor/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 8bcb4133777..1f93f5ae2c6 100644 --- a/i18n/kor/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -37,8 +37,6 @@ "openToSide": "측면에서 열기", "compareSource": "비교를 위해 선택", "globalCompareFile": "활성 파일을 다음과 비교...", - "pickHistory": "비교할 이전에 연 파일 선택", - "unableToFileToCompare": "선택한 파일을 '{0}'과(와) 비교할 수 없습니다.", "openFileToCompare": "첫 번째 파일을 열어서 다른 파일과 비교합니다.", "compareWith": "'{0}'과(와) '{1}' 비교", "compareFiles": "파일 비교", @@ -47,7 +45,6 @@ "saveAs": "다른 이름으로 저장...", "saveAll": "모두 저장", "saveAllInGroup": "그룹의 모든 항목 저장", - "saveFiles": "더티 파일 저장", "revert": "파일 되돌리기", "focusOpenEditors": "열려 있는 편집기 뷰에 포커스", "focusFilesExplorer": "파일 탐색기에 포커스", diff --git a/i18n/kor/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/kor/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 643334c6aba..42fb83a81b7 100644 --- a/i18n/kor/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,6 @@ { "noWorkspace": "열린 폴더 없음", "explorerSection": "파일 탐색기 섹션", - "noWorkspaceHelp": "아직 폴더를 열지 않았습니다.", + "noFolderHelp": "아직 폴더를 열지 않았습니다.", "openFolder": "폴더 열기" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/kor/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..9a5ca02f322 --- /dev/null +++ b/i18n/kor/src/vs/workbench/parts/markers/browser/markersFileDecorations.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. +{ + "label": "문제" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index 393b61b671f..fa4d6d2e024 100644 --- a/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "설정을 여기에 넣어서 기본 설정을 덮어씁니다.", - "errorInvalidConfiguration": "설정에 쓸 수 없습니다. 파일에서 오류/경고를 해결하고 다시 시도하세요.", "emptyWorkspaceSettingsHeader": "설정을 여기에 넣어서 사용자 설정을 덮어씁니다.", "emptyFolderSettingsHeader": "폴더 설정을 여기에 넣어서 작업 영역 설정을 덮어씁니다.", "defaultFolderSettingsTitle": "기본 폴더 설정", diff --git a/i18n/kor/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/kor/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 3643111bada..a8785cacb78 100644 --- a/i18n/kor/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "'{0}' 명령은 현재 컨텍스트에서 사용할 수 없습니다.", "recentlyUsed": "최근에 사용한 항목", "morecCommands": "기타 명령", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "일치하는 명령 없음" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index eda87691830..4b214694baf 100644 --- a/i18n/kor/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -17,7 +17,6 @@ "exclude": "검색에서 파일 및 폴더를 제외하도록 GLOB 패턴을 구성합니다. files.exclude 설정에서 모든 GLOB 패턴을 상속합니다.", "exclude.boolean": "파일 경로를 일치시킬 GLOB 패턴입니다. 패턴을 사용하거나 사용하지 않도록 설정하려면 true 또는 false로 설정하세요.", "exclude.when": "일치하는 파일의 형제에 대한 추가 검사입니다. $(basename)을 일치하는 파일 이름에 대한 변수로 사용하세요.", - "useRipgrep": "텍스트 검색에서 ripgrep 사용 여부를 제어합니다.", "useIgnoreFilesByDefault": "새 작업 영역에서 검색할 때 기본적으로 .gitignore 파일 및 .ignore 파일을 사용할지 여부를 제어합니다.", "search.quickOpen.includeSymbols": "Quick Open에 대한 파일 결과에 전역 기호 검색 결과를 포함하도록 구성합니다." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/kor/src/vs/workbench/parts/search/browser/searchActions.i18n.json index d8c432f8bb0..ffeb7ea9a94 100644 --- a/i18n/kor/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -19,7 +19,6 @@ "ClearSearchResultsAction.label": "검색 결과 지우기", "FocusNextSearchResult.label": "다음 검색 결과에 포커스", "FocusPreviousSearchResult.label": "이전 검색 결과에 포커스", - "RemoveAction.label": "제거", "file.replaceAll.label": "모두 바꾸기", "match.replace.label": "바꾸기" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/kor/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index b80c311ab32..0bac25f2467 100644 --- a/i18n/kor/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,8 +10,8 @@ "vscode.extension.contributes.snippets": "코드 조각을 적용합니다.", "vscode.extension.contributes.snippets-language": "이 코드 조각이 적용되는 언어 식별자입니다.", "vscode.extension.contributes.snippets-path": "코드 조각 파일의 경로입니다. 이 경로는 확장 폴더의 상대 경로이며 일반적으로 './snippets/'로 시작합니다.", - "badFile": "코드 조각 파일 \"{0}\"을(를) 읽을 수 없습니다.", "badVariableUse": "\"{0}\"-snippet은 snippet-variables 및 snippet-placeholders와 혼동하기 쉽습니다. 자세한 내용은\n https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax를 참조하세요.", + "badFile": "코드 조각 파일 \"{0}\"을(를) 읽을 수 없습니다.", "source.snippet": "사용자 코드 조각", "detail.snippet": "{0}({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 110ad443882..9415bbb9140 100644 --- a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -16,7 +16,6 @@ "workbench.action.terminal.new.short": "새 터미널", "workbench.action.terminal.focus": "터미널에 포커스", "workbench.action.terminal.focusNext": "다음 터미널에 포커스", - "workbench.action.terminal.focusAtIndex": "{0} 터미널로 포커스 이동", "workbench.action.terminal.focusPrevious": "이전 터미널에 포커스", "workbench.action.terminal.paste": "활성 터미널에 붙여넣기", "workbench.action.terminal.DefaultShell": "기본 셸 선택", diff --git a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 9fe74c319a1..08eba97a0dc 100644 --- a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "복사", - "createNewTerminal": "새 터미널", "paste": "붙여넣기", "selectAll": "모두 선택", "clear": "지우기" diff --git a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 81c70b66b79..b21bf5b25fa 100644 --- a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "다시 표시 안 함", "terminal.integrated.chooseWindowsShell": "기본으로 설정할 터미널 셸을 선택하세요. 나중에 설정에서 이 셸을 변경할 수 있습니다.", "terminalService.terminalCloseConfirmationSingular": "활성 터미널 세션이 있습니다. 종료할까요?", - "terminalService.terminalCloseConfirmationPlural": "{0}개의 활성 터미널 세션이 있습니다. 종료할까요?", - "yes": "예" + "terminalService.terminalCloseConfirmationPlural": "{0}개의 활성 터미널 세션이 있습니다. 종료할까요?" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/kor/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..4fdc20a33c2 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "설정을 요약합니다. 이 레이블은 설정 파일에서 구분 주석으로 사용됩니다.", + "vscode.extension.contributes.configuration.properties": "구성 속성에 대한 설명입니다.", + "scope.window.description": "[사용자] 설정 또는 [작업 영역] 설정에서 구성할 수 있는 창 특정 구성입니다.", + "scope.resource.description": "사용자, 작업 영역 또는 폴더 설정에서 구성할 수 있는 리소스 특정 구성", + "scope.description": "구성이 적용되는 범위입니다. 사용 가능 범위는 '창'과 '리소스'입니다.", + "vscode.extension.contributes.configuration": "구성 설정을 적용합니다.", + "invalid.title": "'configuration.title'은 문자열이어야 합니다.", + "vscode.extension.contributes.defaultConfiguration": "언어별로 기본 편집기 구성 설정을 적용합니다.", + "invalid.properties": "'configuration.properties'는 개체여야 합니다.", + "invalid.allOf": "'configuration.allOf'는 사용되지 않으며 더 이상 사용해서는 안됩니다. 대신 여러 구성 섹션을 배열로 'configuration' 기여 지점에 전달하세요.", + "workspaceConfig.folders.description": "작업 영역에 로드되는 폴더 목록입니다.", + "workspaceConfig.path.description": "파일 경로입니다. 예: `/root/folderA` 또는 `./folderA`(작업 영역 파일의 위치를 기준으로 확인할 상대 경로인 경우)", + "workspaceConfig.name.description": "폴더에 대한 선택적 이름입니다." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/kor/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/editor/common/editorService.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. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/kor/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..4bcd1e891d3 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.themes": "Contributes textmate color themes.", + "vscode.extension.contributes.themes.id": "사용자 설정에 사용된 아이콘 테마의 ID입니다.", + "vscode.extension.contributes.themes.label": "UI에 표시되는 색 테마의 레이블입니다.", + "vscode.extension.contributes.themes.uiTheme": "편집기 주변의 색을 정의하는 기본 테마입니다. 'vs'는 밝은색 테마이고, 'vs-dark'는 어두운색 테마입니다. 'hc-black'은 어두운 고대비 테마입니다.", + "vscode.extension.contributes.themes.path": "tmTheme 파일의 경로입니다. 확장 폴더의 상대 경로이며 일반적으로 './themes/themeFile.tmTheme'입니다.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "`contributes.{0}.path`에 문자열이 필요합니다. 제공된 값: {1}", + "invalid.path.1": "확장 폴더({2})에 포함할 `contributes.{0}.path`({1})가 필요합니다. 확장이 이식 불가능해질 수 있습니다." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/kor/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..b0f9faf6b52 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.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. +{ + "error.cannotparseicontheme": "Problems parsing file icons file: {0}" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/kor/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..10f74d38b89 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "사용자 설정에 사용된 아이콘 테마의 ID입니다.", + "vscode.extension.contributes.iconThemes.label": "UI에 표시된 아이콘 테마의 레이블입니다.", + "vscode.extension.contributes.iconThemes.path": "아이콘 테마 정의 파일의 경로입니다. 확장 폴더의 상대 경로이며 일반적으로 './icons/awesome-icon-theme.json'입니다.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "`contributes.{0}.path`에 문자열이 필요합니다. 제공된 값: {1}", + "reqid": "`contributes.{0}.id`에 문자열이 필요합니다. 제공된 값: {1}", + "invalid.path.1": "확장 폴더({2})에 포함할 `contributes.{0}.path`({1})가 필요합니다. 확장이 이식 불가능해질 수 있습니다." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/kor/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index 3f05d41e6bb..c7ed3a3fe46 100644 --- a/i18n/kor/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/kor/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,31 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "사용자 설정에 사용된 아이콘 테마의 ID입니다.", - "vscode.extension.contributes.themes.label": "UI에 표시되는 색 테마의 레이블입니다.", - "vscode.extension.contributes.themes.uiTheme": "편집기 주변의 색을 정의하는 기본 테마입니다. 'vs'는 밝은색 테마이고, 'vs-dark'는 어두운색 테마입니다. 'hc-black'은 어두운 고대비 테마입니다.", - "vscode.extension.contributes.themes.path": "tmTheme 파일의 경로입니다. 확장 폴더의 상대 경로이며 일반적으로 './themes/themeFile.tmTheme'입니다.", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "사용자 설정에 사용된 아이콘 테마의 ID입니다.", - "vscode.extension.contributes.iconThemes.label": "UI에 표시된 아이콘 테마의 레이블입니다.", - "vscode.extension.contributes.iconThemes.path": "아이콘 테마 정의 파일의 경로입니다. 확장 폴더의 상대 경로이며 일반적으로 './icons/awesome-icon-theme.json'입니다.", "migration.completed": "새 테마 설정이 사용자 설정에 추가되었습니다. {0}에서 백업을 사용할 수 있습니다.", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "`contributes.{0}.path`에 문자열이 필요합니다. 제공된 값: {1}", - "invalid.path.1": "확장 폴더({2})에 포함할 `contributes.{0}.path`({1})가 필요합니다. 확장이 이식 불가능해질 수 있습니다.", - "reqid": "`contributes.{0}.id`에 문자열이 필요합니다. 제공된 값: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "워크벤치에서 사용되는 아이콘 테마를 지정합니다. 'null'로 지정하면 파일 아이콘을 표시하지 않습니다.", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "현재 선택한 색 테마에서 색을 재정의합니다.", - "workbenchColors.deprecated": "이 설정은 더 이상 실험적 설정이 아니며 이름이\n 'workbench.colorCustomizations'로 변경되었습니다.", - "workbenchColors.deprecatedDescription": "대신 'workbench.colorCustomizations'를 사용합니다.", "editorColors": "현재 선택된 색 테마에서 편집기 색상과 글꼴 스타일을 재정의합니다.", "editorColors.comments": "주석의 색 및 스타일을 설정합니다.", "editorColors.strings": "문자열 리터럴의 색 및 스타일을 설정합니다.", diff --git a/i18n/kor/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/kor/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..32a5b42e309 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/workspace/node/workspaceEditingService.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. +{ + "openWorkspaceConfigurationFile": "작업 영역 구성 파일 열기", + "close": "닫기" +} \ No newline at end of file diff --git a/i18n/ptb/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/ptb/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index ab0c10765f7..c86627bbf9c 100644 --- a/i18n/ptb/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/ptb/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "por exemplo meuArquivo.txt", - "activeEditorMedium": "e.g. minhaPasta/meuArquivo.txt", - "activeEditorLong": "por exemplo /Usuários/Desenvolvimento/meuProjeto/minhaPasta/meuArquivo/txt", - "rootName": "por exemplo: minhaPasta1, minhaPasta2, minhaPasta3", - "rootPath": "por exemplo /Usuários/desenvolvimento/meuProjeto", - "folderName": "por exemplo: minhaPasta", - "folderPath": "por exemplo, /Users/Development/myFolder", + "activeEditorShort": "o nome do arquivo (por exemplo, MyFile. txt)", + "activeEditorMedium": "o caminho do arquivo relativo à pasta de trabalho (por exemplo, myFolder/myFile.txt)", + "activeEditorLong": "o caminho completo do arquivo (por exemplo, /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "nome da área de trabalho (por exemplo, minhaPasta ou minhaAreadeTrabalho)", + "rootPath": "caminho do arquivo da área de trabalho (por exemplo, /Usuarios/Desenvolvimento/minhaAreadeTrabalho)", + "folderName": "nome do diretório da área de trabalho onde arquivo está localizado (por exemplo, myFolder)", + "folderPath": "caminho do arquivo no diretório da área de trabalho onde o arquivo está localizado (por exemplo, /Users/Development/myFolder)", "appName": "e.g. VS Code", "dirty": "Um indicador de alteração se o editor ativo foi alterado", "separator": "um separador condicional (' - ') que somente é mostrado quando envolvido por variáveis com valores", diff --git a/i18n/ptb/extensions/emmet/package.i18n.json b/i18n/ptb/extensions/emmet/package.i18n.json index 07589c8fc9d..582e68c8fa1 100644 --- a/i18n/ptb/extensions/emmet/package.i18n.json +++ b/i18n/ptb/extensions/emmet/package.i18n.json @@ -28,13 +28,6 @@ "command.incrementNumberByTen": "Incremento de 10", "command.decrementNumberByTen": "Decrementar por 10", "emmetSyntaxProfiles": "Definir o perfil para a sintaxe especificada ou usar seu próprio perfil com regras específicas.", - "emmetExclude": "Uma matriz de línguagens onde abreviaturas emmet não devem ser expandidas.", - "emmetExtensionsPath": "Caminho para uma pasta que contém os perfis de emmet e trechos de código.'", - "emmetShowExpandedAbbreviation": "Mostra abreviaturas emmet expandidas como sugestões.\nA opção \"inMarkupAndStylesheetFilesOnly\" aplica-se a html, haml, jade, slim, xml, xsl, css, scss, sass, less e stylus.\nA opção \"always\" se aplica a todas as partes do arquivo independentemente de marcação/css.", - "emmetShowAbbreviationSuggestions": "Mostra possíveis abreviaturas emmet como sugestões. Não aplicável em folhas de estilo ou quando emmet.showExpandedAbbreviation é definido como \"nunca\".", - "emmetIncludeLanguages": "Habilita as abreviaturas do emmet em idiomas que não são suportados por padrão. Adicione um mapeamento aqui entre a linguagem e a linguagem emmet suportada.\n Por exemplo: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", - "emmetVariables": "Variáveis a serem usadas em trechos de código emmet", - "emmetTriggerExpansionOnTab": "Quando habilitado, abreviações emmet são expandidas ao pressionar TAB.", "emmetPreferences": "Preferências usadas para modificar o comportamento de algumas ações e resolvedores de Emmet.", "emmetPreferencesIntUnit": "Unidade padrão para valores inteiros", "emmetPreferencesFloatUnit": "Unidade padrão para valores float", @@ -44,5 +37,7 @@ "emmetPreferencesCssBetween": "Símbolo a ser colocado entre a propriedade CSS e o valor quando expandir abreviaturas CSS", "emmetPreferencesSassBetween": "Símbolo a ser colocado entre a propriedade CSS e o valor quando expandir abreviaturas CSS em arquivos Sass", "emmetPreferencesStylusBetween": "Símbolo a ser colocado entre a propriedade CSS e o valor quando expandir abreviaturas CSS em arquivos Stylus", - "emmetShowSuggestionsAsSnippets": "Se verdadeiro, então as sugestões emmet aparecerão como trechos, permitindo você requisitá-los conforme a configuração de editor.snippetSuggestions." + "emmetPreferencesFilterCommentBefore": "Uma definição de comentário que deve ser colocado antes de elemento correspondente quando um filtro de comentário é aplicado.", + "emmetPreferencesFilterCommentAfter": "Uma definição de comentário que deve ser colocado após o elemento correspondente quando um filtro de comentário é aplicado.", + "emmetPreferencesFilterCommentTrigger": "Uma lista separada por vírgulas de nomes de atributo que deve existir em abreviações para o filtro de comentário a ser aplicado" } \ No newline at end of file diff --git a/i18n/ptb/extensions/git/out/commands.i18n.json b/i18n/ptb/extensions/git/out/commands.i18n.json index 4c72afe876f..d3e314a0e15 100644 --- a/i18n/ptb/extensions/git/out/commands.i18n.json +++ b/i18n/ptb/extensions/git/out/commands.i18n.json @@ -12,8 +12,9 @@ "cloning": "Clonando repositório do Git...", "openrepo": "Abrir Repositório", "proposeopen": "Gostaria de abrir o repositório clonado?", - "path to init": "Caminho da pasta", - "provide path": "Por favor, forneça um caminho de pasta para inicializar um repositório Git", + "init repo": "Inicializar Repositório", + "create repo": "Inicializar Repositório", + "are you sure": "Isto irá criar um repositório Git em '{0}'. Tem certeza que deseja continuar?", "HEAD not available": "Versão HEAD de '{0}' não está disponível.", "confirm stage files with merge conflicts": "Tem certeza que deseja processar {0} arquivos com conflitos de mesclagem?", "confirm stage file with merge conflicts": "Tem certeza que deseja processar {0} com conflitos de mesclagem?", diff --git a/i18n/ptb/extensions/git/out/repository.i18n.json b/i18n/ptb/extensions/git/out/repository.i18n.json index d9855ba9df2..6c47d5f327f 100644 --- a/i18n/ptb/extensions/git/out/repository.i18n.json +++ b/i18n/ptb/extensions/git/out/repository.i18n.json @@ -21,6 +21,8 @@ "deleted by us": "Excluído por nós", "both added": "Ambos adicionados", "both modified": "Ambos modificados", + "untracked, short": "U", + "modified, short": "M", "commit": "Confirmar", "merge changes": "Mesclar Alterações", "staged changes": "Alterações em Etapas", diff --git a/i18n/ptb/extensions/git/package.i18n.json b/i18n/ptb/extensions/git/package.i18n.json index f45cd09fb8b..8ca31f76ec1 100644 --- a/i18n/ptb/extensions/git/package.i18n.json +++ b/i18n/ptb/extensions/git/package.i18n.json @@ -15,6 +15,8 @@ "command.stageAll": "Estagiar Todas Alterações", "command.stageSelectedRanges": "Estagiar Faixas Selecionadas", "command.revertSelectedRanges": "Reverter Faixas Selecionadas", + "command.stageChange": "Mudança de fase", + "command.revertChange": "Reverter a alteração", "command.unstage": "Desestagiar Alterações", "command.unstageAll": "Desestagiar Todas Alterações", "command.unstageSelectedRanges": "Desestagiar Faixas Selecionadas", diff --git a/i18n/ptb/extensions/typescript/package.i18n.json b/i18n/ptb/extensions/typescript/package.i18n.json index 8b7415813f2..4bc0448e7a9 100644 --- a/i18n/ptb/extensions/typescript/package.i18n.json +++ b/i18n/ptb/extensions/typescript/package.i18n.json @@ -44,7 +44,8 @@ "typescript.npm": "Especifica o caminho para o executável do NPM usado para Aquisição de Tipo Automático. Requer TypeScript > = 2.3.4.", "typescript.check.npmIsInstalled": "Verificar se o NPM está instalado para aquisição automática de tipo.", "javascript.nameSuggestions": "Habilitar/desabilitar incluindo nomes exclusivos do arquivo nas listas de sugestão de JavaScript.", - "typescript.tsc.autoDetect": "Controla se a auto-detecção de tarefas tsc estão ligadas ou desligadas.", + "typescript.tsc.autoDetect": "Controla a auto deteção das tarefas de tsc. 'off' desativa esse recurso. 'build' só cria tarefas de compilação de execução única. 'watch' cria apenas tarefas de compilação e monitoramento. 'on' cria ambas as tarefas de compilar e monitoramento. Padrão é 'on'.", "typescript.problemMatchers.tsc.label": "Problemas TypeScript", - "typescript.problemMatchers.tscWatch.label": "Problemas TypeScript (modo observação)" + "typescript.problemMatchers.tscWatch.label": "Problemas TypeScript (modo observação)", + "typescript.quickSuggestionsForPaths": "Ativar/desativar sugestões rápidas quando estiver digitando um caminho de importação." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/ptb/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 473543c0850..fcd5681301a 100644 --- a/i18n/ptb/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/ptb/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,6 @@ "label.replaceButton": "Substituir", "label.replaceAllButton": "Substituir Tudo", "label.toggleReplaceButton": "Ativar/desativar modo Substituir", - "title.matchesCountLimit": "Somente os primeiros 999 resultados são realçados, mas todas as operações de pesquisa funcionam em todo o texto.", "label.matchesLocation": "{0} de {1}", "label.noResults": "Nenhum resultado" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/ptb/src/vs/editor/contrib/find/common/findController.i18n.json index 93f4b43b45c..ce656c20f36 100644 --- a/i18n/ptb/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/ptb/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "Localizar Próxima Seleção", "previousSelectionMatchFindAction": "Localizar Seleção Anterior", "startReplace": "Substituir", - "addSelectionToNextFindMatch": "Adicionar Seleção ao Próximo Localizar Correspondência", - "addSelectionToPreviousFindMatch": "Adicionar Seleção à Correspondência de Localização Anterior", - "moveSelectionToNextFindMatch": "Mover Última Seleção para Próximo Localizar Correspondência", - "moveSelectionToPreviousFindMatch": "Mover Última Seleção para Correspondência de Localização Anterior", - "selectAllOccurrencesOfFindMatch": "Selecionar Todas as Ocorrências de Localizar Correspondência", - "changeAll.label": "Alterar todas as ocorrências", "showNextFindTermAction": "Mostrar Próximo Termo de Busca", "showPreviousFindTermAction": "Mostrar Termo de Busca Anterior" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/ptb/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 583be5b3e5c..790c737c8eb 100644 --- a/i18n/ptb/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/ptb/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Inserir cursor acima", "mutlicursor.insertBelow": "Inserir cursor abaixo", - "mutlicursor.insertAtEndOfEachLineSelected": "Adicionar Cursores ao Final das Linhas" + "mutlicursor.insertAtEndOfEachLineSelected": "Adicionar Cursores ao Final das Linhas", + "addSelectionToNextFindMatch": "Adicionar Seleção ao Próximo Localizar Correspondência", + "addSelectionToPreviousFindMatch": "Adicionar Seleção à Correspondência de Localização Anterior", + "moveSelectionToNextFindMatch": "Mover Última Seleção para Próximo Localizar Correspondência", + "moveSelectionToPreviousFindMatch": "Mover Última Seleção para Correspondência de Localização Anterior", + "selectAllOccurrencesOfFindMatch": "Selecionar Todas as Ocorrências de Localizar Correspondência", + "changeAll.label": "Alterar todas as ocorrências" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/ptb/src/vs/platform/theme/common/colorRegistry.i18n.json index 2c5e3a22276..a6b7b377cac 100644 --- a/i18n/ptb/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/ptb/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "Formato inválido de cor. Use #RGB, #RGBA, #RRGGBB ou #RRGGBBAA", "schema.colors": "Cores usadas no workbench.", "foreground": "Cor de primeiro plano geral. Essa cor é só usada se não for substituída por um componente.", "errorForeground": "Cor de primeiro plano geral para mensagens de erro. Essa cor é só usada se não for substituída por um componente.", diff --git a/i18n/ptb/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/ptb/src/vs/workbench/browser/actions/workspaceActions.i18n.json index f9516787ac6..5a005571d2b 100644 --- a/i18n/ptb/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -9,14 +9,17 @@ "addFolderToWorkspace": "Adicionar pasta ao espaço de trabalho...", "add": "&& Adicionar", "addFolderToWorkspaceTitle": "Adicionar pasta ao espaço de trabalho", + "globalRemoveFolderFromWorkspace": "Remover pasta da área de trabalho", "newWorkspace": "Novo espaço de trabalho...", "select": "&&Selecionar", "selectWorkspace": "Selecionar pastas para espaço de trabalho", "removeFolderFromWorkspace": "Remover pasta da área de trabalho", + "openFolderSettings": "Abrir configurações da pasta", "saveWorkspaceAsAction": "Salvar o espaço de trabalho como...", "save": "&&Salvar", "saveWorkspace": "Salvar o espaço de trabalho", "openWorkspaceAction": "Abrir o Espaço de Trabalho...", "openWorkspaceConfigFile": "Abrir o Arquivo de Configuração do Espaço de Trabalho", + "openFolderAsWorkspaceInNewWindow": "Abrir a pasta como espaço de trabalho em nova janela", "workspaceFolderPickerPlaceholder": "Selecione a pasta de trabalho" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index 577ad33d0b4..f42981ec157 100644 --- a/i18n/ptb/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Ocultar a Barra de Atividades", - "activityBarAriaLabel": "Chave do Modo de exibição Ativo", "globalActions": "Ações globais" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..4a4304f83f0 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/browser/parts/compositebar/compositeBar.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. +{ + "activityBarAriaLabel": "Chave do Modo de exibição Ativo" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..ab4fa3904b3 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/browser/parts/compositebar/compositeBarActions.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. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "Visualizações Adicionais", + "numberBadge": "{0} ({1})", + "manageExtension": "Gerenciar Extensão", + "titleKeybinding": "{0} ({1})", + "hide": "Ocultar", + "toggle": "Alternar Visualização Fixa" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index e318ceb9434..d1d8a425227 100644 --- a/i18n/ptb/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "Mostrar editores no segundo grupo", "groupThreePicker": "Mostrar editores no terceiro grupo", "allEditorsPicker": "Mostrar todos editores abertos", - "view": "Exibir" + "view": "Exibir", + "file": "Arquivo" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 4a2adabf5a6..b997093f4f8 100644 --- a/i18n/ptb/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "O comando '{0}' não está habilitado e não pode ser executado.", "manageExtension": "Gerenciar Extensão" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/ptb/src/vs/workbench/electron-browser/main.contribution.i18n.json index 4f521d06910..8f50f5262de 100644 --- a/i18n/ptb/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,18 +10,15 @@ "workspaces": "Espaços de trabalho", "developer": "Desenvolvedor", "showEditorTabs": "Controla se os editores abertos devem ou não serem exibidos em abas.", - "workbench.editor.labelFormat.default": "Mostrar o nome do arquivo. Quando as abas estão habilitadas e dois arquivos têm o mesmo nome em um grupo são adicionadas as seções de diferenciação do caminho de cada arquivo. Quando as abas estão desativadas, o caminho relativo para a raiz do espaço de trabalho é mostrado se o editor está ativo.", "workbench.editor.labelFormat.short": "Mostrar o nome do arquivo seguido pelo nome do diretório.", - "workbench.editor.labelFormat.medium": "Mostrar o nome do arquivo seguido pelo seu caminho relativo à raiz do espaço de trabalho.", "workbench.editor.labelFormat.long": "Mostrar o nome do arquivo seguido pelo seu caminho absoluto.", "tabDescription": "Controla o formato do rótulo para um editor. Alterar essa configuração pode por exemplo tornar mais fácil entender a localização de um arquivo:\n- curto: 'parent'\n- médio: 'workspace/src/parent'\n- longa: '/ home/user/workspace/src/parent'\n- padrão: '... /parent, quando outra guia compartilha o mesmo título, ou o caminho relativo do espaço de trabalho se as guias estão desabilitadas", "editorTabCloseButton": "Controla a posição dos botões de fechar das abas do editor ou os desabilita quando configurados para 'desligado'.", "showIcons": "Controla se os editores abertos devem ou não ser exibidos com um ícone. Requer um tema de ícone para ser habilitado. ", "enablePreview": "Controla se editores abertos mostram uma visualização. Editores de visualização são reutilizados até que eles sejam mantidos (por exemplo, através do duplo clique ou edição) e aparecerem com um estilo de fonte em itálico.", "enablePreviewFromQuickOpen": "Controla se os editores abertos da Abertura Rápida são exibidos como visualização. Os editores de visualização são reutilizados até serem preservados (por exemplo, através de um duplo clique ou edição).", - "editorOpenPositioning": "Controla onde os editores serão abertos. Escolha 'esquerda' ou 'direita' para abrir os editores à esquerda ou à direita do \neditor ativo. Selecione 'primeiro' ou 'último' para abrir os editores independentemente do atual.", "revealIfOpen": "Controla se um editor é exibido em qualquer um dos grupos, se aberto. Se desabilitado, um editor será aberto preferencialmente no grupo de editores ativo. Se habilitado, um editor já aberto será exibido no grupo de editores ativo, ao invés de ser aberto novamente. Note que há alguns casos onde esta configuração é ignorada, por exemplo, quando for forçada a abertura de um editor em um grupo específico ou ao lado do grupo atualmente ativo.", - "commandHistory": "Controla o número de comandos recentemente usados mantidos no histórico para a paleta de comandos. Definir como 0 para desativar o histórico de comandos.", + "commandHistory": "Controla o número de comandos usados recentemente a serem mantidos no histórico da paleta de comando. Definir como 0 para desativar o histórico de comandos.", "preserveInput": "Controla se a última entrada digitada na paleta de comandos deve ser restaurada ao abri-la da próxima vez.", "closeOnFocusLost": "Controla se Abertura Rápida deve fechar automaticamente caso perca o foco.", "openDefaultSettings": "Controla se a abertura de configurações também abre um editor mostrando todas as configurações padrão.", @@ -50,7 +47,7 @@ "restoreWindows": "Controla como as janelas serão reabertas após uma reinicialização. Selecione 'nenhum' para sempre iniciar com uma área de trabalho vazia, 'um' para reabrir a última janela que você trabalhou, 'pastas' para reabrir todas as janelas que tinham pastas abertas ou 'todos' para reabrir todas as janelas da sua última sessão.", "restoreFullscreen": "Controla se uma janela deve ser restaurada em modo de tela cheia se ela foi finalizada em modo de tela cheia.", "zoomLevel": "Ajusta o nível de zoom da janela. O tamanho original é 0 e cada aumento (por exemplo, 1) ou redução (por exemplo, -1) representa um zoom 20% maior ou menor. Você também pode digitar decimais para ajustar o nível de zoom com uma granularidade mais fina.", - "title": "Controla o título de janela baseado no editor do ativo. Variáveis são substituídas com base no contexto:\n${activeEditorShort}: por exemplo, MyFile.txt \n${activeEditorMedium}: por exemplo, myFolder/myFile.txt \n${activeEditorLong}: por exemplo, /Users/Development/myProject/myFolder/myFile.txt \n${folderName}: por exemplo myFolder \n${folderPath}: por exemplo, /Users/Development/myFolder \n${rootName}: por exemplo, myFolder1, myFolder2, myFolder3 \n${rootPath}: por exemplo, /Users/Development/myWorkspace \n${appName}: por exemplo, VS Code \n${dirty}: um indicador que mostra se o editor ativo está modificado\n${separator}: um separador condicional (\"-\") que é mostrado apenas quando cercado por variáveis com valores", + "title": "Controla o título de janela baseado no editor ativo. Variáveis são substituídas com base no contexto: \n${activeEditorShort}: o nome do arquivo (por exemplo, MyFile txt)\n${activeEditorMedium}: o caminho do arquivo relativo à pasta da área de trabalho (por exemplo, myFolder/myFile.txt) \n${activeEditorLong}: o caminho completo do arquivo (por exemplo, /Users/Development/myProject/myFolder/myFile.txt) \n${folderName}: nome da pasta de trabalho em que o arquivo está contido (por exemplo, myFolder) \n${folderPath}: caminho do arquivo da pasta de trabalho em que o arquivo está contido (por exemplo, /Users/Development/myFolder) {\n$(rootName}: nome do espaço de trabalho (por exemplo, myFolder ou myWorkspace)\n${rootPath}: caminho do espaço de trabalho (por exemplo, /Users/Development/myWorkspace) \n${appName}: por exemplo, VS Code\n${dirty}: um indicador se o editor ativo foi modificado\n${separator}: um separador condicional (\"-\") que é mostrado apenas quando cercado por variáveis com valores", "window.newWindowDimensions.default": "Abrir novas janelas no centro da tela.", "window.newWindowDimensions.inherit": "Abrir novas janelas com a mesma dimensão da última janela ativa.", "window.newWindowDimensions.maximized": "Abrir novas janelas maximizadas.", diff --git a/i18n/ptb/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/ptb/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 01955c44965..dd268ebad23 100644 --- a/i18n/ptb/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,7 @@ { "entryAriaLabel": "depurar {0}", "debugAriaLabel": "Digite um nome de uma configuração de lançamento para ser executado.", + "addConfiguration": "Adicionar Configuração...", "noConfigurationsMatching": "Não há configurações de depuração correspondentes", "noConfigurationsFound": "Configurações de depuração não encontradas. Por favor, crie um arquivo 'launch.json'." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/ptb/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..7a6db36a29e --- /dev/null +++ b/i18n/ptb/src/vs/workbench/parts/debug/browser/debugStatus.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. +{ + "debug": "Depurar" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/ptb/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..86ae4403f16 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/parts/debug/browser/debugViewlet.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. +{ + "debugFocusVariablesView": "Foco em Variáveis", + "debugFocusWatchView": "Foco em Monitoramento", + "debugFocusCallStackView": "Foco em Pilha de Chamadas", + "debugFocusBreakpointsView": "Foco em Pontos de Interrupção" +} \ 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 05e76d32185..3908acc5028 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 @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "Configurações para gerar o 'launch.json' inicial.", "vscode.extension.contributes.debuggers.languages": "Lista de idiomas para os quais a extensão de depuração pode ser considerada o \"depurador padrão\".", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Se especificado VS Code chamará este comando para determinar o caminho do executável do adaptador de depuração e os argumentos para passar.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Se especificado VS Code chamará este comando para as ações de \"depurar\" ou \"executar\" direcionadas para esta extensão.", "vscode.extension.contributes.debuggers.configurationSnippets": "Trechos de código para adicionar novas configurações em 'launch.json'.", "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.", diff --git a/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index aaf52e5dedb..5e4eb26c208 100644 --- a/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,10 +12,10 @@ "breakpointRemoved": "Ponto de interrupção removido, linha {0}, arquivo {1}", "compoundMustHaveConfigurations": "Composição deve ter o atributo \"configurations\" definido para iniciar várias configurações.", "configMissing": "Configuração '{0}' não tem 'launch.json'.", - "debugRequestNotSupported": "Configuração de depuração escolhido possui um valor de atributo não suportado '{0}': '{1}'.", - "debugRequesMissing": "Atributo '{0}' está faltando para a configuração de depuração escolhida.", + "debugRequestNotSupported": "Atributo '{0}' tem um valor sem suporte '{1}' na configuração de depuração escolhida.", + "debugRequesMissing": "Atributo '{0}' está faltando na configuração de depuração escolhida.", "debugTypeNotSupported": "Tipo de depuração configurado '{0}' não é suportado.", - "debugTypeMissing": "Falta a propriedade 'type' para a configuração de lançamento escolhida.", + "debugTypeMissing": "Falta a propriedade 'tipo' para a configuração de lançamento escolhida.", "preLaunchTaskErrors": "Erros de build foram detectados durante a preLaunchTask '{0}'.", "preLaunchTaskError": "Erro de build foi detectado durante a preLaunchTask '{0}'.", "preLaunchTaskExitCode": "A preLaunchTask '{0}' encerrada com código de saída {1}.", diff --git a/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 4afd6d64d82..5f2a144a70e 100644 --- a/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -8,5 +8,5 @@ "replVariableAriaLabel": "Variável {0} tem valor {1}, ler a impressão do valor do loop, depurar", "replExpressionAriaLabel": "Expressão {0} tem valor {1}, ler o laço de avaliação de impressão, depurar", "replValueOutputAriaLabel": " impressão da avaliação do laço de leitura, depurar", - "replKeyValueOutputAriaLabel": "Variável de saída {0} tem valor {1}, ler o loop de avaliação de impressão, depurar" + "replRawObjectAriaLabel": "Variável repl {0} tem valor {1}, ler o loop de avaliação de impressão e depuração" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index 39deecf379b..464da97e4e9 100644 --- a/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "Arquivos", + "filesCategory": "Arquivo", "revealInSideBar": "Revelar na Barra Lateral", "acceptLocalChanges": "Usar suas alterações e substituir o conteúdo do disco", "revertLocalChanges": "Descartar as alterações e reverter para o conteúdo no disco" diff --git a/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 99af18bd13e..674a4dedbf2 100644 --- a/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "Tem certeza de que deseja excluir '{0}'?", "undoBin": "Você pode restaurar da lixeira.", "undoTrash": "Você pode restaurar a partir do lixo.", + "doNotAskAgain": "Não me pergunte novamente", "confirmDeleteMessageFolder": "Tem certeza de que deseja excluir permanentemente '{0}' e seu conteúdo?", "confirmDeleteMessageFile": "Tem certeza de que deseja excluir permanentemente '{0}'?", "irreversible": "Esta ação é irreversível!", @@ -37,8 +38,6 @@ "openToSide": "Aberto para o lado", "compareSource": "Selecione para comparar", "globalCompareFile": "Compare o Arquivo Ativo Com...", - "pickHistory": "Selecione um arquivo previamente aberto para comparar com", - "unableToFileToCompare": "O arquivo selecionado não pode ser comparado com '{0}'.", "openFileToCompare": "Abrir um arquivo primeiro para compará-lo com outro arquivo.", "compareWith": "Comparar '{0}' com '{1}'", "compareFiles": "Comparar Arquivos", @@ -47,7 +46,7 @@ "saveAs": "Salvar como...", "saveAll": "Salvar Todos", "saveAllInGroup": "Salvar Todos no Grupo", - "saveFiles": "Salvar Arquivos Sujos", + "saveFiles": "Salvar todos os arquivos", "revert": "Reverter Arquivo", "focusOpenEditors": "Foco na Visualização dos Editores Abertos", "focusFilesExplorer": "Foco no Explorador de Arquivos", diff --git a/i18n/ptb/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 8100b458672..0e95d226253 100644 --- a/i18n/ptb/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -40,10 +40,14 @@ "dynamicHeight": "Controla se a altura da seção de editores abertos deve adaptar-se dinamicamente para o número de elementos ou não.", "autoReveal": "Controla se o explorador deve automaticamente revelar e selecionar arquivos ao abri-los.", "enableDragAndDrop": "Controla se o explorador deve permitir mover arquivos e pastas através de arrastar e soltar.", + "confirmDragAndDrop": "Controla se o explorer deve pedir a confirmação ao mover arquivos ou pastas através de arrastar e soltar.", + "confirmDelete": "Controla se o explorador deve pedir a confirmação ao excluir um arquivo por meio do lixo.", "sortOrder.default": "Arquivos e pastas são classificadas por seus nomes, em ordem alfabética. Pastas são exibidas acima dos arquivos.", "sortOrder.mixed": "Arquivos e pastas são classificadas por seus nomes, em ordem alfabética. Arquivos são misturados com pastas.", "sortOrder.filesFirst": "Arquivos e pastas são classificadas por seus nomes, em ordem alfabética. Os arquivos são exibidos acima das pastas.", "sortOrder.type": "Arquivos e pastas são classificadas de acordo com suas extensões, em ordem alfabética. Pastas são exibidas acima dos arquivos.", "sortOrder.modified": "Arquivos e pastas são classificados de acordo com a data da última modificação, em ordem decrescente. Pastas são exibidas acima dos arquivos.", - "sortOrder": "Controla a ordem de classificação dos arquivos e pastas no explorador. Além da classificação padrão, você pode definir a ordem para 'mixed' (arquivos e pastas misturados), 'type' (por tipo de arquivo), 'modified' (pela data da última modificação) ou 'filesFirst' (exibe os arquivos acima das pastas)." + "sortOrder": "Controla a ordem de classificação dos arquivos e pastas no explorador. Além da classificação padrão, você pode definir a ordem para 'mixed' (arquivos e pastas misturados), 'type' (por tipo de arquivo), 'modified' (pela data da última modificação) ou 'filesFirst' (exibe os arquivos acima das pastas).", + "explorer.decorations.colors": "Controles se as decorações de arquivo devem usar cores.", + "explorer.decorations.badges": "Controles se as decorações de arquivo devem usar identificações." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/ptb/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 38f98ed9420..69f48bde47d 100644 --- a/i18n/ptb/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "Nenhuma Pasta Aberta", "explorerSection": "Seção de Explorador de Arquivos", - "noWorkspaceHelp": "Você ainda não abriu uma pasta.", + "noWorkspaceHelp": "Você ainda não adicionou uma pasta no espaço de trabalho.", + "addFolder": "Adicionar pasta", + "noFolderHelp": "Você ainda não abriu uma pasta.", "openFolder": "Abrir Pasta" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/ptb/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index d321f8c15ce..f5321d10375 100644 --- a/i18n/ptb/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -4,12 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "canNotResolve": "Não pode resolver a pasta {0}", "fileInputAriaLabel": "Digite o Nome do arquivo. Pressione Enter para confirmar ou Escape para cancelar.", "filesExplorerViewerAriaLabel": "{0}, Explorador de Arquivos", "dropFolders": "Você quer adicionar as pastas no espaço de trabalho?", "dropFolder": "Você quer adicionar a pasta no espaço de trabalho?", "addFolders": "&& Adicionar pastas", "addFolder": "&& Adicionar pasta", + "confirmMove": "Tem certeza que deseja mover '{0}'?", + "doNotAskAgain": "Não me pergunte novamente", "confirmOverwriteMessage": "'{0}' já existe na pasta de destino. Deseja substituí-lo?", "irreversible": "Esta ação é irreversível!", "replaceButtonLabel": "&&Substituir" diff --git a/i18n/ptb/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/ptb/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..62c14983ac7 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/parts/markers/browser/markersFileDecorations.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. +{ + "label": "Problemas", + "tooltip.1": "1 problema neste arquivo", + "tooltip.N": "{0} problemas neste arquivo", + "markers.showOnFile": "Mostre erros e avisos no arquivos e pasta." +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index 1b5d84180e9..10a0c7ab0f2 100644 --- a/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "Coloque as suas configurações aqui para substituir as configurações padrão.", - "errorInvalidConfiguration": "Não é possível gravar em configurações. Corrija erros/avisos no arquivo e tente novamente.", "emptyWorkspaceSettingsHeader": "Coloque as suas configurações aqui para substituir as configurações de usuário.", "emptyFolderSettingsHeader": "Coloque as suas configurações de pasta aqui para substituir aqueles das configurações do espaço de trabalho.", "defaultFolderSettingsTitle": "Configurações de pasta padrão", diff --git a/i18n/ptb/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/ptb/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index b6d5cdbd2e5..e45b8e421e8 100644 --- a/i18n/ptb/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "O comando '{0}' não está habilitado no contexto atual.", "recentlyUsed": "usados recentemente", "morecCommands": "outros comandos", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "Não há comandos correspondentes" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index f9640a94d5a..2ab571fe333 100644 --- a/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,6 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "{0} de {1} mudanças", + "change": "{0} de {1} mudança", + "show previous change": "Mostrar a Alteração Anterior", + "show next change": "Mostrar a Próxima Alteração", "editorGutterModifiedBackground": "Cor de fundo da dobra do editor para as linhas que estão modificadas.", "editorGutterAddedBackground": "Cor de fundo da dobra do editor para as linhas que estão adicionadas.", "editorGutterDeletedBackground": "Cor de fundo da dobra do editor para as linhas que estão excluídas.", diff --git a/i18n/ptb/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index 6e7cef32f55..477df0fd694 100644 --- a/i18n/ptb/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -17,7 +17,7 @@ "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.", "exclude.when": "Verificação adicional nos irmãos de um arquivo correspondente. Use $(basename) como variável para o nome do arquivo correspondente.", - "useRipgrep": "Controla se deve utilizar ripgrep na pesquisa de texto", + "useRipgrep": "Controla se utiliza ripgrep em buscas de texto e de arquivo", "useIgnoreFilesByDefault": "Controla se deve utilizar arquivos .gitignore e .ignore por padrão ao fazer pesquisas em um novo espaço de trabalho.", "search.quickOpen.includeSymbols": "Configurar para incluir resultados de uma pesquisa símbolo global nos resultados do arquivo para Abertura Rápida." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/ptb/src/vs/workbench/parts/search/browser/searchActions.i18n.json index cd879d71747..933840a7fc3 100644 --- a/i18n/ptb/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -19,7 +19,6 @@ "ClearSearchResultsAction.label": "Limpar os Resultados da Pesquisa", "FocusNextSearchResult.label": "Focalizar o Próximo Resultado da Pesquisa", "FocusPreviousSearchResult.label": "Focalizar o Resultado da Pesquisa Anterior", - "RemoveAction.label": "Remover", "file.replaceAll.label": "Substituir Tudo", "match.replace.label": "Substituir" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/ptb/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index d1afc5ef25a..61f582e57b8 100644 --- a/i18n/ptb/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,8 +10,8 @@ "vscode.extension.contributes.snippets": "Contribui aos trechos de código.", "vscode.extension.contributes.snippets-language": "Identificador de linguagem para o qual este trecho de código contribui.", "vscode.extension.contributes.snippets-path": "Caminho do arquivo de trechos de código. O caminho é relativo à pasta de extensão e normalmente começa com '. /snippets/'.", - "badFile": "O arquivo de trechos \"{0}\" não pôde ser lido.", "badVariableUse": "O trecho de código \"{0}\" muito provavelmente confunde as variáveis de trecho de código e espaços reservados do trecho de código. Consulte https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax para obter mais detalhes.", + "badFile": "O arquivo de trechos \"{0}\" não pôde ser lido.", "source.snippet": "Trecho de código do usuário", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 526a6233a3d..7841731c435 100644 --- a/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -14,6 +14,7 @@ "runningTasks": "Mostrar tarefas em execução", "tasks": "Tarefas", "TaskSystem.noHotSwap": "Alterar o mecanismo de execução da tarefa com uma tarefa ativa executando exige que a janela seja recarregada", + "TaskServer.folderIgnored": "A pasta {0} é ignorada desde que use a versão de tarefas 0.1.0", "TaskService.noBuildTask1": "Nenhuma tarefa de compilação definida. Marque uma tarefa com 'isBuildCommand' no arquivo tasks.json.", "TaskService.noBuildTask2": "Nenhuma tarefa de compilação definida. Marque uma tarefa como um grupo 'build' no arquivo tasks.json.", "TaskService.noTestTask1": "Nenhuma tarefa de teste definida. Marque uma tarefa com 'isTestCommand' no arquivo tasks.json.", @@ -30,6 +31,7 @@ "TaskSystem.activeSame.noBackground": "A tarefa '{0}' já está ativa. Para finalizá-la use 'Finalizar Tarefa' no menu Tarefas.", "TaskSystem.active": "Já existe uma tarefa sendo executada. Finalize-a antes de executar outra tarefa.", "TaskSystem.restartFailed": "Falha ao finalizar e reiniciar a tarefa {0}", + "TaskService.noConfiguration": "Erro: A deteção de tarefa {0} não contribuiu para uma tarefa para a seguinte configuração: {1} a tarefa será ignorada.\n", "TaskSystem.configurationErrors": "Erro: A configuração da tarefa informada possui erros de validação e não pode ser utilizada. Por favor, corrija os erros primeiro.", "taskService.ignoreingFolder": "Ignorar as configurações de tarefa para a pasta de trabalho {0}. Suporte a tarefas de espaço de trabalho de múltiplas pastas requer que todas as pastas usem a versão de tarefas 2.0.0\n", "TaskSystem.invalidTaskJson": "Erro: O conteúdo do arquivo tasks.json possui erros de sintaxe. Por favor, corrija-os antes de executar uma tarefa.\n", diff --git a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index b075d6f0b92..f4a78b8d461 100644 --- a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -17,6 +17,7 @@ "terminal.integrated.fontFamily": "Controla a família de fontes do terminal, este padrão é o valor do editor.fontFamily.", "terminal.integrated.fontSize": "Controla o tamanho da fonte em pixels do terminal.", "terminal.integrated.lineHeight": "Controles a altura da linha do terminal, este número é multiplicada pelo tamanho da fonte terminal para obter a altura real da linha em pixels.", + "terminal.integrated.enableBold": "Se deseja habilitar o texto em negrito dentro do terminal, note que isso requer o apoio do shell do terminal.", "terminal.integrated.cursorBlinking": "Controla se o cursor do terminal pisca.", "terminal.integrated.cursorStyle": "Controla o estilo do cursor do terminal.", "terminal.integrated.scrollback": "Controla a quantidade máxima de linhas que o terminal mantém em seu buffer.", diff --git a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 7379c161275..2ee45b6deb3 100644 --- a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -16,7 +16,6 @@ "workbench.action.terminal.new.short": "Novo Terminal", "workbench.action.terminal.focus": "Focalizar Terminal", "workbench.action.terminal.focusNext": "Focalizar Próximo Terminal", - "workbench.action.terminal.focusAtIndex": "Focalizar Terminal {0}", "workbench.action.terminal.focusPrevious": "Focalizar Terminal Anterior", "workbench.action.terminal.paste": "Colar no Terminal Ativo", "workbench.action.terminal.DefaultShell": "Selecionar Shell Padrão", diff --git a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 2bbfefe2297..ef05288e718 100644 --- a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Copiar", - "createNewTerminal": "Novo Terminal", "paste": "Colar", "selectAll": "Selecionar Tudo", "clear": "Limpar" diff --git a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 08ec4bd9777..83214ad4be8 100644 --- a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "Ok, Nunca Mostrar Novamente", "terminal.integrated.chooseWindowsShell": "Selecione o seu terminal shell preferido, você pode alterar isso mais tarde em suas configurações", "terminalService.terminalCloseConfirmationSingular": "Há uma sessão ativa de terminal, você quer finalizá-la?", - "terminalService.terminalCloseConfirmationPlural": "Existem {0} sessões ativas de terminal, você quer finalizá-las?", - "yes": "Sim" + "terminalService.terminalCloseConfirmationPlural": "Existem {0} sessões ativas de terminal, você quer finalizá-las?" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/ptb/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..5d3bc21b50f --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.configuration.title": "Um resumo das configurações. Este rótulo será usado no arquivo de configurações como um comentário de separação.", + "vscode.extension.contributes.configuration.properties": "Descrição das propriedades de configuração.", + "scope.window.description": "Janela de configuração específica que pode ser configurada nas configurações do usuário ou área de trabalho.", + "scope.resource.description": "Configuração específica do recurso que pode ser configurada nas configurações do usuário, espaço de trabalho ou pasta.", + "vscode.extension.contributes.configuration": "Contribui às definições de configuração.", + "invalid.title": "'configuration.title' deve ser um string", + "vscode.extension.contributes.defaultConfiguration": "Contribui às definições de configuração padrão do editor por linguagem.", + "invalid.properties": "'configuration.properties' deve ser um objeto", + "invalid.allOf": "'configuration.allOf' está obsoleto e não deve ser usado. Em vez disso, passe várias seções de configuração como uma matriz para o ponto de contribuição 'configuration'.", + "workspaceConfig.folders.description": "Lista de pastas a serem carregadas no espaço de trabalho.", + "workspaceConfig.path.description": "Um caminho para um arquivo. Por exemplo, '/root /pastaA' ou './pastaA' para um caminho relativo que será determinado de acordo com o local do arquivo no espaço de trabalho.", + "workspaceConfig.settings.description": "Configurações de espaço de trabalho", + "workspaceConfig.extensions.description": "Extensões para o espaço de trabalho", + "unknownWorkspaceProperty": "Propriedade de configuração do espaço de trabalho desconhecida" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/ptb/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/editor/common/editorService.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. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/ptb/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index 0f7a663082c..ca77d82093c 100644 --- a/i18n/ptb/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/ptb/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -6,6 +6,7 @@ { "schema.token.settings": "Cores e estilos para o token.", "schema.token.foreground": "Cor do primeiro plano para o token.", + "schema.token.background.warning": "Atualmente as cores de fundo do token não são suportadas.", "schema.token.fontStyle": "Estilo da fonte da regra: um estilo ou uma combinação de 'itálico', 'negrito' e 'sublinhado'", "schema.fontStyle.error": "O estilo da fonte deve ser uma combinação de 'itálico', 'negrito' e 'sublinhado'", "schema.properties.name": "Descrição da regra.", diff --git a/i18n/ptb/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/ptb/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index 3cf20c82de2..ddfc13e6a19 100644 --- a/i18n/ptb/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/ptb/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "Quando estiver utilizando uma fonte: O tamanho da fonte em porcentagem para a fonte de texto. Se não for definido, o padrão é o tamanho na definição de fonte.", "schema.fontId": "Quando estiver utilizando uma fonte: A identificação da fonte. Se não for definido, o padrão é a primeira definição de fonte.", "schema.light": "Associações opcionais para ícones de arquivo em temas de cor clara.", - "schema.highContrast": "Associações opcionais para ícones de arquivo em temas de alto contraste." + "schema.highContrast": "Associações opcionais para ícones de arquivo em temas de alto contraste.", + "schema.hidesExplorerArrows": "Define se as setas do explorador de arquivos devem ser ocultadas quando este tema está ativo." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..938c7bbea81 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.themes": "Contribui com temas de cores do textmate.", + "vscode.extension.contributes.themes.id": "ID do tema do ícone como usado em configurações do usuário.", + "vscode.extension.contributes.themes.label": "Etiqueta da cor do tema como mostrado na interface do usuário.", + "vscode.extension.contributes.themes.uiTheme": "Tema base de definição das cores do editor: 'vs' é o tema de cor clara, 'vs-dark' é o tema de cor escura. 'hc preto' é o tema escuro de alto contraste.", + "vscode.extension.contributes.themes.path": "Caminho do arquivo tmTheme. O caminho é relativo à pasta de extensão e é normalmente './themes/themeFile.tmTheme'.", + "reqarray": "Ponto de extensão '{0}' deve ser uma matriz.", + "reqpath": "Esperada uma string em `contributes.{0}.path`. Valor informado: {1}", + "invalid.path.1": "É esperado que `contributes.{0}.path` ({1}) seja incluído na pasta da extensão ({2}). Isto pode tornar a extensão não portável." +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..f78a56c0249 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.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. +{ + "error.cannotparseicontheme": "Problemas de análise do arquivo de ícones: {0}" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..0181b35ac2a --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.iconThemes": "Contribui com temas de ícones de arquivo.", + "vscode.extension.contributes.iconThemes.id": "ID do tema do ícone como usado em configurações do usuário.", + "vscode.extension.contributes.iconThemes.label": "Etiqueta do tema do ícone como mostrado na interface do usuário.", + "vscode.extension.contributes.iconThemes.path": "Caminho do arquivo de definição do tema do ícone. O caminho é relativo à pasta de extensão e é normalmente './icons/awesome-icon-theme.json'.", + "reqarray": "Ponto de extensão '{0}' deve ser uma matriz.", + "reqpath": "Esperada uma string em `contributes.{0}.path`. Valor informado: {1}", + "reqid": "Esperada sequência em 'contributes.{0}.ID'. Valor fornecido: {1}", + "invalid.path.1": "É esperado que `contributes.{0}.path` ({1}) seja incluído na pasta da extensão ({2}). Isto pode tornar a extensão não portável." +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index db248225f67..d27ccd6f4ab 100644 --- a/i18n/ptb/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,31 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contribui com temas de cores do textmate.", - "vscode.extension.contributes.themes.id": "ID do tema do ícone conforme usado em configurações do usuário.", - "vscode.extension.contributes.themes.label": "Etiqueta da cor do tema como mostrado na interface do usuário.", - "vscode.extension.contributes.themes.uiTheme": "Tema base de definição das cores do editor: 'vs' é o tema de cor clara, 'vs-dark' é o tema de cor escura. 'hc preto' é o tema escuro de alto contraste.", - "vscode.extension.contributes.themes.path": "Caminho do arquivo tmTheme. O caminho é relativo à pasta de extensão e é normalmente './themes/themeFile.tmTheme'.", - "vscode.extension.contributes.iconThemes": "Contribui com temas de ícones de arquivo.", - "vscode.extension.contributes.iconThemes.id": "ID do tema do ícone como usado em configurações do usuário.", - "vscode.extension.contributes.iconThemes.label": "Etiqueta do tema do ícone como mostrado na interface do usuário.", - "vscode.extension.contributes.iconThemes.path": "Caminho do arquivo de definição do tema do ícone. O caminho é relativo à pasta de extensão e é normalmente './icons/awesome-icon-theme.json'.", "migration.completed": "Foram adicionadas novas configurações de tema para as configurações de usuário. Backup está disponível em {0}.", "error.cannotloadtheme": "Não é possível carregar {0}: {1}", - "reqarray": "Ponto de extensão '{0}' deve ser uma matriz.", - "reqpath": "Esperada uma string em `contributes.{0}.path`. Valor informado: {1}", - "invalid.path.1": "É esperado que `contributes.{0}.path` ({1}) seja incluído na pasta da extensão ({2}). Isto pode tornar a extensão não portável.", - "reqid": "Esperada sequência em 'contributes.{0}.ID'. Valor fornecido: {1}", "error.cannotloadicontheme": "Não é possível carregar {0}", - "error.cannotparseicontheme": "Problemas de análise do arquivo de ícones: {0}", "colorTheme": "Especifica o tema de cores usado no espaço de trabalho.", "colorThemeError": "Tema é desconhecido ou não está instalado.", "iconTheme": "Especifica o tema de ícones usado no espaço de trabalho ou 'null' para não mostrar qualquer arquivo de ícones.", "noIconThemeDesc": "Nenhum arquivo de ícones", "iconThemeError": "Arquivo de tema de ícones é desconhecido ou não está instalado.", "workbenchColors": "Substitui as cores do tema do tema de cores atualmente selecionado.", - "workbenchColors.deprecated": "A configuração não é mais experimental e foi renomeada para 'workbench.colorCustomizations'", - "workbenchColors.deprecatedDescription": "Use 'workbench.colorCustomizations'", "editorColors": "Substitui as cores e o estilo da fonte do editor do tema de cores atualmente selecionado.", "editorColors.comments": "Define as cores e estilos para os comentários", "editorColors.strings": "Define as cores e estilos para textos literais.", diff --git a/i18n/ptb/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/ptb/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..ddf43c7774f --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/workspace/node/workspaceEditingService.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. +{ + "openWorkspaceConfigurationFile": "Abrir o Arquivo de Configuração do Espaço de Trabalho", + "close": "Fechar" +} \ No newline at end of file diff --git a/i18n/rus/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/rus/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index 8760c57e674..a691501ffe0 100644 --- a/i18n/rus/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/rus/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "например, myFile.txt", - "activeEditorMedium": "например, myFolder/myFile.txt", - "activeEditorLong": "например, /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "например, myFolder1, myFolder2, myFolder3", - "rootPath": "например, /Users/Development/myProject", - "folderName": "например, myFolder", - "folderPath": "например, /Users/Development/myFolder", "appName": "например, VS Code", "dirty": "индикатор dirty, если активный редактор является \"грязным\"", "separator": "условный разделитель (-), который отображается, только если окружен переменными со значениями", diff --git a/i18n/rus/extensions/emmet/package.i18n.json b/i18n/rus/extensions/emmet/package.i18n.json index 5df2b4e5410..3c7e7099a9d 100644 --- a/i18n/rus/extensions/emmet/package.i18n.json +++ b/i18n/rus/extensions/emmet/package.i18n.json @@ -28,13 +28,6 @@ "command.incrementNumberByTen": "Увеличить значение на 10", "command.decrementNumberByTen": "Уменьшить значение на 10", "emmetSyntaxProfiles": "Задайте профиль для указанного синтаксиса или используйте свой собственный профиль с определенными правилами.", - "emmetExclude": "Массив языков, в которых не должны развертываться сокращения Emmet.", - "emmetExtensionsPath": "Путь к папке, содержащей профили Emmet и фрагменты кода.", - "emmetShowExpandedAbbreviation": "Отображает развернутые сокращения Emmet в виде предложений.\nПараметр \"inMarkupAndStylesheetFilesOnly\" применяется к html, haml, jade, slim, xml, xsl, css, scss, sass, less и stylus .\nПараметр \"always\" применяется ко всем частям файла независимо от разметки и стилей.", - "emmetShowAbbreviationSuggestions": "Отображает возможные сокращения Emmet в виде предложений. Не применяется в таблицах стилей или если параметр emmet.showExpandedAbbreviation имеет значение \"never\".", - "emmetIncludeLanguages": "Включает сокращения Emmet в языках, которые не поддерживаются по умолчанию. Здесь можно указать связь между не поддерживаемым и поддерживаемым языками.\nПример: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", - "emmetVariables": "Переменные, которые будут использоваться во фрагментах Emmet", - "emmetTriggerExpansionOnTab": "Если включено, сокращения Emmet разворачиваются при нажатии клавиши TAB.", "emmetPreferences": "Настройки, которые используются для изменения поведения некоторых действий и сопоставителей Emmet.", "emmetPreferencesIntUnit": "Единица по умолчанию для целочисленных значений", "emmetPreferencesFloatUnit": "Единица по умолчанию для значений с плавающей запятой", @@ -43,6 +36,5 @@ "emmetPreferencesStylusAfter": "Символ, который будет помещен в конце свойства CSS при развертывании сокращений CSS в файлах Stylus", "emmetPreferencesCssBetween": "Символ, который будет помещен между свойством CSS и значением при развертывании сокращений CSS", "emmetPreferencesSassBetween": "Символ, который будет помещен между свойством CSS и значением при развертывании сокращений CSS в файлах Sass", - "emmetPreferencesStylusBetween": "Символ, который будет помещен между свойством CSS и значением при развертывании сокращений CSS в файлах Stylus", - "emmetShowSuggestionsAsSnippets": "Если этот параметр имеет значение true, предложения Emmet будут отображаться в виде фрагментов, которые можно упорядочить с помощью параметра editor.snippetSuggestions." + "emmetPreferencesStylusBetween": "Символ, который будет помещен между свойством CSS и значением при развертывании сокращений CSS в файлах Stylus" } \ No newline at end of file diff --git a/i18n/rus/extensions/git/out/commands.i18n.json b/i18n/rus/extensions/git/out/commands.i18n.json index 633cd74962b..f8b4fce36b0 100644 --- a/i18n/rus/extensions/git/out/commands.i18n.json +++ b/i18n/rus/extensions/git/out/commands.i18n.json @@ -12,8 +12,8 @@ "cloning": "Клонируется репозиторий Git...", "openrepo": "Открыть репозиторий", "proposeopen": "Вы хотите открыть клонированный репозиторий?", - "path to init": "Путь к папке", - "provide path": "Укажите путь к папке для инициализации репозитория Git", + "init repo": "Инициализировать репозиторий", + "create repo": "Инициализировать репозиторий", "HEAD not available": "Версия HEAD '{0}' недоступна.", "confirm stage files with merge conflicts": "Вы действительно хотите перенести в промежуточный этап файлы с конфликтами слияния ({0})?", "confirm stage file with merge conflicts": "Вы действительно хотите перенести в промежуточный этап файлы с конфликтами слияния ({0})?", diff --git a/i18n/rus/extensions/git/out/repository.i18n.json b/i18n/rus/extensions/git/out/repository.i18n.json index 053f8f8b45f..019265640e5 100644 --- a/i18n/rus/extensions/git/out/repository.i18n.json +++ b/i18n/rus/extensions/git/out/repository.i18n.json @@ -21,6 +21,8 @@ "deleted by us": "Удалено нами", "both added": "Добавлено обеими сторонами", "both modified": "Изменено обеими сторонами", + "untracked, short": "U", + "modified, short": "M", "commit": "Commit", "merge changes": "Объединить изменения", "staged changes": "Промежуточно сохраненные изменения", diff --git a/i18n/rus/extensions/typescript/package.i18n.json b/i18n/rus/extensions/typescript/package.i18n.json index aeaeec49a6a..15940c3fc59 100644 --- a/i18n/rus/extensions/typescript/package.i18n.json +++ b/i18n/rus/extensions/typescript/package.i18n.json @@ -44,7 +44,6 @@ "typescript.npm": "Указывает путь к исполняемому файлу NPM, используемому для автоматического получения типа. Требуется TypeScript версии 2.3.4 или более поздней версии.", "typescript.check.npmIsInstalled": "Проверяет, установлен ли NPM для автоматического получения типов.", "javascript.nameSuggestions": "Включить/отключить использование уникальных имен из файла в списках предложений JavaScript.", - "typescript.tsc.autoDetect": "Включает или отключает автоматическое определние заданий tsc.", "typescript.problemMatchers.tsc.label": "Проблемы TypeScript", "typescript.problemMatchers.tscWatch.label": "Проблемы TypeScript (режим наблюдения)" } \ No newline at end of file diff --git a/i18n/rus/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/rus/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 56455258496..32fb3e012c8 100644 --- a/i18n/rus/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/rus/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,6 @@ "label.replaceButton": "Заменить", "label.replaceAllButton": "Заменить все", "label.toggleReplaceButton": "Режим \"Переключение замены\"", - "title.matchesCountLimit": "Отображаются только первые 999 результатов, но все операции поиска выполняются со всем текстом.", "label.matchesLocation": "{0} из {1}", "label.noResults": "Нет результатов" } \ No newline at end of file diff --git a/i18n/rus/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/rus/src/vs/editor/contrib/find/common/findController.i18n.json index 5cbc15bce8a..5c6f87afd29 100644 --- a/i18n/rus/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/rus/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "Найти следующее выделение", "previousSelectionMatchFindAction": "Найти предыдущее выделение", "startReplace": "Заменить", - "addSelectionToNextFindMatch": "Добавить выделение в следующее найденное совпадение", - "addSelectionToPreviousFindMatch": "Добавить выделенный фрагмент в предыдущее найденное совпадение", - "moveSelectionToNextFindMatch": "Переместить последнее выделение в следующее найденное совпадение", - "moveSelectionToPreviousFindMatch": "Переместить последний выделенный фрагмент в предыдущее найденное совпадение", - "selectAllOccurrencesOfFindMatch": "Выбрать все вхождения найденных совпадений", - "changeAll.label": "Изменить все вхождения", "showNextFindTermAction": "Показать следующий найденный термин", "showPreviousFindTermAction": "Показать предыдущий найденный термин" } \ No newline at end of file diff --git a/i18n/rus/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/rus/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index de410095204..660193a943e 100644 --- a/i18n/rus/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/rus/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Добавить курсор выше", "mutlicursor.insertBelow": "Добавить курсор ниже", - "mutlicursor.insertAtEndOfEachLineSelected": "Добавить курсоры к окончаниям строк" + "mutlicursor.insertAtEndOfEachLineSelected": "Добавить курсоры к окончаниям строк", + "addSelectionToNextFindMatch": "Добавить выделение в следующее найденное совпадение", + "addSelectionToPreviousFindMatch": "Добавить выделенный фрагмент в предыдущее найденное совпадение", + "moveSelectionToNextFindMatch": "Переместить последнее выделение в следующее найденное совпадение", + "moveSelectionToPreviousFindMatch": "Переместить последний выделенный фрагмент в предыдущее найденное совпадение", + "selectAllOccurrencesOfFindMatch": "Выбрать все вхождения найденных совпадений", + "changeAll.label": "Изменить все вхождения" } \ No newline at end of file diff --git a/i18n/rus/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/rus/src/vs/platform/theme/common/colorRegistry.i18n.json index dbab65f5dc7..4de61ec7ef4 100644 --- a/i18n/rus/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/rus/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "Недопустимый формат цвета. Используйте #RGB, #RGBA, #RRGGBB или #RRGGBBAA", "schema.colors": "Цвета, используемые на рабочем месте.", "foreground": "Общий цвет переднего плана. Этот цвет используется, только если его не переопределит компонент.", "errorForeground": "Общий цвет переднего плана для сообщений об ошибках. Этот цвет используется только если его не переопределяет компонент.", diff --git a/i18n/rus/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/rus/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 3dc67610b94..8ad801af2f1 100644 --- a/i18n/rus/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -13,6 +13,7 @@ "select": "&&Выбрать", "selectWorkspace": "Выбрать папки для рабочей области", "removeFolderFromWorkspace": "Удалить папку из рабочей области", + "openFolderSettings": "Открыть параметры папок", "saveWorkspaceAsAction": "Сохранить рабочую область как...", "save": "Сохранить", "saveWorkspace": "Сохранить рабочую область", diff --git a/i18n/rus/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index cdc81741e9e..946bb84393f 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Скрыть панель действий", - "activityBarAriaLabel": "Переключатель активного представления", "globalActions": "Глобальные действия" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..c9f39eaf3a5 --- /dev/null +++ b/i18n/rus/src/vs/workbench/browser/parts/compositebar/compositeBar.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. +{ + "activityBarAriaLabel": "Переключатель активного представления" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..0e338824c87 --- /dev/null +++ b/i18n/rus/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "Дополнительные представления", + "numberBadge": "{0} ({1})", + "manageExtension": "Управление расширениями", + "titleKeybinding": "{0} ({1})", + "toggle": "Переключить закрепленное представление" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 75bbb3e9519..3c123d9ce41 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "Показать редакторы во второй группе", "groupThreePicker": "Показать редакторы в третьей группе", "allEditorsPicker": "Показать все открытые редакторы", - "view": "Просмотр" + "view": "Просмотр", + "file": "Файл" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 000e440a7b7..2fc29a94bab 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "Команда \"{0}\" сейчас неактивна, и ее невозможно выполнить.", "manageExtension": "Управление расширениями" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/rus/src/vs/workbench/electron-browser/main.contribution.i18n.json index 1de29e6dd0e..6887c80a117 100644 --- a/i18n/rus/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,18 +10,14 @@ "workspaces": "Рабочие области", "developer": "Разработчик", "showEditorTabs": "Определяет, должны ли открытые редакторы отображаться на вкладках или нет.", - "workbench.editor.labelFormat.default": "Отображать имя файла. Если вкладки включены и в одной группе есть два файла с одинаковыми именами, будут добавлены различающиеся части пути к каждому из этих файлов. Если вкладки отключены, то для активного редактора отображается путь по отношению к корневому каталогу рабочей области.", "workbench.editor.labelFormat.short": "Отображать имя файла и имя каталога.", - "workbench.editor.labelFormat.medium": "Отображать имя файла и путь к файлу относительно корневого каталога рабочей области.", "workbench.editor.labelFormat.long": "Отображать имя файла и абсолютный путь.", "tabDescription": "Определяет формат метки редактора. Изменив этот параметр, можно сделать более наглядным расположение файла:\n- короткий формат: 'parent'\n- средний формат: 'workspace/src/parent'\n- длинный формат: '/home/user/workspace/src/parent'\n- по умолчанию: '.../parent', если другая вкладка имеет такой же заголовок или относительный путь к рабочей области, если вкладки отключены", "editorTabCloseButton": "Определяет положение кнопок закрытия вкладок редактора или отключает их, если задано значение off.", "showIcons": "Определяет, должны ли открытые редакторы отображаться со значком. Требует включить тему значков.", "enablePreview": "Определяет, отображаются ли открытые редакторы в режиме предварительного просмотра. Редакторы в режиме предварительного просмотра можно использовать, пока они открыты (например, с помощью двойного щелчка мыши или изменения). Текст в таких редакторах отображается курсивом.", "enablePreviewFromQuickOpen": "Определяет, отображаются ли редакторы из Quick Open в режиме предварительного просмотра. Редакторы в режиме предварительного просмотра повторно используются до сохранения (например, с помощью двойного щелчка или изменения).", - "editorOpenPositioning": "Определяет место открытия редакторов. Выберите \"Слева\" или \"Справа\", чтобы открывать редакторы слева или справа от активного сейчас редактора. Выберите \"Первый\" или \"Последний\", чтобы открывать редакторы независимо от активного сейчас редактора.", "revealIfOpen": "Определяет, отображается ли редактор в какой-либо из видимых групп при открытии. Если функция отключена, редактор открывается в текущей активной группе редакторов. Если функция включена, вместо открытия уже открытый редактор будет отображен в текущей активной группе редакторов. Обратите внимание, что в некоторых случаях этот параметр игнорируется, например при принудительном открытии редактора в определенной группе или сбоку от текущей активной группы редакторов.", - "commandHistory": "Определяет количество недавно использованных команд, которые следует хранить в журнале палитры команд. Установите значение 0, чтобы отключить журнал команд.", "preserveInput": "Определяет, следует ли восстановить последнюю введенную команду в палитре команд при следующем открытии палитры.", "closeOnFocusLost": "Управляет автоматическим закрытием Quick Open при потере фокуса.", "openDefaultSettings": "Управляет открытием редактора с отображением всех настроек по умолчанию при открытии настроек.", @@ -50,7 +46,6 @@ "restoreWindows": "Управляет повторным открытием окон после перезапуска. Выберите 'none', чтобы всегда начинать с пустой рабочей области; 'one', чтобы открыть последнее окно, с которым вы работали; 'folders', чтобы открыть все окна с открытыми папками, и 'all', чтобы открыть все окна последнего сеанса.", "restoreFullscreen": "Определяет, должно ли окно восстанавливаться в полноэкранном режиме, если оно было закрыто в полноэкранном режиме.", "zoomLevel": "Настройте масштаб окна. Исходный размер равен 0. Увеличение или уменьшение значения на 1 означает увеличение или уменьшение окна на 20 %. Чтобы более точно задать масштаб, можно также ввести десятичное число.", - "title": "Определяет заголовок окна в зависимости от активного редактора. Подстановка переменных выполняется на основе контекста:\n${activeEditorShort}: например, myFile.txt\n${activeEditorMedium}: например, myFolder/myFile.txt\n${activeEditorLong}: например, /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: например, myFolder\n${folderPath}: например, /Users/Development/myFolder\n${rootName}: например, myFolder1, myFolder2, myFolder3\n${rootPath}: например, /Users/Development/myWorkspace\n${appName}: например, VS Code\n${dirty}: индикатор dirty, если активный редактор является \"грязным\"\n${separator}: условный разделитель (\" - \"), который отображается, только если окружен переменными со значениями ", "window.newWindowDimensions.default": "Открывать новые окна в центре экрана.", "window.newWindowDimensions.inherit": "Открывать новые окна того же размера, что и последнее активное окно.", "window.newWindowDimensions.maximized": "Открывать новые окна в развернутом состоянии.", diff --git a/i18n/rus/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 820bfa6a8c8..4c4a6981903 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "Отладка: {0}", "debugAriaLabel": "Введите имя используемой конфигурации запуска.", + "addConfigTo": "Добавить конфигурацию ({0})...", + "addConfiguration": "Добавить конфигурацию...", "noConfigurationsMatching": "Нет соответствующих конфигураций отладки.", "noConfigurationsFound": "Конфигурации отладки не найдены. Создайте файл \"launch.json\"." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..255ae8e1d50 --- /dev/null +++ b/i18n/rus/src/vs/workbench/parts/debug/browser/debugStatus.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. +{ + "debug": "Отладка" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/rus/src/vs/workbench/parts/debug/browser/debugViewlet.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/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 7574689b0ef..63d876aca0d 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 @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "Конфигурации для создания первоначального файла launch.json.", "vscode.extension.contributes.debuggers.languages": "Список языков, для которых расширение отладки может считаться \"отладчиком по умолчанию\".", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Если задано, VS Code будет вызывать эту команду, чтобы определить путь к исполняемому файлу адаптера отладки и передаваемые аргументы.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Если задано, VS Code будет вызывать эту команду для действий \"отладка\" или \"запуск\", предназначенных для этого расширения.", "vscode.extension.contributes.debuggers.configurationSnippets": "Фрагменты для добавления новых конфигураций в launch.json.", "vscode.extension.contributes.debuggers.configurationAttributes": "Конфигурации схемы JSON для проверки launch.json.", "vscode.extension.contributes.debuggers.windows": "Параметры, связанные с Windows.", diff --git a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 3333c4ffeb2..94b75507832 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,10 +12,7 @@ "breakpointRemoved": "Удалена точка останова: строка {0}, файл {1}", "compoundMustHaveConfigurations": "Для составного элемента должен быть задан атрибут configurations для запуска нескольких конфигураций.", "configMissing": "Конфигурация \"{0}\" отсутствует в launch.json.", - "debugRequestNotSupported": "В выбранной конфигурации отладки указано неподдерживаемое значение атрибута '{0}': '{1}'.", - "debugRequesMissing": "В выбранной конфигурации отладки отсутствует атрибут '{0}'.", "debugTypeNotSupported": "Настроенный тип отладки \"{0}\" не поддерживается.", - "debugTypeMissing": "Отсутствует свойство \"type\" для выбранной конфигурации запуска.", "preLaunchTaskErrors": "При выполнении предварительной задачи \"{0}\" обнаружены ошибки.", "preLaunchTaskError": "При выполнении предварительной задачи \"{0}\" обнаружена ошибка.", "preLaunchTaskExitCode": "Выполнение предварительной задачи \"{0}\" завершено с кодом выхода {1}.", diff --git a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 4c742d270df..c7556643f1a 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -7,6 +7,5 @@ "stateCapture": "Состояние объекта записывается после первого вычисления", "replVariableAriaLabel": "Переменная \"{0}\" имеет значение \"{1}\", read–eval–print loop, отладка", "replExpressionAriaLabel": "Выражение \"{0}\" имеет значение \"{1}\", read–eval–print loop, отладка", - "replValueOutputAriaLabel": "{0}, read–eval–print loop, отладка", - "replKeyValueOutputAriaLabel": "Выходная переменная \"{0}\" имеет значение \"{1}\", read–eval–print loop, отладка" + "replValueOutputAriaLabel": "{0}, read–eval–print loop, отладка" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index 9a2b3bf6390..821930bfc87 100644 --- a/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "Файлы", + "filesCategory": "Файл", "revealInSideBar": "Показать в боковой панели", "acceptLocalChanges": "Использовать изменения и перезаписать содержимое диска", "revertLocalChanges": "Отменить изменения и вернуться к содержимому на диске" diff --git a/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 61840ca236b..b5890f55c3b 100644 --- a/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -37,8 +37,6 @@ "openToSide": "Открыть сбоку", "compareSource": "Выбрать для сравнения", "globalCompareFile": "Сравнить активный файл с...", - "pickHistory": "Выберите предыдущий открытый файл для сравнения.", - "unableToFileToCompare": "Выбранный файл нельзя сравнить с \"{0}\".", "openFileToCompare": "Чтобы сравнить файл с другим файлом, сначала откройте его.", "compareWith": "Сравнить '{0}' с '{1}'", "compareFiles": "Сравнить файлы", @@ -47,7 +45,6 @@ "saveAs": "Сохранить как...", "saveAll": "Сохранить все", "saveAllInGroup": "Сохранить все в группе", - "saveFiles": "Сохранить файлы с изменениями", "revert": "Отменить изменения в файле", "focusOpenEditors": "Фокус на представлении открытых редакторов", "focusFilesExplorer": "Фокус на проводнике", diff --git a/i18n/rus/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/rus/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 5eb9bd6927b..5c9b67b2669 100644 --- a/i18n/rus/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,6 @@ { "noWorkspace": "Нет открытой папки", "explorerSection": "Раздел проводника", - "noWorkspaceHelp": "Вы еще не открыли папку.", + "noFolderHelp": "Вы еще не открыли папку.", "openFolder": "Открыть папку" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/rus/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..1ffd1cf8897 --- /dev/null +++ b/i18n/rus/src/vs/workbench/parts/markers/browser/markersFileDecorations.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. +{ + "label": "Проблемы" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index 71bf804e800..ef1380536bf 100644 --- a/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "Укажите параметры здесь, чтобы перезаписать параметры по умолчанию.", - "errorInvalidConfiguration": "Не удается записать параметры. Устраните ошибки и предупреждения в файле и повторите попытку.", "emptyWorkspaceSettingsHeader": "Укажите параметры здесь, чтобы перезаписать параметры пользователей.", "emptyFolderSettingsHeader": "Укажите параметры папок здесь, чтобы перезаписать параметры рабочих областей.", "defaultFolderSettingsTitle": "Параметры папок по умолчанию", diff --git a/i18n/rus/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/rus/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 631ee068c6b..a7528085d74 100644 --- a/i18n/rus/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "Команда {0} не разрешена в текущем контексте.", "recentlyUsed": "недавно использованные", "morecCommands": "другие команды", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "Нет соответствующих команд" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index f26e342d6b3..6d0870f5800 100644 --- a/i18n/rus/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -17,7 +17,6 @@ "exclude": "Настройте стандартные маски для исключения файлов и папок при поиске. Все стандартные маски наследуются от параметра file.exclude.", "exclude.boolean": "Стандартная маска, соответствующая путям к файлам. Задайте значение true или false, чтобы включить или отключить маску.", "exclude.when": "Дополнительная проверка элементов того же уровня соответствующего файла. Используйте $(basename) в качестве переменной для соответствующего имени файла.", - "useRipgrep": "Определяет, использовать ли ripgrep в текстовом поиске", "useIgnoreFilesByDefault": "Определяет, следует ли использовать GITIGNORE- и IGNORE-файлы по умолчанию при поиске в новой рабочей области.", "search.quickOpen.includeSymbols": "Настройте для включения результатов поиска глобальных символов в файлы по запросу для Quick Open." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/rus/src/vs/workbench/parts/search/browser/searchActions.i18n.json index a60edb8ea77..969c020706c 100644 --- a/i18n/rus/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -19,7 +19,6 @@ "ClearSearchResultsAction.label": "Очистить результаты поиска", "FocusNextSearchResult.label": "Перейти к следующему результату поиска.", "FocusPreviousSearchResult.label": "Перейти к предыдущему результату поиска.", - "RemoveAction.label": "Удалить", "file.replaceAll.label": "Заменить все", "match.replace.label": "Заменить" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/rus/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 8f0ce17a110..d771b1fdbdc 100644 --- a/i18n/rus/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,8 +10,8 @@ "vscode.extension.contributes.snippets": "Добавляет фрагменты.", "vscode.extension.contributes.snippets-language": "Идентификатор языка, для которого добавляется этот фрагмент.", "vscode.extension.contributes.snippets-path": "Путь к файлу фрагментов. Путь указывается относительно папки расширения и обычно начинается с \"./snippets/\".", - "badFile": "Не удалось прочитать файл фрагмента \"{0}\".", "badVariableUse": "Похоже, во фрагменте \"{0}\" перепутаны переменные и заполнители. Дополнительные сведения см. на странице https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax.", + "badFile": "Не удалось прочитать файл фрагмента \"{0}\".", "source.snippet": "Фрагмент кода пользователя", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 05cb39eed74..18331d6a712 100644 --- a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -16,7 +16,6 @@ "workbench.action.terminal.new.short": "Новый терминал", "workbench.action.terminal.focus": "Фокус на терминале", "workbench.action.terminal.focusNext": "Фокус на следующем терминале", - "workbench.action.terminal.focusAtIndex": "Фокус на терминале {0}", "workbench.action.terminal.focusPrevious": "Фокус на предыдущем терминале", "workbench.action.terminal.paste": "Вставить в активный терминал", "workbench.action.terminal.DefaultShell": "Выбрать оболочку по умолчанию", diff --git a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 92eaeea4fb9..80ae6596199 100644 --- a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Копировать", - "createNewTerminal": "Новый терминал", "paste": "Вставить", "selectAll": "Выбрать все", "clear": "Очистить" diff --git a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 77b64a5be2d..440d374ef82 100644 --- a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "ОК. Больше не показывать", "terminal.integrated.chooseWindowsShell": "Выберите предпочитаемую оболочку терминала. Ее можно позже изменить в параметрах", "terminalService.terminalCloseConfirmationSingular": "Есть активный сеанс терминала, завершить его?", - "terminalService.terminalCloseConfirmationPlural": "Есть несколько активных сеансов терминала ({0}), завершить их?", - "yes": "Да" + "terminalService.terminalCloseConfirmationPlural": "Есть несколько активных сеансов терминала ({0}), завершить их?" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/rus/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..42442e0f21a --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,22 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.configuration.title": "Краткая сводка параметров. Эта метка будет использоваться в файле параметров в качестве разделяющего комментария.", + "vscode.extension.contributes.configuration.properties": "Описание свойств конфигурации.", + "scope.window.description": "Конфигурация окна, которая может быть задана в параметрах пользователя или рабочей области.", + "scope.resource.description": "Конфигурации ресурсов, которые могут быть заданы в параметрах пользователей, рабочих областей или папок.", + "scope.description": "Область, в которой применяется конфигурация. Доступные области — 'window' и 'resource'.", + "vscode.extension.contributes.configuration": "Добавляет параметры конфигурации.", + "invalid.title": "configuration.title должно быть строкой", + "vscode.extension.contributes.defaultConfiguration": "Предоставляет параметры конфигурации редактора по умолчанию в соответствии с языком.", + "invalid.properties": "configuration.properties должно быть объектом", + "invalid.allOf": "Параметр 'configuration.allOf' является устаревшим, и использовать его не рекомендуется. Вместо этого передайте несколько параметров в виде массива в точку вклада 'configuration'.", + "workspaceConfig.folders.description": "Список папок, которые будут загружены в рабочую область.", + "workspaceConfig.path.description": "Путь к файлу, например, \"/root/folderA\" или \"./folderA\" для пути по отношению к файлу рабочей области.", + "workspaceConfig.name.description": "Необязательное имя папки.", + "workspaceConfig.extensions.description": "Расширения рабочей области", + "unknownWorkspaceProperty": "Неизвестное свойство рабочей области" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/rus/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/editor/common/editorService.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. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/rus/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..c91d95429ee --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.themes": "Contributes textmate color themes.", + "vscode.extension.contributes.themes.id": "Идентификатор темы значка, как используется в параметрах пользователя.", + "vscode.extension.contributes.themes.label": "Метка цветовой схемы, отображаемая в пользовательском интерфейсе.", + "vscode.extension.contributes.themes.uiTheme": "Базовая тема, определяющая цвета оформления редактора: \"vs\" — светлая цветовая тема, \"vs-dark\" — темная цветовая тема. \"hc-black\" — темная высококонтрастная тема.", + "vscode.extension.contributes.themes.path": "Путь к файлу tmTheme. Путь указывается относительно папки расширения и имеет вид \"./themes/themeFile.tmTheme\".", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "В contributes.{0}.path требуется строка. Указанное значение: {1}", + "invalid.path.1": "contributes.{0}.path ({1}) должен был быть включен в папку расширения ({2}). Это может сделать расширение непереносимым." +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/rus/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..b0f9faf6b52 --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.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. +{ + "error.cannotparseicontheme": "Problems parsing file icons file: {0}" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/rus/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..d03dc07b9a9 --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "Идентификатор темы значка, как используется в параметрах пользователя.", + "vscode.extension.contributes.iconThemes.label": "Метка темы значка, как отображается в пользовательском интерфейсе.", + "vscode.extension.contributes.iconThemes.path": "Путь к файлу определения темы значка. Путь задается относительно папки расширения и, как правило, имеет следующий вид: \"./icons/awesome-icon-theme.json\".", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "В contributes.{0}.path требуется строка. Указанное значение: {1}", + "reqid": "Ожидалась строка в \"contributes.{0}.id\". Указанное значение: {1}", + "invalid.path.1": "contributes.{0}.path ({1}) должен был быть включен в папку расширения ({2}). Это может сделать расширение непереносимым." +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/rus/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index 8caee5d0eae..e2aef412ef5 100644 --- a/i18n/rus/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/rus/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,31 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "Идентификатор темы значка, как используется в параметрах пользователя.", - "vscode.extension.contributes.themes.label": "Метка цветовой схемы, отображаемая в пользовательском интерфейсе.", - "vscode.extension.contributes.themes.uiTheme": "Базовая тема, определяющая цвета оформления редактора: \"vs\" — светлая цветовая тема, \"vs-dark\" — темная цветовая тема. \"hc-black\" — темная высококонтрастная тема.", - "vscode.extension.contributes.themes.path": "Путь к файлу tmTheme. Путь указывается относительно папки расширения и имеет вид \"./themes/themeFile.tmTheme\".", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "Идентификатор темы значка, как используется в параметрах пользователя.", - "vscode.extension.contributes.iconThemes.label": "Метка темы значка, как отображается в пользовательском интерфейсе.", - "vscode.extension.contributes.iconThemes.path": "Путь к файлу определения темы значка. Путь задается относительно папки расширения и, как правило, имеет следующий вид: \"./icons/awesome-icon-theme.json\".", "migration.completed": "В параметры пользователя были добавлены новые параметры темы. Резервная копия доступна в {0}.", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "В contributes.{0}.path требуется строка. Указанное значение: {1}", - "invalid.path.1": "contributes.{0}.path ({1}) должен был быть включен в папку расширения ({2}). Это может сделать расширение непереносимым.", - "reqid": "Ожидалась строка в \"contributes.{0}.id\". Указанное значение: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "Указывает тему значков, используемую в рабочей области. Чтобы значки файлов не отображались, используйте значение 'null'.", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "Переопределяет цвета из выбранной цветовой темы.", - "workbenchColors.deprecated": "Параметр больше не является экспериментальным и был переименован в 'workbench.colorCustomizations'", - "workbenchColors.deprecatedDescription": "Используйте параметр 'workbench.colorCustomizations'", "editorColors": "Переопределяет цвета редактора и стиль шрифта из текущей выбранной цветовой темы.", "editorColors.comments": "Задает цвета и стили для комментариев", "editorColors.strings": "Задает цвета и стили для строковых литералов.", diff --git a/i18n/rus/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/rus/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..585cdb62fd6 --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/workspace/node/workspaceEditingService.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. +{ + "openWorkspaceConfigurationFile": "Открыть файл конфигурации рабочей области", + "close": "Закрыть" +} \ No newline at end of file diff --git a/i18n/trk/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/trk/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index cffb38fa05c..4f4f8629e96 100644 --- a/i18n/trk/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/trk/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "ör. myFile.txt", - "activeEditorMedium": "ör. myFolder/myFile.txt", - "activeEditorLong": "ör. /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "ör: myFolder1, myFolder2, myFolder3", - "rootPath": "ör. /Users/Development/myProject", - "folderName": "ör: myFolder", - "folderPath": "ör: /Users/Development/myFolder", "appName": "ör. VS Code", "dirty": "değişiklik göstergesi, aktif düzenleyici kaydedilmemiş değişiklikler içeriyorsa", "separator": "koşullu ayırıcı ('-') sadece değişkenler tarafından değerlerle çevrildiğinde gösterir", diff --git a/i18n/trk/extensions/emmet/package.i18n.json b/i18n/trk/extensions/emmet/package.i18n.json index e1f898b22d3..d22e3044f1e 100644 --- a/i18n/trk/extensions/emmet/package.i18n.json +++ b/i18n/trk/extensions/emmet/package.i18n.json @@ -28,13 +28,6 @@ "command.incrementNumberByTen": "10 Arttır", "command.decrementNumberByTen": "10 Azalt", "emmetSyntaxProfiles": "Belirtilen sentaks için profil tanımlayın veya kendi profilinizi belirli kurallarla kullanın.", - "emmetExclude": "Emmet kısaltmalarının genişletilmeyeceği bir diller dizisi.", - "emmetExtensionsPath": "Emmet profileri ve parçacıklarını içeren bir klasör yolu.'", - "emmetShowExpandedAbbreviation": "Genişletilmiş emmet kısaltmalarını öneriler olarak gösterir.\n\"inMarkupAndStylesheetFilesOnly\" seçeneği\" html, haml, jade, xml, xsl, css, scss, sass, less ve stylus'a uygulanır.\n\"always\" seçeneği işaretleme/css'den bağımsız olarak dosyanın tüm bölümlerine uygulanır.", - "emmetShowAbbreviationSuggestions": "Olası emmet kısaltmalarını öneriler olarak gösterir. Stil dosyalarında veya emmet.showExpandedAbbreviation, \"never\" olarak ayarlandığında uygulanamaz.", - "emmetIncludeLanguages": "Varsayılan olarak desteklenmeyen dillerde emmet kısaltmalarını etkinleştirin. Burada dil ile desteklenen emmet destekli dil arasında eşleme ekleyin.", - "emmetVariables": "Emmet parçacıklarında kullanılacak değişkenler", - "emmetTriggerExpansionOnTab": "Etkinleştirildiğinde, emmet kısaltmaları TAB tuşuna basıldığında genişletilir.", "emmetPreferences": "Emmet'in bazı eylemleri ve çözümleyicilerinin davranışını değiştirmek için kullanılacak tercihler.", "emmetPreferencesIntUnit": "Tam sayı değerleri için varsayılan birim", "emmetPreferencesFloatUnit": "Ondalık sayı değerleri için varsayılan birim", @@ -43,6 +36,5 @@ "emmetPreferencesStylusAfter": "Stylus dosyalarında CSS kısaltmaları genişletilirken CSS özelliğinin sonuna koyulacak sembol", "emmetPreferencesCssBetween": "CSS kısaltmaları genişletilirken CSS özelliği ve değerinin arasına koyulacak sembol", "emmetPreferencesSassBetween": "Sass dosyalarında CSS kısaltmaları genişletilirken CSS özelliği ve değerinin arasına koyulacak sembol", - "emmetPreferencesStylusBetween": "Stylus dosyalarında CSS kısaltmaları genişletilirken CSS özelliği ve değerinin arasına koyulacak sembol", - "emmetShowSuggestionsAsSnippets": "Doğru ise, emmet önerileri, editor.snippetSuggestions ayarı ile sıralayabilmenizi sağlayan parçacıklar olarak gösterilir." + "emmetPreferencesStylusBetween": "Stylus dosyalarında CSS kısaltmaları genişletilirken CSS özelliği ve değerinin arasına koyulacak sembol" } \ No newline at end of file diff --git a/i18n/trk/extensions/git/out/commands.i18n.json b/i18n/trk/extensions/git/out/commands.i18n.json index 062e690a02d..324d93134ea 100644 --- a/i18n/trk/extensions/git/out/commands.i18n.json +++ b/i18n/trk/extensions/git/out/commands.i18n.json @@ -12,8 +12,8 @@ "cloning": "Git deposu kopyalanıyor...", "openrepo": "Depoyu Aç", "proposeopen": "Kopyalanan depoyu açmak ister misiniz?", - "path to init": "Klasör yolu", - "provide path": "Git deposu oluşturmak için lütfen bir klasör yolu belirtin", + "init repo": "Depo Oluştur", + "create repo": "Depo Oluştur", "HEAD not available": "'{0}'e ait HEAD sürümü mevcut değil.", "confirm stage files with merge conflicts": "Birleştirme çakışmaları bulunan {0} dosyayı hazırlamak istediğinizden emin misiniz?", "confirm stage file with merge conflicts": "Birleştirme çakışmaları bulunan {0} klasörünü hazırlamak istediğinizden emin misiniz?", diff --git a/i18n/trk/extensions/git/out/repository.i18n.json b/i18n/trk/extensions/git/out/repository.i18n.json index 4f0f8a1a395..77b9fa01352 100644 --- a/i18n/trk/extensions/git/out/repository.i18n.json +++ b/i18n/trk/extensions/git/out/repository.i18n.json @@ -21,6 +21,8 @@ "deleted by us": "Bizim Tarafımızdan Silindi", "both added": "Her İkimiz de Ekledik", "both modified": "Her İkimiz de Değiştirdik", + "untracked, short": "Z", + "modified, short": "D", "commit": "Commit'le", "merge changes": "Değişiklikleri Birleştir", "staged changes": "Hazırlanmış Değişiklikler", diff --git a/i18n/trk/extensions/typescript/package.i18n.json b/i18n/trk/extensions/typescript/package.i18n.json index 6a51d6c3ed7..a4900ef3eea 100644 --- a/i18n/trk/extensions/typescript/package.i18n.json +++ b/i18n/trk/extensions/typescript/package.i18n.json @@ -44,7 +44,6 @@ "typescript.npm": "Otomatik Tür Kazanımı için kullanılacak NPM yürütülebilir dosyasının yolunu belirtir. TypeScript >= 2.3.4 gerektirir.", "typescript.check.npmIsInstalled": "Otomatik Tür Kazanımı için NPM'in yüklü olup olmadığını kontrol et.", "javascript.nameSuggestions": "JavaScript öneri listelerindeki dosyadan benzersiz adları eklemeyi etkinleştir veya devre dışı bırak.", - "typescript.tsc.autoDetect": "Tsc görevlerinin otomatik olarak algılanıp algılanmayacağını denetler. Varsayılan olarak açıktır.", "typescript.problemMatchers.tsc.label": "TypeScript sorunları", "typescript.problemMatchers.tscWatch.label": "TypeScript sorunları (izleme modu)" } \ No newline at end of file diff --git a/i18n/trk/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/trk/src/vs/editor/contrib/find/browser/findWidget.i18n.json index e483c295f19..52b4e3de03f 100644 --- a/i18n/trk/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/trk/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,6 @@ "label.replaceButton": "Değiştir", "label.replaceAllButton": "Tümünü Değiştir", "label.toggleReplaceButton": "Değiştirme modunu değiştir", - "title.matchesCountLimit": "Yalnızca ilk 999 sonuç vurgulandı, ancak tüm bulma işlemleri metnin tamamı üzerinde çalışıyor.", "label.matchesLocation": "{0}/{1}", "label.noResults": "Sonuç Yok" } \ No newline at end of file diff --git a/i18n/trk/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/trk/src/vs/editor/contrib/find/common/findController.i18n.json index e30fbb8a6d5..d6d3fc6ccf3 100644 --- a/i18n/trk/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/trk/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "Sonraki Seçimi Bul", "previousSelectionMatchFindAction": "Önceki Seçimi Bul", "startReplace": "Değiştir", - "addSelectionToNextFindMatch": "Seçimi Sonraki Bulunan Eşleşmeye Ekle", - "addSelectionToPreviousFindMatch": "Seçimi Önceki Bulunan Eşleşmeye Ekle", - "moveSelectionToNextFindMatch": "Son Seçimi Sonraki Bulunan Eşleşmeye Taşı", - "moveSelectionToPreviousFindMatch": "Son Seçimi Önceki Bulunan Eşleşmeye Taşı", - "selectAllOccurrencesOfFindMatch": "Bulunan Eşleşmenin Tüm Tekrarlamalarını Seç", - "changeAll.label": "Tüm Tekrarlamaları Değiştir", "showNextFindTermAction": "Sonraki Arama Terimini Göster", "showPreviousFindTermAction": "Önceki Arama Terimini Göster" } \ No newline at end of file diff --git a/i18n/trk/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/trk/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index f3fa18b4184..899e10e4b02 100644 --- a/i18n/trk/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/trk/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Yukarıya İmleç Ekle", "mutlicursor.insertBelow": "Aşağıya İmleç Ekle", - "mutlicursor.insertAtEndOfEachLineSelected": "Satır Sonlarına İmleç Ekle" + "mutlicursor.insertAtEndOfEachLineSelected": "Satır Sonlarına İmleç Ekle", + "addSelectionToNextFindMatch": "Seçimi Sonraki Bulunan Eşleşmeye Ekle", + "addSelectionToPreviousFindMatch": "Seçimi Önceki Bulunan Eşleşmeye Ekle", + "moveSelectionToNextFindMatch": "Son Seçimi Sonraki Bulunan Eşleşmeye Taşı", + "moveSelectionToPreviousFindMatch": "Son Seçimi Önceki Bulunan Eşleşmeye Taşı", + "selectAllOccurrencesOfFindMatch": "Bulunan Eşleşmenin Tüm Tekrarlamalarını Seç", + "changeAll.label": "Tüm Tekrarlamaları Değiştir" } \ No newline at end of file diff --git a/i18n/trk/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/trk/src/vs/platform/theme/common/colorRegistry.i18n.json index 690e08f5f05..4a14af64319 100644 --- a/i18n/trk/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/trk/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "Geçersiz renk biçimi. #RGB, #RGBA, #RRGGBB veya #RRGGBBAA kullanın", "schema.colors": "Çalışma ekranında kullanılan renkler.", "foreground": "Genel ön plan rengi. Bu renk, bir bileşen tarafından geçersiz kılınmadıkça kullanılır.", "errorForeground": "Hata mesajları için genel ön plan rengi. Bu renk, bir bileşen tarafından geçersiz kılınmadıkça kullanılır.", diff --git a/i18n/trk/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/trk/src/vs/workbench/browser/actions/workspaceActions.i18n.json index ed0caa5b58f..006f3eee320 100644 --- a/i18n/trk/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -9,10 +9,12 @@ "addFolderToWorkspace": "Çalışma Alanına Klasör Ekle...", "add": "&&Ekle", "addFolderToWorkspaceTitle": "Çalışma Alanına Klasör Ekle", + "globalRemoveFolderFromWorkspace": "Çalışma Alanından Klasör Kaldır...", "newWorkspace": "Yeni Çalışma Alanı...", "select": "&&Seç", "selectWorkspace": "Çalışma Alanı İçin Klasörleri Seçin", "removeFolderFromWorkspace": "Çalışma Alanından Klasör Kaldır", + "openFolderSettings": "Klasör Ayarlarını Aç", "saveWorkspaceAsAction": "Çalışma Alanını Farklı Kaydet...", "save": "&&Kaydet", "saveWorkspace": "Çalışma Alanını Kaydet", diff --git a/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index 32c2c08ce4c..832ee472cb0 100644 --- a/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Etkinlik Çubuğunu Gizle", - "activityBarAriaLabel": "Aktif Görünüm Değiştirici", "globalActions": "Global Eylemler" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..99a95a1980c --- /dev/null +++ b/i18n/trk/src/vs/workbench/browser/parts/compositebar/compositeBar.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. +{ + "activityBarAriaLabel": "Aktif Görünüm Değiştirici" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..fcbc6260597 --- /dev/null +++ b/i18n/trk/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "Ek Görünümler", + "numberBadge": "{0} ({1})", + "manageExtension": "Eklentiyi Yönet", + "titleKeybinding": "{0} ({1})", + "toggle": "Görünüm Sabitlemeyi Aç/Kapat" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 9059d7f92c9..5ff77e04882 100644 --- a/i18n/trk/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "İkinci Gruptaki Düzenleyicileri Göster", "groupThreePicker": "Üçüncü Gruptaki Düzenleyicileri Göster", "allEditorsPicker": "Açık Tüm Düzenleyicileri Göster", - "view": "Görüntüle" + "view": "Görüntüle", + "file": "Dosya" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index ea87cdb6229..38591433f64 100644 --- a/i18n/trk/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "'{0}' komutu şu an etkin değildir ve çalıştırılamaz.", "manageExtension": "Eklentiyi Yönet" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/trk/src/vs/workbench/electron-browser/main.contribution.i18n.json index efdf40af46b..947272ee097 100644 --- a/i18n/trk/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,18 +10,14 @@ "workspaces": "Çalışma Alanları", "developer": "Geliştirici", "showEditorTabs": "Açık düzenleyicilerin sekmelerde gösterilip gösterilmeyeceğini denetler", - "workbench.editor.labelFormat.default": "Dosyanın adını göster. Sekmeler etkinleştirilmiş ve bir grupta iki dosya aynı ada sahiplerse, her dosyanın yolundaki ayırt edici bölümler eklenir. Sekmeler devre dışı ve düzenleyici aktifse, çalışma alanı kök klasörüne göreli yol gösterilir.", "workbench.editor.labelFormat.short": "Dosyanın adını ve ardından dizin adını göster.", - "workbench.editor.labelFormat.medium": "Dosyanın adını ve ardından çalışma alanı kök klasörüne göreli yolunu göster.", "workbench.editor.labelFormat.long": "Dosyanın adını ve ardından mutlak yolunu göster.", "tabDescription": "Bir düzenleyici için etiketin biçimini denetler. Bu ayarı değiştirmek; örneğin, bir dosyanın konumunun daha kolay anlaşılmasını sağlar:\n- short: 'ustklasor'\n- medium: 'calismaalani/src/ustklasor'\n- long: '/home/user/calismaalani/src/ustklasor'\n- default: diğer bir sekme aynı başlığı paylaşıyorsa '.../ustklasor' veya sekmeler devre dışı ise göreli çalışma alanı yolu", "editorTabCloseButton": "Düzenleyici sekmelerinin kapat butonlarının konumunu denetler veya 'off' olarak ayarlandığında devre dışı bırakır.", "showIcons": "Açık düzenleyicilerin bir simge ile gösterilip gösterilmemelerini denetler. Bu, bir simge temasının etkinleştirilmesini de gerektirir.", "enablePreview": "Açık düzenleyicilerin önizleme olarak gösterilip gösterilmeyeceğini denetler. Önizleme düzenleyicileri kalıcı olarak açılana kadar (ör. çift tıklama veya düzenleme ile) tekrar kullanılırlar ve italik yazı tipiyle gösterilirler.", "enablePreviewFromQuickOpen": "Hızlı Aç'taki açık düzenleyicilerin önizleme olarak gösterilip gösterilmeyeceğini denetler. Önizleme düzenleyicileri kalıcı olarak açılana kadar (ör. çift tıklama veya düzenleme ile) tekrar kullanılırlar.", - "editorOpenPositioning": "Düzenleyicilerin nerede açılacağını denetler. Düzenleyicileri, geçerli olanın soluna veya sağına açmak için 'left' veya 'right' seçeneklerinden birini seçin. Düzenleyicileri, geçerli olandan bağımsız bir şekilde açmak için 'first' veya 'last' seçeneklerinden birini seçin.", "revealIfOpen": "Düzenleyicinin görünen gruplardan herhangi birinde açıldıysa ortaya çıkarılıp çıkarılmayacağını denetler. Devre dışı bırakılırsa; bir düzenleyici, o an aktif düzenleyici grubunda açılmayı tercih edecektir. Etkinleştirilirse; o an aktif düzenleyici grubunda tekrar açılmak yerine, zaten açık olan düzenleyici ortaya çıkarılacaktır. Bu ayarın yok sayılacağı bazı durumların olduğunu unutmayın, ör. bir düzenleyiciyi, belirli bir grupta veya o an aktif grubun yanına açmaya zorladığınızda. ", - "commandHistory": "Komut paleti geçmişinde tutulacak son kullanılan komutların sayısını denetler. Komut geçmişini kapatmak için 0 olarak ayarlayın.", "preserveInput": "Komut paletine son girilen girdinin, bir sonraki açılışta tekrar yer alıp almayacağını denetler.", "closeOnFocusLost": "Hızlı Aç'ın odağını kaybettiğinde otomatik olarak kapanıp kapanmayacağını denetler.", "openDefaultSettings": "Ayarları açmanın ayrıca tüm varsayılan ayarları gösteren bir düzenleyici açıp açmayacağını denetler.", @@ -50,7 +46,6 @@ "restoreWindows": "Pencerelerin, bir yeniden başlatma sonrası nasıl yeniden açılacağını denetler. Her zaman boş bir çalışma alanı ile başlamak için 'none', üzerinde çalıştığınız son pencereyi yeniden açmak için 'one', açık klasör bulunduran tüm pencereleri yeniden açmak için 'folders' veya son oturumunuzdaki tüm pencereleri yeniden açmak için 'all' seçeneğini seçin.", "restoreFullscreen": "Bir pencere tam ekran modundayken çıkıldıysa, bu pencerenin tam ekran moduna geri dönüp dönmeyeceğini denetler.", "zoomLevel": "Pencerenin yakınlaştırma düzeyini ayarlayın. Orijinal boyut 0'dır ve üstündeki (ör. 1) veya altındaki (ör. -1) her artırma 20% daha fazla veya az yakınlaştırmayı temsil eder. Yakınlaştırma düzeyini daha ince ayrıntılarla ayarlamak için ondalık değerler de girebilirsiniz.", - "title": "Pencere başlığını aktif düzenleyiciye bağlı olarak denetler. Değişkenler, bağlama göre değiştirilir:\n${activeEditorShort}: ör. myFile.txt\n${activeEditorMedium}: ör. myFolder/myFile.txt\n${activeEditorLong}: ör. /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: ör. myFolder\n${folderPath}: ör. /Users/Development/myFolder\n${rootName}: ör. myFolder1, myFolder2, myFolder3\n${rootPath}: ör. /Users/Development/myWorkspace\n${appName}: ör. VS Code\n${dirty}: etkin düzenleyici kaydedilmemiş değişiklikler içeriyorsa, değişiklik göstergesi\n${separator}: şartlı ayırıcı (\" - \") yalnızca değer içeren değişkenlerle çevrili olduğunda gösterilir", "window.newWindowDimensions.default": "Yeni pencereleri ekranın ortasında açın.", "window.newWindowDimensions.inherit": "Yeni pencereleri son aktif pencere ile aynı ölçülerde açın.", "window.newWindowDimensions.maximized": "Yeni pencereleri ekranı kapla modunda açın.", diff --git a/i18n/trk/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 6a22d71e97d..480910c4883 100644 --- a/i18n/trk/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, hata ayıklama", "debugAriaLabel": "Çalıştırılacak bir başlatma yapılandırması adı girin.", + "addConfigTo": "Yapılandırma Ekle ({0})...", + "addConfiguration": "Yapı&&landırma Ekle...", "noConfigurationsMatching": "Eşleyen hata ayıklama yapılandırması yok", "noConfigurationsFound": "Hiçbir hata ayıklama yapılandırması bulunamadı. Lütfen bir 'launch.json' dosyası oluşturun." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..5319c1251cb --- /dev/null +++ b/i18n/trk/src/vs/workbench/parts/debug/browser/debugStatus.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. +{ + "debug": "Hata Ayıklama" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/trk/src/vs/workbench/parts/debug/browser/debugViewlet.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/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 0fbc09f8cc1..ea94460b89a 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 @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "İlk 'launch.json' dosyasının üretimi için yapılandırmalar.", "vscode.extension.contributes.debuggers.languages": "Hata ayıklama eklentisinin, \"varsayılan hata ayıklayıcı\" olarak değerlendirilebileceği diller listesi.", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Belirtilirse; VS Code, hata ayıklama bağdaştırıcısı yürütülebilir dosyasının yolunu ve ona gönderilecek argümanları belirlemek için bu komutu çağırır.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Belirtilirse; VS Code, bu eklenti için hedeflenen \"hata ayıklama\" ve \"çalıştır\" eylemleri için bu komutu çağırır.", "vscode.extension.contributes.debuggers.configurationSnippets": "'launch.json' dosyasına yeni yapılandırmalar ekleme parçacıkları.", "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.", diff --git a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 25a3a60a2ae..8d0432122a3 100644 --- a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,10 +12,10 @@ "breakpointRemoved": "Kesme noktası kaldırıldı, {0}. satır, {1} dosyası", "compoundMustHaveConfigurations": "Bileşik, birden çok yapılandırmayı başlatmak için \"configurations\" özniteliği bulundurmalıdır.", "configMissing": "'launch.json' dosyasında '{0}' yapılandırması eksik.", - "debugRequestNotSupported": "Seçilen hata ayıklama yapılandırması desteklenmeyen öznitelik değeri `{0}` içeriyor: '{1}'.", - "debugRequesMissing": "'{0}' özniteliği seçilen hata ayıklama yapılandırılmasında eksik.", + "debugRequestNotSupported": "Seçilen hata ayıklama yapılandırılmasındaki `{0}` özniteliği desteklenmeyen `{1}` değeri içeriyor.", + "debugRequesMissing": "`{0}` özniteliği seçilen hata ayıklama yapılandırılmasında eksik.", "debugTypeNotSupported": "Yapılandırılan hata ayıklama türü '{0}', desteklenmiyor.", - "debugTypeMissing": "Seçilen başlatma yapılandırması için 'type' özelliği eksik.", + "debugTypeMissing": "Seçilen başlatma yapılandırmasında `type` özelliği eksik.", "preLaunchTaskErrors": "'{0}' ön başlatma görevi sırasında derleme hataları algılandı.", "preLaunchTaskError": "'{0}' ön başlatma görevi sırasında derleme hatası algılandı.", "preLaunchTaskExitCode": "'{0}' ön başlatma görevi {1} çıkış koduyla sonlandı.", diff --git a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 3ee7a241566..59b7c7fc1a3 100644 --- a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -7,6 +7,5 @@ "stateCapture": "Nesne durumu ilk değerlendirmeden alındı", "replVariableAriaLabel": "{0} değişkeni, {1} değerine sahip, oku değerlendir yaz döngüsü, hata ayıklama", "replExpressionAriaLabel": "{0} ifadesi, {1} değerine sahip, oku değerlendir yaz döngüsü, hata ayıklama", - "replValueOutputAriaLabel": "{0}, oku değerlendir yaz döngüsü, hata ayıklama", - "replKeyValueOutputAriaLabel": "{0} çıktı değişkeni, {1} değerine sahip, oku değerlendir yaz döngüsü, hata ayıklama" + "replValueOutputAriaLabel": "{0}, oku değerlendir yaz döngüsü, hata ayıklama" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index c907a874d19..09b50f5c819 100644 --- a/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "Dosyalar", + "filesCategory": "Dosya", "revealInSideBar": "Kenar Çubuğunda Ortaya Çıkar", "acceptLocalChanges": "Değişikliklerinizi kullanın ve diskteki içeriklerin üzerine yazın", "revertLocalChanges": "Değişikliklerinizi göz ardı edin ve diskteki içeriğe geri dönün" diff --git a/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 84098dc8d04..36b6a59d2b2 100644 --- a/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -37,8 +37,6 @@ "openToSide": "Yana Aç", "compareSource": "Karşılaştırma İçin Seç", "globalCompareFile": "Aktif Dosyayı Karşılaştır...", - "pickHistory": "Karşılaştırmak için daha önce açılan bir dosyayı seçin", - "unableToFileToCompare": "Seçtiğiniz dosya, '{0}' ile karşılaştırılamaz.", "openFileToCompare": "Bir başka dosya ile karşılaştırmak için ilk olarak bir dosya açın.", "compareWith": "'{0}' dosyasını '{1}' ile karşılaştır", "compareFiles": "Dosyaları Karşılaştır", @@ -47,7 +45,6 @@ "saveAs": "Farklı Kaydet...", "saveAll": "Tümünü Kaydet", "saveAllInGroup": "Gruptaki Tümünü Kadet", - "saveFiles": "Kaydedilmemiş Değişiklikler İçeren Dosyaları Kaydet", "revert": "Dosyayı Geri Döndür", "focusOpenEditors": "Açık Düzenleyiciler Görünümüne Odakla", "focusFilesExplorer": "Dosya Gezginine Odakla", diff --git a/i18n/trk/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/trk/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index d14973027f7..21fd7b44865 100644 --- a/i18n/trk/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,6 @@ { "noWorkspace": "Açık Klasör Yok", "explorerSection": "Dosya Gezgini Bölümü", - "noWorkspaceHelp": "Henüz bir klasör açmadınız.", + "noFolderHelp": "Henüz bir klasör açmadınız.", "openFolder": "Klasör Aç" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/trk/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..706a42a2e0d --- /dev/null +++ b/i18n/trk/src/vs/workbench/parts/markers/browser/markersFileDecorations.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. +{ + "label": "Sorunlar" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index 5992f38bfb5..f7b1f83c99e 100644 --- a/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "Varsayılan ayarların üzerine yazmak için ayarlarınızı buraya yerleştirin.", - "errorInvalidConfiguration": "Ayarlara yazılamıyor. Lütfen dosyadaki hataları/uyarıları düzeltin ve tekrar deneyin.", "emptyWorkspaceSettingsHeader": "Varsayılan kullanıcı ayarlarının üzerine yazmak için ayarlarınızı buraya yerleştirin.", "emptyFolderSettingsHeader": "Çalışma alanı ayarlarındakilerin üzerine yazmak için klasör ayarlarınızı buraya yerleştirin.", "defaultFolderSettingsTitle": "Varsayılan Klasör Ayarları", diff --git a/i18n/trk/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/trk/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index bef4db281ad..3164aed2f83 100644 --- a/i18n/trk/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "'{0}' komutu geçerli bağlamda etkin değil.", "recentlyUsed": "yakınlarda kullanıldı", "morecCommands": "diğer komutlar", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "Eşleşen komut yok" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index 803061b0af7..7c4f78fe197 100644 --- a/i18n/trk/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -17,7 +17,6 @@ "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.", "exclude.when": "Eşleşen bir dosyanın eşdüzey dosyalarında ek denetim. Eşleşen dosya adı için değişken olarak $(basename) kullanın.", - "useRipgrep": "Metin aramasında Ripgrep kullanılıp kullanılmayacağını denetler", "useIgnoreFilesByDefault": "Yeni bir çalışma alanında arama yaparken .gitignore ve .ignore dosyalarının varsayılan olarak kullanılıp kullanılmayacağını denetler.", "search.quickOpen.includeSymbols": "Dosya sonuçlarındaki bir global sembol aramasının sonuçlarının Hızlı Aç'a dahil edilip edilmeyeceğini yapılandırın." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/trk/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 0af6fe9976d..fb6486c2e36 100644 --- a/i18n/trk/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -19,7 +19,6 @@ "ClearSearchResultsAction.label": "Arama Sonuçlarını Temizle", "FocusNextSearchResult.label": "Sonraki Arama Sonucuna Odakla", "FocusPreviousSearchResult.label": "Önceki Arama Sonucuna Odakla", - "RemoveAction.label": "Kaldır", "file.replaceAll.label": "Tümünü Değiştir", "match.replace.label": "Değiştir" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 52c84a18c00..2f0e0bda449 100644 --- a/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,8 +10,8 @@ "vscode.extension.contributes.snippets": "Parçacıklara ekleme yapar.", "vscode.extension.contributes.snippets-language": "Bu parçacığın ekleneceği dilin tanımlayıcısı.", "vscode.extension.contributes.snippets-path": "Parçacıklar dosyasının yolu. Yol, eklenti klasörüne görecelidir ve genellikle './snippets/' ile başlar.", - "badFile": "Parçacık dosyası \"{0}\" okunamadı.", "badVariableUse": "\"{0}\"-parçacığı yüksek olasılıkla parçacık değişkenleri ile parçacık yer tutucularını karıştırıyor. Daha fazla bilgi için https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax adresini ziyaret edin.", + "badFile": "Parçacık dosyası \"{0}\" okunamadı.", "source.snippet": "Kullanıcı Parçacığı", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 8d8d4cb77d3..539713491df 100644 --- a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -16,7 +16,6 @@ "workbench.action.terminal.new.short": "Yeni Terminal", "workbench.action.terminal.focus": "Terminale Odakla", "workbench.action.terminal.focusNext": "Sonraki Terminale Odakla", - "workbench.action.terminal.focusAtIndex": "{0}. Terminale Odakla", "workbench.action.terminal.focusPrevious": "Önceki Terminale Odakla", "workbench.action.terminal.paste": "Aktif Terminale Yapıştır", "workbench.action.terminal.DefaultShell": "Varsayılan Kabuğu Seç", diff --git a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index be9f370adec..92d6df37712 100644 --- a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Kopyala", - "createNewTerminal": "Yeni Terminal", "paste": "Yapıştır", "selectAll": "Tümünü Seç", "clear": "Temizle" diff --git a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 28fa93d323a..a30794054e1 100644 --- a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "Tamam, Tekrar Gösterme", "terminal.integrated.chooseWindowsShell": "Tercih ettiğiniz terminal kabuğunu seçin, bunu daha sonra ayarlarınızdan değiştirebilirsiniz", "terminalService.terminalCloseConfirmationSingular": "Aktif bir terminal oturumu var, sonlandırmak istiyor musunuz?", - "terminalService.terminalCloseConfirmationPlural": "{0} aktif terminal oturumu var, bunları sonlandırmak istiyor musunuz?", - "yes": "Evet" + "terminalService.terminalCloseConfirmationPlural": "{0} aktif terminal oturumu var, bunları sonlandırmak istiyor musunuz?" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/trk/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..4c2ceda75b6 --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "Ayarların bir özeti. Bu etiket ayar dosyasında ayırıcı yorum olarak kullanılacaktır.", + "vscode.extension.contributes.configuration.properties": "Yapılandırma özelliklerinin açıklaması.", + "scope.window.description": "Kullanıcı veya çalışma alanında yapılandırılabilen Windows'a özel yapılandırma.", + "scope.resource.description": "Kullanıcı veya çalışma alanında yapılandırılabilen kaynağa özel yapılandırma.", + "scope.description": "Yapılandırmanın uygulanabilir olduğu kapsam. Mevcut kapsamlar 'window' ve 'resource'tır.", + "vscode.extension.contributes.configuration": "Yapılandırma ayarlarına ekleme yapar.", + "invalid.title": "'configuration.title' bir dize olmalıdır", + "vscode.extension.contributes.defaultConfiguration": "Varsayılan düzenleyici yapılandırma ayarlarına dil bazında ekleme yapar.", + "invalid.properties": "'configuration.properties' bir nesne olmalıdır", + "invalid.allOf": "'configuration.allOf' kullanım dışıdır ve artık kullanılmamalıdır. Bunun yerine, birden çok yapılandırma bölümlerini bir dizi olarak 'configuration' ekleme noktasına geçirin.", + "workspaceConfig.folders.description": "Çalışma alanına yüklenecek klasörler listesi.", + "workspaceConfig.path.description": "Bir dosya yolu. ör. `/root/folderA` veya çalışma alanı dosyasının konumuna karşı çözümlenecek göreceli bir yol için `./folderA`.", + "workspaceConfig.name.description": "Klasör için isteğe bağlı bir ad.", + "workspaceConfig.uri.description": "Klasörün URI'si", + "workspaceConfig.settings.description": "Çalışma alanı ayarları", + "workspaceConfig.extensions.description": "Çalışma alanı eklentileri", + "unknownWorkspaceProperty": "Bilinmeyen çalışma alanı yapılandırması özelliği" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/trk/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/editor/common/editorService.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. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/trk/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..ab403ef3493 --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.themes": "Textmate renk temalarına ekleme yapar.", + "vscode.extension.contributes.themes.id": "Kullanıcı ayarlarında kullanılan simge teması Id'si.", + "vscode.extension.contributes.themes.label": "Kullanıcı arayüzünde görünen renk temasının etiketi.", + "vscode.extension.contributes.themes.uiTheme": "Editördeki renkleri tanımlayan temel tema: 'vs' açık renk temasıdır, 'vs-dark' koyu renk temasıdır. 'hc-black' ise yüksek kontrast temasıdır.", + "vscode.extension.contributes.themes.path": "tmLanguage dosyasının yolu. Yol, eklenti klasörüne görecelidir ve genellikle './themes/themeFile.tmTheme'dir.", + "reqarray": "Eklenti noktası `{0}` bir dizi olmalıdır.", + "reqpath": "`contributes.{0}.path` ögesinde dize bekleniyor. Sağlanan değer: {1}", + "invalid.path.1": "`contributes.{0}.path` ögesinin ({1}) eklentinin klasöründe ({2}) yer alması bekleniyor. Bu, eklentiyi taşınamaz yapabilir." +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/trk/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..c7286a77b94 --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.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. +{ + "error.cannotparseicontheme": "Dosya simgeleri dosyasını ayrıştırma sorunları: {0}" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/trk/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..65e81b3fdbf --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * 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. +{ + "vscode.extension.contributes.iconThemes": "Dosya simgesi temalarına ekleme yapar.", + "vscode.extension.contributes.iconThemes.id": "Kullanıcı ayarlarında kullanılan simge teması Id'si.", + "vscode.extension.contributes.iconThemes.label": "Kullanıcı arayüzünde görünen simge temasının etiketi.", + "vscode.extension.contributes.iconThemes.path": "Simge teması tanımlama dosyasının yolu. Yol, eklenti klasörüne görecelidir ve genellikle './icons/awesome-icon-theme.json'dur.", + "reqarray": "Eklenti noktası `{0}` bir dizi olmalıdır.", + "reqpath": "`contributes.{0}.path` ögesinde dize bekleniyor. Sağlanan değer: {1}", + "reqid": "`contributes.{0}.id` ögesinde dize bekleniyordu. Belirtilen değer: {1}", + "invalid.path.1": "`contributes.{0}.path` ögesinin ({1}) eklentinin klasöründe ({2}) yer alması bekleniyor. Bu, eklentiyi taşınamaz yapabilir." +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/trk/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index 44429da31b5..6715de58332 100644 --- a/i18n/trk/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/trk/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,31 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Textmate renk temalarına ekleme yapar.", - "vscode.extension.contributes.themes.id": "Kullanıcı ayarlarında kullanılan simge teması Id'si.", - "vscode.extension.contributes.themes.label": "Kullanıcı arayüzünde görünen renk temasının etiketi.", - "vscode.extension.contributes.themes.uiTheme": "Editördeki renkleri tanımlayan temel tema: 'vs' açık renk temasıdır, 'vs-dark' koyu renk temasıdır. 'hc-black' ise yüksek kontrast temasıdır.", - "vscode.extension.contributes.themes.path": "tmLanguage dosyasının yolu. Yol, eklenti klasörüne görecelidir ve genellikle './themes/themeFile.tmTheme'dir.", - "vscode.extension.contributes.iconThemes": "Dosya simgesi temalarına ekleme yapar.", - "vscode.extension.contributes.iconThemes.id": "Kullanıcı ayarlarında kullanılan simge teması Id'si.", - "vscode.extension.contributes.iconThemes.label": "Kullanıcı arayüzünde görünen simge temasının etiketi.", - "vscode.extension.contributes.iconThemes.path": "Simge teması tanımlama dosyasının yolu. Yol, eklenti klasörüne görecelidir ve genellikle './icons/awesome-icon-theme.json'dur.", "migration.completed": "Yeni tema ayarları kullanıcı ayarlarına eklendi. Yedek, {0} konumunda mevcuttur.", "error.cannotloadtheme": "{0} yüklenemedi: {1}", - "reqarray": "Eklenti noktası `{0}` bir dizi olmalıdır.", - "reqpath": "`contributes.{0}.path` ögesinde dize bekleniyor. Sağlanan değer: {1}", - "invalid.path.1": "`contributes.{0}.path` ögesinin ({1}) eklentinin klasöründe ({2}) yer alması bekleniyor. Bu, eklentiyi taşınamaz yapabilir.", - "reqid": "`contributes.{0}.id` ögesinde dize bekleniyordu. Belirtilen değer: {1}", "error.cannotloadicontheme": "{0} yüklenemedi", - "error.cannotparseicontheme": "Dosya simgeleri dosyasını ayrıştırma sorunları: {0}", "colorTheme": "Çalışma ekranında kullanılan renk temasını belirtir.", "colorThemeError": "Tema bilinmiyor veya yüklenmemiş.", "iconTheme": "Çalışma ekranında kullanılan simge temasını veya hiçbir dosya simgesi göstermemek için 'null' belirtir.", "noIconThemeDesc": "Dosya simgesi yok", "iconThemeError": "Dosya simgesi teması bilinmiyor veya yüklenmemiş.", "workbenchColors": "Şu an seçili renk temasındaki renkleri geçersiz kılar.", - "workbenchColors.deprecated": "Ayar, artık deneysel değildir ve 'workbench.colorCustomizations' olarak yeniden adlandırılmıştır", - "workbenchColors.deprecatedDescription": "Bunun yerine 'workbench.colorCustomizations' kullanın", "editorColors": "Şu an seçili renk temasındaki düzenleyici renklerini ve yazı tipi stilini geçersiz kılar.", "editorColors.comments": "Yorumların rengini ve stillerini ayarlar", "editorColors.strings": "Dizelerin rengini ve stillerini ayarlar.", diff --git a/i18n/trk/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/trk/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..776050fe34c --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/workspace/node/workspaceEditingService.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. +{ + "openWorkspaceConfigurationFile": "Çalışma Alanı Yapılandırma Dosyasını Aç", + "close": "Kapat" +} \ No newline at end of file diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index ac4d08222c9..f855a4d012d 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -596,7 +596,7 @@ "xterm": { "version": "2.9.1", "from": "Tyriar/xterm.js#vscode-release/1.18", - "resolved": "git+https://github.com/Tyriar/xterm.js.git#d57ac8df05ddf04b509505eadc0d408a0b3bfa38" + "resolved": "git+https://github.com/Tyriar/xterm.js.git#80718295b8f73d809686741a251aa529317c1d35" }, "yauzl": { "version": "2.8.0", diff --git a/resources/linux/code.desktop b/resources/linux/code.desktop index 0048429416c..af3d2967d3d 100644 --- a/resources/linux/code.desktop +++ b/resources/linux/code.desktop @@ -9,19 +9,10 @@ StartupNotify=true StartupWMClass=@@NAME_SHORT@@ Categories=Utility;TextEditor;Development;IDE; MimeType=text/plain;inode/directory; -Actions=new-window; +Actions=new-empty-window; Keywords=vscode; -[Desktop Action new-window] -Name=New Window -Name[de]=Neues Fenster -Name[es]=Nueva ventana -Name[fr]=Nouvelle fenêtre -Name[it]=Nuova finestra -Name[ja]=新規ウインドウ -Name[ko]=새 창 -Name[ru]=Новое окно -Name[zh_CN]=新建窗口 -Name[zh_TW]=開新視窗 +[Desktop Action new-empty-window] +Name=New Empty Window Exec=/usr/share/@@NAME@@/@@NAME@@ --new-window %F Icon=@@NAME@@ diff --git a/src/typings/xterm.d.ts b/src/typings/xterm.d.ts index ceed656bf3f..40085d10893 100644 --- a/src/typings/xterm.d.ts +++ b/src/typings/xterm.d.ts @@ -7,166 +7,166 @@ * to be stable and consumed by external programs. */ -/** - * An object containing start up options for the terminal. - */ -interface ITerminalOptions { - /** - * A data uri of the sound to use for the bell (needs bellStyle = 'sound'). - */ - bellSound?: string; - - /** - * The type of the bell notification the terminal will use. - */ - bellStyle?: 'none' | 'visual' | 'sound' | 'both'; - - /** - * The number of columns in the terminal. - */ - cols?: number; - - /** - * Whether the cursor blinks. - */ - cursorBlink?: boolean; - - /** - * The style of the cursor. - */ - cursorStyle?: 'block' | 'underline' | 'bar'; - - /** - * Whether input should be disabled. - */ - disableStdin?: boolean; - - /** - * Whether to enable the rendering of bold text. - */ - enableBold?: boolean; - - /** - * The font size used to render text. - */ - fontSize?: number; - - /** - * The font family used to render text. - */ - fontFamily?: string; - - /** - * The line height used to render text. - */ - lineHeight?: number; - - /** - * The number of rows in the terminal. - */ - rows?: number; - - /** - * The amount of scrollback in the terminal. Scrollback is the amount of rows - * that are retained when lines are scrolled beyond the initial viewport. - */ - scrollback?: number; - - /** - * The size of tab stops in the terminal. - */ - tabStopWidth?: number; - - /** - * The color theme of the terminal. - */ - theme?: ITheme; -} - -/** - * Contains colors to theme the terminal with. - */ -interface ITheme { - /** The default foreground color */ - foreground?: string, - /** The default background color */ - background?: string, - /** The cursor color */ - cursor?: string, - /** The selection color (can be transparent) */ - selection?: string, - /** The accent color of the cursor (used as the foreground color for a block cursor) */ - cursorAccent?: string, - /** ANSI black (eg. `\x1b[30m`) */ - black?: string, - /** ANSI red (eg. `\x1b[31m`) */ - red?: string, - /** ANSI green (eg. `\x1b[32m`) */ - green?: string, - /** ANSI yellow (eg. `\x1b[33m`) */ - yellow?: string, - /** ANSI blue (eg. `\x1b[34m`) */ - blue?: string, - /** ANSI magenta (eg. `\x1b[35m`) */ - magenta?: string, - /** ANSI cyan (eg. `\x1b[36m`) */ - cyan?: string, - /** ANSI white (eg. `\x1b[37m`) */ - white?: string, - /** ANSI bright black (eg. `\x1b[1;30m`) */ - brightBlack?: string, - /** ANSI bright red (eg. `\x1b[1;31m`) */ - brightRed?: string, - /** ANSI bright green (eg. `\x1b[1;32m`) */ - brightGreen?: string, - /** ANSI bright yellow (eg. `\x1b[1;33m`) */ - brightYellow?: string, - /** ANSI bright blue (eg. `\x1b[1;34m`) */ - brightBlue?: string, - /** ANSI bright magenta (eg. `\x1b[1;35m`) */ - brightMagenta?: string, - /** ANSI bright cyan (eg. `\x1b[1;36m`) */ - brightCyan?: string, - /** ANSI bright white (eg. `\x1b[1;37m`) */ - brightWhite?: string -} - -/** - * An object containing options for a link matcher. - */ -interface ILinkMatcherOptions { - /** - * The index of the link from the regex.match(text) call. This defaults to 0 - * (for regular expressions without capture groups). - */ - matchIndex?: number; - - /** - * A callback that validates an individual link, returning true if valid and - * false if invalid. - */ - validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void; - - /** - * A callback that fires when the mouse hovers over a link for a moment. - */ - tooltipCallback?: (event: MouseEvent, uri: string) => boolean | void; - - /** - * A callback that fires when the mouse leaves a link. Note that this can - * happen even when tooltipCallback hasn't fired for the link yet. - */ - leaveCallback?: (event: MouseEvent, uri: string) => boolean | void; - - /** - * The priority of the link matcher, this defines the order in which the link - * matcher is evaluated relative to others, from highest to lowest. The - * default value is 0. - */ - priority?: number; -} - declare module 'xterm' { + /** + * An object containing start up options for the terminal. + */ + interface ITerminalOptions { + /** + * A data uri of the sound to use for the bell (needs bellStyle = 'sound'). + */ + bellSound?: string; + + /** + * The type of the bell notification the terminal will use. + */ + bellStyle?: 'none' | 'visual' | 'sound' | 'both'; + + /** + * The number of columns in the terminal. + */ + cols?: number; + + /** + * Whether the cursor blinks. + */ + cursorBlink?: boolean; + + /** + * The style of the cursor. + */ + cursorStyle?: 'block' | 'underline' | 'bar'; + + /** + * Whether input should be disabled. + */ + disableStdin?: boolean; + + /** + * Whether to enable the rendering of bold text. + */ + enableBold?: boolean; + + /** + * The font size used to render text. + */ + fontSize?: number; + + /** + * The font family used to render text. + */ + fontFamily?: string; + + /** + * The line height used to render text. + */ + lineHeight?: number; + + /** + * The number of rows in the terminal. + */ + rows?: number; + + /** + * The amount of scrollback in the terminal. Scrollback is the amount of rows + * that are retained when lines are scrolled beyond the initial viewport. + */ + scrollback?: number; + + /** + * The size of tab stops in the terminal. + */ + tabStopWidth?: number; + + /** + * The color theme of the terminal. + */ + theme?: ITheme; + } + + /** + * Contains colors to theme the terminal with. + */ + interface ITheme { + /** The default foreground color */ + foreground?: string, + /** The default background color */ + background?: string, + /** The cursor color */ + cursor?: string, + /** The selection color (can be transparent) */ + selection?: string, + /** The accent color of the cursor (used as the foreground color for a block cursor) */ + cursorAccent?: string, + /** ANSI black (eg. `\x1b[30m`) */ + black?: string, + /** ANSI red (eg. `\x1b[31m`) */ + red?: string, + /** ANSI green (eg. `\x1b[32m`) */ + green?: string, + /** ANSI yellow (eg. `\x1b[33m`) */ + yellow?: string, + /** ANSI blue (eg. `\x1b[34m`) */ + blue?: string, + /** ANSI magenta (eg. `\x1b[35m`) */ + magenta?: string, + /** ANSI cyan (eg. `\x1b[36m`) */ + cyan?: string, + /** ANSI white (eg. `\x1b[37m`) */ + white?: string, + /** ANSI bright black (eg. `\x1b[1;30m`) */ + brightBlack?: string, + /** ANSI bright red (eg. `\x1b[1;31m`) */ + brightRed?: string, + /** ANSI bright green (eg. `\x1b[1;32m`) */ + brightGreen?: string, + /** ANSI bright yellow (eg. `\x1b[1;33m`) */ + brightYellow?: string, + /** ANSI bright blue (eg. `\x1b[1;34m`) */ + brightBlue?: string, + /** ANSI bright magenta (eg. `\x1b[1;35m`) */ + brightMagenta?: string, + /** ANSI bright cyan (eg. `\x1b[1;36m`) */ + brightCyan?: string, + /** ANSI bright white (eg. `\x1b[1;37m`) */ + brightWhite?: string + } + + /** + * An object containing options for a link matcher. + */ + interface ILinkMatcherOptions { + /** + * The index of the link from the regex.match(text) call. This defaults to 0 + * (for regular expressions without capture groups). + */ + matchIndex?: number; + + /** + * A callback that validates an individual link, returning true if valid and + * false if invalid. + */ + validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void; + + /** + * A callback that fires when the mouse hovers over a link for a moment. + */ + tooltipCallback?: (event: MouseEvent, uri: string) => boolean | void; + + /** + * A callback that fires when the mouse leaves a link. Note that this can + * happen even when tooltipCallback hasn't fired for the link yet. + */ + leaveCallback?: (event: MouseEvent, uri: string) => boolean | void; + + /** + * The priority of the link matcher, this defines the order in which the link + * matcher is evaluated relative to others, from highest to lowest. The + * default value is 0. + */ + priority?: number; + } + /** * The class that represents an xterm.js terminal. */ diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index d0dfb1d885c..b8af134f20e 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import * as platform from 'vs/base/common/platform'; import { TPromise } from 'vs/base/common/winjs.base'; import { TimeoutTimer } from 'vs/base/common/async'; import { onUnexpectedError } from 'vs/base/common/errors'; @@ -1054,3 +1055,23 @@ export function computeScreenAwareSize(cssPx: number): number { const screenPx = window.devicePixelRatio * cssPx; return Math.max(1, Math.floor(screenPx)) / window.devicePixelRatio; } + +/** + * See https://github.com/Microsoft/monaco-editor/issues/601 + * To protect against malicious code in the linked site, particularly phishing attempts, + * the window.opener should be set to null to prevent the linked site from having access + * to change the location of the current page. + * See https://mathiasbynens.github.io/rel-noopener/ + */ +export function windowOpenNoOpener(url: string): void { + if (platform.isNative) { + // In VSCode, window.open() always returns null... + window.open(url); + } else { + let newTab = window.open(); + if (newTab) { + newTab.opener = null; + newTab.location.href = url; + } + } +} diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts index 10144ee2c71..86b39b2e234 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.ts +++ b/src/vs/base/browser/ui/checkbox/checkbox.ts @@ -73,6 +73,10 @@ export class Checkbox extends Widget { }); } + public get enabled(): boolean { + return this.domNode.getAttribute('aria-disabled') !== 'true'; + } + public focus(): void { this.domNode.focus(); } diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index 89dac41da35..60dec0ac2a3 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -28,7 +28,6 @@ export interface IIconLabelOptions { extraClasses?: string[]; italic?: boolean; matches?: IMatch[]; - badge?: ILabelBadgeOptions; } class FastLabelNode { @@ -90,18 +89,19 @@ export class IconLabel { private domNode: FastLabelNode; private labelNode: FastLabelNode | HighlightedLabel; private descriptionNode: FastLabelNode; - private badgeNode: HTMLSpanElement; constructor(container: HTMLElement, options?: IIconLabelCreationOptions) { this.domNode = new FastLabelNode(dom.append(container, dom.$('.monaco-icon-label'))); + const labelDescriptionContainer = new FastLabelNode(dom.append(this.domNode.element, dom.$('.monaco-icon-label-description-container'))); + if (options && options.supportHighlights) { - this.labelNode = new HighlightedLabel(dom.append(this.domNode.element, dom.$('a.label-name'))); + this.labelNode = new HighlightedLabel(dom.append(labelDescriptionContainer.element, dom.$('a.label-name'))); } else { - this.labelNode = new FastLabelNode(dom.append(this.domNode.element, dom.$('a.label-name'))); + this.labelNode = new FastLabelNode(dom.append(labelDescriptionContainer.element, dom.$('a.label-name'))); } - this.descriptionNode = new FastLabelNode(dom.append(this.domNode.element, dom.$('span.label-description'))); + this.descriptionNode = new FastLabelNode(dom.append(labelDescriptionContainer.element, dom.$('span.label-description'))); } public get element(): HTMLElement { @@ -148,20 +148,6 @@ export class IconLabel { this.descriptionNode.textContent = description || ''; this.descriptionNode.empty = !description; - - if (options && options.badge) { - if (!this.badgeNode) { - this.badgeNode = document.createElement('span'); - this.element.style.display = 'flex'; - this.element.appendChild(this.badgeNode); - } - this.badgeNode.title = options.badge.title; - this.badgeNode.className = `label-badge ${options.badge.className}`; - dom.show(this.badgeNode); - - } else if (this.badgeNode) { - dom.hide(this.badgeNode); - } } public dispose(): void { diff --git a/src/vs/base/browser/ui/iconLabel/iconlabel.css b/src/vs/base/browser/ui/iconLabel/iconlabel.css index 259040da2c2..6e6a73fb542 100644 --- a/src/vs/base/browser/ui/iconLabel/iconlabel.css +++ b/src/vs/base/browser/ui/iconLabel/iconlabel.css @@ -6,7 +6,7 @@ /* ---------- Icon label ---------- */ .monaco-icon-label { - display: inline-block; /* required for icons support :before rule */ + display: flex; /* required for icons support :before rule */ overflow: hidden; text-overflow: ellipsis; } @@ -25,34 +25,46 @@ /* fonts icons */ -webkit-font-smoothing: antialiased; vertical-align: top; + + flex-shrink: 0; /* fix for https://github.com/Microsoft/vscode/issues/13787 */ } -.monaco-icon-label > .label-name { +.monaco-icon-label > .monaco-icon-label-description-container { + overflow: hidden; /* this causes the label/description to shrink first if decorations are enabled */ + text-overflow: ellipsis; +} + +.monaco-icon-label > .monaco-icon-label-description-container > .label-name { color: inherit; white-space: pre; /* enable to show labels that include multiple whitespaces */ } -.monaco-icon-label > .label-description { +.monaco-icon-label > .monaco-icon-label-description-container > .label-description { opacity: 0.7; margin-left: 0.5em; font-size: 0.9em; white-space: pre; /* enable to show labels that include multiple whitespaces */ } -.monaco-icon-label.italic > .label-name, -.monaco-icon-label.italic > .label-description { +.monaco-icon-label.italic > .monaco-icon-label-description-container > .label-name, +.monaco-icon-label.italic > .monaco-icon-label-description-container > .label-description { font-style: italic; } -.monaco-icon-label > .label-badge { - align-self: center; - height: 12px; - min-width: 10px; - line-height: 125%; - font-size: 80%; - margin: 1px 15px 1px auto; - padding: 2px 3px; - border-radius: 5px; - font-weight: normal; +.monaco-icon-label::after { + opacity: 0.75; + font-size: 90%; + font-weight: 600; + padding: 0 12px 0 5px; + margin-left: auto; text-align: center; } + +/* make sure selection color wins when a label is being selected */ +.monaco-tree.focused .selected .monaco-icon-label, /* tree */ +.monaco-tree.focused .selected .monaco-icon-label::after, +.monaco-list:focus .focused.selected .monaco-icon-label, /* list */ +.monaco-list:focus .focused.selected .monaco-icon-label::after +{ + color: inherit !important; +} diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 4168b8c4977..360d0f4afdb 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -14,7 +14,7 @@ import * as platform from 'vs/base/common/platform'; import { EventType as TouchEventType } from 'vs/base/browser/touch'; import { KeyCode } from 'vs/base/common/keyCodes'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import Event, { Emitter, EventBufferer, chain, mapEvent, fromCallback, any } from 'vs/base/common/event'; +import Event, { Emitter, EventBufferer, chain, mapEvent, fromCallback, anyEvent } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; import { IDelegate, IRenderer, IListEvent, IListMouseEvent, IListContextMenuEvent } from './list'; import { ListView, IListViewOptions } from './listView'; @@ -347,7 +347,7 @@ class MouseController implements IDisposable { .map(({ element, index, clientX, clientY }) => ({ element, index, anchor: { x: clientX + 1, y: clientY } })) .event; - return any>(fromKeyboard, fromMouse); + return anyEvent>(fromKeyboard, fromMouse); } constructor( diff --git a/src/vs/base/browser/ui/splitview/panelview.ts b/src/vs/base/browser/ui/splitview/panelview.ts index 7d7caf121cd..68cb92ea81f 100644 --- a/src/vs/base/browser/ui/splitview/panelview.ts +++ b/src/vs/base/browser/ui/splitview/panelview.ts @@ -336,10 +336,13 @@ export class PanelView implements IDisposable { private _onDidDrop = new Emitter<{ from: Panel, to: Panel }>(); readonly onDidDrop: Event<{ from: Panel, to: Panel }> = this._onDidDrop.event; + readonly onDidSashChange: Event; + constructor(private container: HTMLElement, options: IPanelViewOptions = {}) { this.dnd = !!options.dnd; this.el = append(container, $('.monaco-panel-view')); this.splitview = new SplitView(this.el); + this.onDidSashChange = this.splitview.onDidSashChange; } addPanel(panel: Panel, size: number, index = this.splitview.length): void { diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index b90401d437f..5a94710ca9c 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -7,7 +7,7 @@ import 'vs/css!./splitview'; import { IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import Event, { fromEventEmitter, mapEvent } from 'vs/base/common/event'; +import Event, { fromEventEmitter, mapEvent, Emitter } from 'vs/base/common/event'; import types = require('vs/base/common/types'); import dom = require('vs/base/browser/dom'); import { clamp } from 'vs/base/common/numbers'; @@ -70,6 +70,9 @@ export class SplitView implements IDisposable { private sashDragState: ISashDragState; private state: State = State.Idle; + private _onDidSashChange = new Emitter(); + readonly onDidSashChange = this._onDidSashChange.event; + get length(): number { return this.viewItems.length; } @@ -129,7 +132,10 @@ export class SplitView implements IDisposable { const onStartDisposable = onStart(this.onSashStart, this); const onChange = mapEvent(fromEventEmitter(sash, 'change'), sashEventMapper); const onSashChangeDisposable = onChange(this.onSashChange, this); - const disposable = combinedDisposable([onStartDisposable, onSashChangeDisposable, sash]); + const onEnd = mapEvent(fromEventEmitter(sash, 'end'), () => null); + const onEndDisposable = onEnd(() => this._onDidSashChange.fire()); + + const disposable = combinedDisposable([onStartDisposable, onSashChangeDisposable, onEndDisposable, sash]); const sashItem: ISashItem = { sash, disposable }; this.sashItems.splice(index - 1, 0, sashItem); diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 19ad6dd8657..387ea5055cb 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -304,7 +304,7 @@ export function once(event: Event): Event { }; } -export function any(...events: Event[]): Event { +export function anyEvent(...events: Event[]): Event { return (listener, thisArgs = null, disposables?) => combinedDisposable(events.map(event => event(e => listener.call(thisArgs, e), null, disposables))); } diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index a943fc15c03..64abb96b9ad 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -421,7 +421,7 @@ function printTable(table: number[][], pattern: string, patternLen: number, word return ret; } -export function isSeparatorAtPos(value: string, index: number): boolean { +function isSeparatorAtPos(value: string, index: number): boolean { if (index < 0 || index >= value.length) { return false; } diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index 93de044478a..c88cdaf8bec 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -38,5 +38,7 @@ export namespace Schemas { export const file: string = 'file'; + export const mailto: string = 'mailto'; + export const untitled: string = 'untitled'; } diff --git a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts index 7667f60d43d..5636beb5f50 100644 --- a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts +++ b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts @@ -6,10 +6,11 @@ 'use strict'; import { compareAnything } from 'vs/base/common/comparers'; -import { matchesPrefix, IMatch, createMatches, matchesCamelCase, isSeparatorAtPos, isUpper } from 'vs/base/common/filters'; +import { matchesPrefix, IMatch, createMatches, matchesCamelCase, isUpper } from 'vs/base/common/filters'; import { isEqual, nativeSep } from 'vs/base/common/paths'; import { isWindows } from 'vs/base/common/platform'; import { stripWildcards } from 'vs/base/common/strings'; +import { CharCode } from 'vs/base/common/charCode'; export type Score = [number /* score */, number[] /* match positions */]; export type ScorerCache = { [key: string]: IItemScore }; @@ -189,22 +190,26 @@ function computeCharScore(query: string, queryLower: string, queryIndex: number, // } } - // After separator bonus - else if (isSeparatorAtPos(target, targetIndex - 1)) { - score += 4; + else { - // if (DEBUG) { - // console.log('After separtor bonus: +4'); - // } - } + // After separator bonus + const separatorBonus = scoreSeparatorAtPos(target.charCodeAt(targetIndex - 1)); + if (separatorBonus) { + score += separatorBonus; - // Inside word upper case bonus - else if (isUpper(target.charCodeAt(targetIndex))) { - score += 1; + // if (DEBUG) { + // console.log('After separtor bonus: +4'); + // } + } - // if (DEBUG) { - // console.log('Inside word upper case bonus: +1'); - // } + // Inside word upper case bonus (camel case) + else if (isUpper(target.charCodeAt(targetIndex))) { + score += 1; + + // if (DEBUG) { + // console.log('Inside word upper case bonus: +1'); + // } + } } // if (DEBUG) { @@ -214,6 +219,24 @@ function computeCharScore(query: string, queryLower: string, queryIndex: number, return score; } +function scoreSeparatorAtPos(charCode: number): number { + switch (charCode) { + case CharCode.Slash: + case CharCode.Backslash: + return 5; // prefer path separators... + case CharCode.Underline: + case CharCode.Dash: + case CharCode.Period: + case CharCode.Space: + case CharCode.SingleQuote: + case CharCode.DoubleQuote: + case CharCode.Colon: + return 4; // ...over other separators + default: + return 0; + } +} + // function printMatrix(query: string, target: string, matches: number[], scores: number[]): void { // console.log('\t' + target.split('').join('\t')); // for (let queryIndex = 0; queryIndex < query.length; queryIndex++) { diff --git a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts index b8b1fc11ca9..9710b98a982 100644 --- a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts +++ b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts @@ -663,6 +663,84 @@ suite('Quick Open Scorer', () => { assert.equal(res[2], resourceB); }); + test('compareFilesByScore - avoid match scattering (bug #14879)', function () { + const resourceA = URI.file('pkg/search/gradient/testdata/constraint_attrMatchString.yml'); + const resourceB = URI.file('cmd/gradient/main.go'); + + let query = 'gradientmain'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #14727 1)', function () { + const resourceA = URI.file('alpha-beta-cappa.txt'); + const resourceB = URI.file('abc.txt'); + + let query = 'abc'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #14727 2)', function () { + const resourceA = URI.file('xerxes-yak-zubba/index.js'); + const resourceB = URI.file('xyz/index.js'); + + let query = 'xyz'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #18381)', function () { + const resourceA = URI.file('AssymblyInfo.cs'); + const resourceB = URI.file('IAsynchronousTask.java'); + + let query = 'async'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #35572)', function () { + const resourceA = URI.file('static/app/source/angluar/-admin/-organization/-settings/layout/layout.js'); + const resourceB = URI.file('static/app/source/angular/-admin/-project/-settings/_settings/settings.js'); + + let query = 'partisettings'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #36810)', function () { + const resourceA = URI.file('Trilby.TrilbyTV.Web.Portal/Views/Systems/Index.cshtml'); + const resourceB = URI.file('Trilby.TrilbyTV.Web.Portal/Areas/Admins/Views/Tips/Index.cshtml'); + + let query = 'tipsindex.cshtml'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + test('compareFilesByScore - prefer shorter hit (bug #20546)', function () { const resourceA = URI.file('editor/core/components/tests/list-view-spec.js'); const resourceB = URI.file('editor/core/components/list-view.js'); diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 18e32ff6fd4..fb916b8f73d 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -356,9 +356,26 @@ export class CodeMenu { newFile = this.createMenuItem(nls.localize({ key: 'miNewFile', comment: ['&& denotes a mnemonic'] }, "&&New File"), 'workbench.action.files.newUntitledFile'); } - const open = new MenuItem(this.likeAction('workbench.action.files.openFileFolder', { label: this.mnemonicLabel(nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open...")), click: (menuItem, win, event) => this.windowsService.pickFileFolderAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) })); - const openWorkspace = new MenuItem(this.likeAction('workbench.action.openWorkspace', { label: this.mnemonicLabel(nls.localize({ key: 'miOpenWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open Workspace...")), click: () => this.windowsService.openWorkspace() })); - const openFolder = new MenuItem(this.likeAction('workbench.action.files.openFolder', { label: this.mnemonicLabel(nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder...")), click: (menuItem, win, event) => this.windowsService.pickFolderAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) })); + let open: Electron.MenuItem; + if (hasNoWindows) { + open = new MenuItem(this.likeAction('workbench.action.files.openFileFolder', { label: this.mnemonicLabel(nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open...")), click: (menuItem, win, event) => this.windowsService.pickFileFolderAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) })); + } else { + open = this.createMenuItem(nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open..."), ['workbench.action.files.openFileFolder', 'workbench.action.files.openFileFolderInNewWindow']); + } + + let openWorkspace: Electron.MenuItem; + if (hasNoWindows) { + openWorkspace = new MenuItem(this.likeAction('workbench.action.openWorkspace', { label: this.mnemonicLabel(nls.localize({ key: 'miOpenWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open Workspace...")), click: (menuItem, win, event) => this.windowsService.pickWorkspaceAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) })); + } else { + openWorkspace = this.createMenuItem(nls.localize({ key: 'miOpenWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open Workspace..."), ['workbench.action.openWorkspace', 'workbench.action.openWorkspaceInNewWindow']); + } + + let openFolder: Electron.MenuItem; + if (hasNoWindows) { + openFolder = new MenuItem(this.likeAction('workbench.action.files.openFolder', { label: this.mnemonicLabel(nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder...")), click: (menuItem, win, event) => this.windowsService.pickFolderAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) })); + } else { + openFolder = this.createMenuItem(nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder..."), ['workbench.action.files.openFolder', 'workbench.action.files.openFolderInNewWindow']); + } let openFile: Electron.MenuItem; if (hasNoWindows) { diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 0698760579e..346c0c37f22 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -1339,8 +1339,8 @@ export class WindowsManager implements IWindowsMainService { return result; } - public openWorkspace(win?: CodeWindow): void { - this.workspacesManager.openWorkspace(win); + public pickWorkspaceAndOpen(options: INativeOpenDialogOptions): void { + this.workspacesManager.pickWorkspaceAndOpen(options); } private onBeforeWindowUnload(e: IWindowUnloadEvent): void { @@ -1618,7 +1618,7 @@ class FileDialog { }); } - public getFileOrFolderPaths(options: IInternalNativeOpenDialogOptions, clb: (paths: string[]) => void): void { + private getFileOrFolderPaths(options: IInternalNativeOpenDialogOptions, clb: (paths: string[]) => void): void { // Ensure dialog options if (!options.dialogOptions) { @@ -1755,13 +1755,8 @@ class WorkspacesManager { }); } - public openWorkspace(window = this.windowsMainService.getLastActiveWindow()): void { - let defaultPath: string; - if (window && window.openedWorkspace && !this.workspacesService.isUntitledWorkspace(window.openedWorkspace)) { - defaultPath = dirname(window.openedWorkspace.configPath); - } else { - defaultPath = this.getWorkspaceDialogDefaultPath(window ? (window.openedWorkspace || window.openedFolderPath) : void 0); - } + public pickWorkspaceAndOpen(options: INativeOpenDialogOptions): void { + const window = this.windowsMainService.getWindowById(options.windowId) || this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow(); this.windowsMainService.pickFileAndOpen({ windowId: window ? window.id : void 0, @@ -1770,8 +1765,11 @@ class WorkspacesManager { title: localize('openWorkspaceTitle', "Open Workspace"), filters: WORKSPACE_FILTER, properties: ['openFile'], - defaultPath - } + defaultPath: options.dialogOptions && options.dialogOptions.defaultPath + }, + forceNewWindow: options.forceNewWindow, + telemetryEventName: options.telemetryEventName, + telemetryExtraData: options.telemetryExtraData }); } @@ -1830,7 +1828,7 @@ class WorkspacesManager { buttonLabel: mnemonicButtonLabel(localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save")), title: localize('saveWorkspace', "Save Workspace"), filters: WORKSPACE_FILTER, - defaultPath: this.getWorkspaceDialogDefaultPath(workspace) + defaultPath: this.getUntitledWorkspaceSaveDialogDefaultPath(workspace) }); if (target) { @@ -1846,7 +1844,7 @@ class WorkspacesManager { } } - private getWorkspaceDialogDefaultPath(workspace?: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): string { + private getUntitledWorkspaceSaveDialogDefaultPath(workspace?: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): string { if (workspace) { if (isSingleFolderWorkspaceIdentifier(workspace)) { return dirname(workspace); @@ -1861,6 +1859,7 @@ class WorkspacesManager { } } } + return void 0; } } diff --git a/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts b/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts index b50adb24b77..43fe27b0d1c 100644 --- a/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts +++ b/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts @@ -96,10 +96,12 @@ export class IndentGuidesOverlay extends DynamicViewOverlay { const lineHeight = this._lineHeight; const indentGuideWidth = dom.computeScreenAwareSize(1); + const indents = this._context.model.getLinesIndentGuides(visibleStartLineNumber, visibleEndLineNumber); + let output: string[] = []; for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) { - let lineIndex = lineNumber - visibleStartLineNumber; - let indent = this._context.model.getLineIndentGuide(lineNumber); + const lineIndex = lineNumber - visibleStartLineNumber; + const indent = indents[lineIndex]; let result = ''; let leftMostVisiblePosition = ctx.visibleRangeForPosition(new Position(lineNumber, 1)); diff --git a/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts index 37625d0dbaf..a188e564ffa 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLine.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLine.ts @@ -15,9 +15,8 @@ import { IVisibleLine } from 'vs/editor/browser/view/viewLayer'; import { RangeUtil } from 'vs/editor/browser/viewParts/lines/rangeUtil'; import { HorizontalRange } from 'vs/editor/common/view/renderingContext'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; -import { ITheme } from 'vs/platform/theme/common/themeService'; +import { ThemeType, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService'; import { IStringBuilder } from 'vs/editor/common/core/stringBuilder'; -import { editorSelectionForeground } from 'vs/platform/theme/common/colorRegistry'; const canUseFastRenderedViewLine = (function () { if (platform.isNative) { @@ -70,7 +69,7 @@ export class DomReadingContext { } export class ViewLineOptions { - public readonly useSelectionForegroundColor: boolean; + public readonly themeType: ThemeType; public readonly renderWhitespace: 'none' | 'boundary' | 'all'; public readonly renderControlCharacters: boolean; public readonly spaceWidth: number; @@ -79,8 +78,8 @@ export class ViewLineOptions { public readonly stopRenderingLineAfter: number; public readonly fontLigatures: boolean; - constructor(config: IConfiguration, theme: ITheme) { - this.useSelectionForegroundColor = !!theme.getColor(editorSelectionForeground); + constructor(config: IConfiguration, themeType: ThemeType) { + this.themeType = themeType; this.renderWhitespace = config.editor.viewInfo.renderWhitespace; this.renderControlCharacters = config.editor.viewInfo.renderControlCharacters; this.spaceWidth = config.editor.fontInfo.spaceWidth; @@ -95,7 +94,7 @@ export class ViewLineOptions { public equals(other: ViewLineOptions): boolean { return ( - this.useSelectionForegroundColor === other.useSelectionForegroundColor + this.themeType === other.themeType && this.renderWhitespace === other.renderWhitespace && this.renderControlCharacters === other.renderControlCharacters && this.spaceWidth === other.spaceWidth @@ -151,7 +150,7 @@ export class ViewLine implements IVisibleLine { this._options = newOptions; } public onSelectionChanged(): boolean { - if (alwaysRenderInlineSelection || this._options.useSelectionForegroundColor) { + if (alwaysRenderInlineSelection || this._options.themeType === HIGH_CONTRAST) { this._isMaybeInvalid = true; return true; } @@ -170,7 +169,7 @@ export class ViewLine implements IVisibleLine { const options = this._options; const actualInlineDecorations = LineDecoration.filter(lineData.inlineDecorations, lineNumber, lineData.minColumn, lineData.maxColumn); - if (alwaysRenderInlineSelection || options.useSelectionForegroundColor) { + if (alwaysRenderInlineSelection || options.themeType === HIGH_CONTRAST) { const selections = viewportData.selections; for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; @@ -398,7 +397,7 @@ class RenderedViewLine implements IRenderedViewLine { this._pixelOffsetCache = null; if (!containsRTL || this._characterMapping.length === 0 /* the line is empty */) { - this._pixelOffsetCache = new Int32Array(this._characterMapping.length + 1); + this._pixelOffsetCache = new Int32Array(Math.max(2, this._characterMapping.length + 1)); for (let column = 0, len = this._characterMapping.length; column <= len; column++) { this._pixelOffsetCache[column] = -1; } diff --git a/src/vs/editor/browser/viewParts/lines/viewLines.ts b/src/vs/editor/browser/viewParts/lines/viewLines.ts index 9c873fa9496..1979f4da935 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLines.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLines.ts @@ -96,7 +96,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, this._isViewportWrapping = conf.editor.wrappingInfo.isViewportWrapping; this._revealHorizontalRightPadding = conf.editor.viewInfo.revealHorizontalRightPadding; this._canUseLayerHinting = conf.editor.canUseLayerHinting; - this._viewLineOptions = new ViewLineOptions(conf, this._context.theme); + this._viewLineOptions = new ViewLineOptions(conf, this._context.theme.type); PartFingerprints.write(this.domNode, PartFingerprint.ViewLines); this.domNode.setClassName('view-lines'); @@ -170,7 +170,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, private _onOptionsMaybeChanged(): boolean { const conf = this._context.configuration; - let newViewLineOptions = new ViewLineOptions(conf, this._context.theme); + let newViewLineOptions = new ViewLineOptions(conf, this._context.theme.type); if (!this._viewLineOptions.equals(newViewLineOptions)) { this._viewLineOptions = newViewLineOptions; @@ -551,17 +551,17 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, } } - // (3) handle scrolling - this._linesContent.setLayerHinting(this._canUseLayerHinting); - const adjustedScrollTop = this._context.viewLayout.getCurrentScrollTop() - viewportData.bigNumbersDelta; - this._linesContent.setTop(-adjustedScrollTop); - this._linesContent.setLeft(-this._context.viewLayout.getCurrentScrollLeft()); - // Update max line width (not so important, it is just so the horizontal scrollbar doesn't get too small) if (!this._updateLineWidthsFast()) { // Computing the width of some lines would be slow => delay it this._asyncUpdateLineWidths.schedule(); } + + // (3) handle scrolling + this._linesContent.setLayerHinting(this._canUseLayerHinting); + const adjustedScrollTop = this._context.viewLayout.getCurrentScrollTop() - viewportData.bigNumbersDelta; + this._linesContent.setTop(-adjustedScrollTop); + this._linesContent.setLeft(-this._context.viewLayout.getCurrentScrollLeft()); } // --- width diff --git a/src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts b/src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts index 0b7a9454170..20fbcbea5ac 100644 --- a/src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts +++ b/src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts @@ -15,13 +15,15 @@ export class TrimTrailingWhitespaceCommand implements editorCommon.ICommand { private selection: Selection; private selectionId: string; + private cursors: Position[]; - constructor(selection: Selection) { + constructor(selection: Selection, cursors: Position[]) { this.selection = selection; + this.cursors = cursors; } public getEditOperations(model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder): void { - let ops = trimTrailingWhitespace(model, []); + let ops = trimTrailingWhitespace(model, this.cursors); for (let i = 0, len = ops.length; i < len; i++) { let op = ops[i]; diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 30c49a81d5a..ebb78f046b7 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -1715,7 +1715,7 @@ export class InternalEditorOptionsFactory { wordWrapBreakBeforeCharacters: opts.wordWrapBreakBeforeCharacters, wordWrapBreakAfterCharacters: opts.wordWrapBreakAfterCharacters, wordWrapBreakObtrusiveCharacters: opts.wordWrapBreakObtrusiveCharacters, - autoClosingBrackets: (accessibilityIsOn ? false : opts.autoClosingBrackets), // DISABLED WHEN SCREEN READER IS ATTACHED + autoClosingBrackets: opts.autoClosingBrackets, autoIndent: opts.autoIndent, dragAndDrop: opts.dragAndDrop, emptySelectionClipboard: opts.emptySelectionClipboard, diff --git a/src/vs/editor/common/controller/coreCommands.ts b/src/vs/editor/common/controller/coreCommands.ts index cefe9d0d216..33661420850 100644 --- a/src/vs/editor/common/controller/coreCommands.ts +++ b/src/vs/editor/common/controller/coreCommands.ts @@ -8,7 +8,7 @@ import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { CursorState, ICursors, RevealTarget, IColumnSelectData, CursorContext } from 'vs/editor/common/controller/cursorCommon'; +import { CursorState, ICursors, RevealTarget, IColumnSelectData, CursorContext, EditOperationType } from 'vs/editor/common/controller/cursorCommon'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; import { CursorMoveCommands, CursorMove as CursorMove_ } from 'vs/editor/common/controller/cursorMoveCommands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -1614,11 +1614,13 @@ export namespace CoreEditingCommands { } public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void { - const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteLeft(editor._getCursorConfiguration(), editor.getModel(), editor.getSelections()); + const cursors = editor._getCursors(); + const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteLeft(cursors.getPrevEditOperationType(), editor._getCursorConfiguration(), editor.getModel(), editor.getSelections()); if (shouldPushStackElementBefore) { editor.pushUndoStop(); } editor.executeCommands(this.id, commands); + cursors.setPrevEditOperationType(EditOperationType.DeletingLeft); } }); @@ -1637,11 +1639,13 @@ export namespace CoreEditingCommands { } public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void { - const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteRight(editor._getCursorConfiguration(), editor.getModel(), editor.getSelections()); + const cursors = editor._getCursors(); + const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteRight(cursors.getPrevEditOperationType(), editor._getCursorConfiguration(), editor.getModel(), editor.getSelections()); if (shouldPushStackElementBefore) { editor.pushUndoStop(); } editor.executeCommands(this.id, commands); + cursors.setPrevEditOperationType(EditOperationType.DeletingRight); } }); diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index bbe2d1aa6ee..9c247c0ac58 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -12,7 +12,7 @@ import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { Selection, SelectionDirection, ISelection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { CursorColumns, CursorConfiguration, EditOperationResult, CursorContext, CursorState, RevealTarget, IColumnSelectData, ICursors } from 'vs/editor/common/controller/cursorCommon'; +import { CursorColumns, CursorConfiguration, EditOperationResult, CursorContext, CursorState, RevealTarget, IColumnSelectData, ICursors, EditOperationType } from 'vs/editor/common/controller/cursorCommon'; import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations'; import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations'; import { TextModelEventType, ModelRawContentChangedEvent, RawContentChangedType } from 'vs/editor/common/model/textModelEvents'; @@ -98,6 +98,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { private _isHandling: boolean; private _isDoingComposition: boolean; private _columnSelectData: IColumnSelectData; + private _prevEditOperationType: EditOperationType; constructor(configuration: editorCommon.IConfiguration, model: editorCommon.IModel, viewModel: IViewModel) { super(); @@ -110,6 +111,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._isHandling = false; this._isDoingComposition = false; this._columnSelectData = null; + this._prevEditOperationType = EditOperationType.Other; this._register(this._model.addBulkListener((events) => { if (this._isHandling) { @@ -278,6 +280,9 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { } private _onModelContentChanged(hadFlushEvent: boolean): void { + + this._prevEditOperationType = EditOperationType.Other; + if (hadFlushEvent) { // a model.setValue() was called this._cursors.dispose(); @@ -322,6 +327,14 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this.setStates(source, CursorChangeReason.NotSet, CursorState.fromModelSelections(selections)); } + public getPrevEditOperationType(): EditOperationType { + return this._prevEditOperationType; + } + + public setPrevEditOperationType(type: EditOperationType): void { + this._prevEditOperationType = type; + } + // ------ auxiliary handling logic private _executeEditOperation(opResult: EditOperationResult): void { @@ -344,6 +357,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { if (result) { // The commands were applied correctly this._interpretCommandResult(result); + + this._prevEditOperationType = opResult.type; } if (opResult.shouldPushStackElementAfter) { @@ -515,16 +530,16 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { } // Here we must interpret each typed character individually, that's why we create a new context - this._executeEditOperation(TypeOperations.typeWithInterceptors(this.context.config, this.context.model, this.getSelections(), chr)); + this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), chr)); } } else { - this._executeEditOperation(TypeOperations.typeWithoutInterceptors(this.context.config, this.context.model, this.getSelections(), text)); + this._executeEditOperation(TypeOperations.typeWithoutInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), text)); } } private _replacePreviousChar(text: string, replaceCharCnt: number): void { - this._executeEditOperation(TypeOperations.replacePreviousChar(this.context.config, this.context.model, this.getSelections(), text, replaceCharCnt)); + this._executeEditOperation(TypeOperations.replacePreviousChar(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), text, replaceCharCnt)); } private _paste(text: string, pasteOnNewLine: boolean): void { @@ -538,14 +553,14 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { private _externalExecuteCommand(command: editorCommon.ICommand): void { this._cursors.killSecondaryCursors(); - this._executeEditOperation(new EditOperationResult([command], { + this._executeEditOperation(new EditOperationResult(EditOperationType.Other, [command], { shouldPushStackElementBefore: false, shouldPushStackElementAfter: false })); } private _externalExecuteCommands(commands: editorCommon.ICommand[]): void { - this._executeEditOperation(new EditOperationResult(commands, { + this._executeEditOperation(new EditOperationResult(EditOperationType.Other, commands, { shouldPushStackElementBefore: false, shouldPushStackElementAfter: false })); diff --git a/src/vs/editor/common/controller/cursorCommon.ts b/src/vs/editor/common/controller/cursorCommon.ts index 615643272da..b3b40cca6b3 100644 --- a/src/vs/editor/common/controller/cursorCommon.ts +++ b/src/vs/editor/common/controller/cursorCommon.ts @@ -31,6 +31,17 @@ export const enum RevealTarget { BottomMost = 2 } +/** + * This is an operation type that will be recorded for undo/redo purposes. + * The goal is to introduce an undo stop when the controller switches between different operation types. + */ +export const enum EditOperationType { + Other = 0, + Typing = 1, + DeletingLeft = 2, + DeletingRight = 3 +} + export interface ICursors { readonly context: CursorContext; getPrimaryCursor(): CursorState; @@ -45,6 +56,9 @@ export interface ICursors { revealRange(revealHorizontal: boolean, viewRange: Range, verticalType: VerticalRevealType, scrollType: ScrollType): void; scrollTo(desiredScrollTop: number): void; + + getPrevEditOperationType(): EditOperationType; + setPrevEditOperationType(type: EditOperationType): void; } export interface CharacterMap { @@ -422,17 +436,20 @@ export class CursorState { export class EditOperationResult { _editOperationResultBrand: void; + readonly type: EditOperationType; readonly commands: ICommand[]; readonly shouldPushStackElementBefore: boolean; readonly shouldPushStackElementAfter: boolean; constructor( + type: EditOperationType, commands: ICommand[], opts: { shouldPushStackElementBefore: boolean; shouldPushStackElementAfter: boolean; } ) { + this.type = type; this.commands = commands; this.shouldPushStackElementBefore = opts.shouldPushStackElementBefore; this.shouldPushStackElementAfter = opts.shouldPushStackElementAfter; diff --git a/src/vs/editor/common/controller/cursorDeleteOperations.ts b/src/vs/editor/common/controller/cursorDeleteOperations.ts index 7951ab91b83..e5b498b40e9 100644 --- a/src/vs/editor/common/controller/cursorDeleteOperations.ts +++ b/src/vs/editor/common/controller/cursorDeleteOperations.ts @@ -5,7 +5,7 @@ 'use strict'; import { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand'; -import { CursorColumns, CursorConfiguration, ICursorSimpleModel, EditOperationResult } from 'vs/editor/common/controller/cursorCommon'; +import { CursorColumns, CursorConfiguration, ICursorSimpleModel, EditOperationResult, EditOperationType } from 'vs/editor/common/controller/cursorCommon'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { MoveOperations } from 'vs/editor/common/controller/cursorMoveOperations'; @@ -14,9 +14,9 @@ import { ICommand } from 'vs/editor/common/editorCommon'; export class DeleteOperations { - public static deleteRight(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] { + public static deleteRight(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] { let commands: ICommand[] = []; - let shouldPushStackElementBefore = false; + let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.DeletingRight); for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; @@ -94,14 +94,14 @@ export class DeleteOperations { return [true, commands]; } - public static deleteLeft(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] { + public static deleteLeft(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] { if (this._isAutoClosingPairDelete(config, model, selections)) { return this._runAutoClosingPairDelete(config, model, selections); } let commands: ICommand[] = []; - let shouldPushStackElementBefore = false; + let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.DeletingLeft); for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; @@ -210,7 +210,7 @@ export class DeleteOperations { commands[i] = new ReplaceCommand(selection, ''); } } - return new EditOperationResult(commands, { + return new EditOperationResult(EditOperationType.Other, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: true }); diff --git a/src/vs/editor/common/controller/cursorMoveCommands.ts b/src/vs/editor/common/controller/cursorMoveCommands.ts index 97925d92dcc..a0f5c443432 100644 --- a/src/vs/editor/common/controller/cursorMoveCommands.ts +++ b/src/vs/editor/common/controller/cursorMoveCommands.ts @@ -418,7 +418,19 @@ export class CursorMoveCommands { let result: CursorState[] = []; for (let i = 0, len = cursors.length; i < len; i++) { const cursor = cursors[i]; - result[i] = CursorState.fromViewState(MoveOperations.moveLeft(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns)); + + let newViewState = MoveOperations.moveLeft(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns); + + if (noOfColumns === 1 && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber) { + // moved over to the previous view line + const newViewModelPosition = context.viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position); + if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) { + // stayed on the same model line => pass wrapping point where 2 view positions map to a single model position + newViewState = MoveOperations.moveLeft(context.config, context.viewModel, newViewState, inSelectionMode, 1); + } + } + + result[i] = CursorState.fromViewState(newViewState); } return result; } @@ -438,7 +450,18 @@ export class CursorMoveCommands { let result: CursorState[] = []; for (let i = 0, len = cursors.length; i < len; i++) { const cursor = cursors[i]; - result[i] = CursorState.fromViewState(MoveOperations.moveRight(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns)); + let newViewState = MoveOperations.moveRight(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns); + + if (noOfColumns === 1 && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber) { + // moved over to the next view line + const newViewModelPosition = context.viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position); + if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) { + // stayed on the same model line => pass wrapping point where 2 view positions map to a single model position + newViewState = MoveOperations.moveRight(context.config, context.viewModel, newViewState, inSelectionMode, 1); + } + } + + result[i] = CursorState.fromViewState(newViewState); } return result; } diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts index 129d02b48a5..0ffb52bd5af 100644 --- a/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -6,7 +6,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { ReplaceCommand, ReplaceCommandWithoutChangingPosition, ReplaceCommandWithOffsetCursorState } from 'vs/editor/common/commands/replaceCommand'; -import { CursorColumns, CursorConfiguration, ICursorSimpleModel, EditOperationResult } from 'vs/editor/common/controller/cursorCommon'; +import { CursorColumns, CursorConfiguration, ICursorSimpleModel, EditOperationResult, EditOperationType } from 'vs/editor/common/controller/cursorCommon'; import { Range } from 'vs/editor/common/core/range'; import { ICommand, ITokenizedModel } from 'vs/editor/common/editorCommon'; import * as strings from 'vs/base/common/strings'; @@ -73,7 +73,7 @@ export class TypeOperations { for (let i = 0, len = selections.length; i < len; i++) { commands[i] = new ReplaceCommand(selections[i], text[i]); } - return new EditOperationResult(commands, { + return new EditOperationResult(EditOperationType.Other, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: true }); @@ -103,7 +103,7 @@ export class TypeOperations { commands[i] = new ReplaceCommand(selection, text); } } - return new EditOperationResult(commands, { + return new EditOperationResult(EditOperationType.Other, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: true }); @@ -255,7 +255,7 @@ export class TypeOperations { return commands; } - public static replacePreviousChar(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], txt: string, replaceCharCnt: number): EditOperationResult { + public static replacePreviousChar(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], txt: string, replaceCharCnt: number): EditOperationResult { let commands: ICommand[] = []; for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; @@ -271,8 +271,8 @@ export class TypeOperations { let range = new Range(pos.lineNumber, startColumn, pos.lineNumber, pos.column); commands[i] = new ReplaceCommand(range, txt); } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: false, + return new EditOperationResult(EditOperationType.Typing, commands, { + shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing), shouldPushStackElementAfter: false }); } @@ -324,6 +324,13 @@ export class TypeOperations { } // no enter rules applied, we should check indentation rules then. + if (!config.autoIndent) { + // Nothing special + let lineText = model.getLineContent(range.startLineNumber); + let indentation = strings.getLeadingWhitespace(lineText).substring(0, range.startColumn - 1); + return TypeOperations._typeCommand(range, '\n' + config.normalizeIndentation(indentation), keepPosition); + } + let ir = LanguageConfigurationRegistry.getIndentForEnter(model, range, { unshiftIndent: (indent) => { return TypeOperations.unshiftIndent(config, indent); @@ -468,7 +475,7 @@ export class TypeOperations { return cnt; } - private static _runAutoClosingCloseCharType(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { + private static _runAutoClosingCloseCharType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { let commands: ICommand[] = []; for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; @@ -476,8 +483,8 @@ export class TypeOperations { const typeSelection = new Range(position.lineNumber, position.column, position.lineNumber, position.column + 1); commands[i] = new ReplaceCommand(typeSelection, ch); } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: false, + return new EditOperationResult(EditOperationType.Typing, commands, { + shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing), shouldPushStackElementAfter: false }); } @@ -550,14 +557,14 @@ export class TypeOperations { return true; } - private static _runAutoClosingOpenCharType(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { + private static _runAutoClosingOpenCharType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { let commands: ICommand[] = []; for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; const closeCharacter = config.autoClosingPairsOpen[ch]; commands[i] = new ReplaceCommandWithOffsetCursorState(selection, ch + closeCharacter, 0, -closeCharacter.length); } - return new EditOperationResult(commands, { + return new EditOperationResult(EditOperationType.Typing, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: false }); @@ -597,14 +604,14 @@ export class TypeOperations { return true; } - private static _runSurroundSelectionType(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { + private static _runSurroundSelectionType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { let commands: ICommand[] = []; for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; const closeCharacter = config.surroundingPairs[ch]; commands[i] = new SurroundSelectionCommand(selection, ch, closeCharacter); } - return new EditOperationResult(commands, { + return new EditOperationResult(EditOperationType.Other, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: true }); @@ -617,7 +624,7 @@ export class TypeOperations { return false; } - private static _typeInterceptorElectricChar(config: CursorConfiguration, model: ITokenizedModel, selection: Selection, ch: string): EditOperationResult { + private static _typeInterceptorElectricChar(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selection: Selection, ch: string): EditOperationResult { if (!config.electricChars.hasOwnProperty(ch) || !selection.isEmpty()) { return null; } @@ -639,7 +646,7 @@ export class TypeOperations { if (electricAction.appendText) { const command = new ReplaceCommandWithOffsetCursorState(selection, ch + electricAction.appendText, 0, -electricAction.appendText.length); - return new EditOperationResult([command], { + return new EditOperationResult(EditOperationType.Typing, [command], { shouldPushStackElementBefore: false, shouldPushStackElementAfter: true }); @@ -670,7 +677,7 @@ export class TypeOperations { let typeSelection = new Range(position.lineNumber, 1, position.lineNumber, position.column); const command = new ReplaceCommand(typeSelection, typeText); - return new EditOperationResult([command], { + return new EditOperationResult(EditOperationType.Typing, [command], { shouldPushStackElementBefore: false, shouldPushStackElementAfter: true }); @@ -680,14 +687,14 @@ export class TypeOperations { return null; } - public static typeWithInterceptors(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { + public static typeWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { if (ch === '\n') { let commands: ICommand[] = []; for (let i = 0, len = selections.length; i < len; i++) { commands[i] = TypeOperations._enter(config, model, false, selections[i]); } - return new EditOperationResult(commands, { + return new EditOperationResult(EditOperationType.Typing, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: false, }); @@ -704,7 +711,7 @@ export class TypeOperations { } } if (!autoIndentFails) { - return new EditOperationResult(commands, { + return new EditOperationResult(EditOperationType.Typing, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: false, }); @@ -712,36 +719,48 @@ export class TypeOperations { } if (this._isAutoClosingCloseCharType(config, model, selections, ch)) { - return this._runAutoClosingCloseCharType(config, model, selections, ch); + return this._runAutoClosingCloseCharType(prevEditOperationType, config, model, selections, ch); } if (this._isAutoClosingOpenCharType(config, model, selections, ch)) { - return this._runAutoClosingOpenCharType(config, model, selections, ch); + return this._runAutoClosingOpenCharType(prevEditOperationType, config, model, selections, ch); } if (this._isSurroundSelectionType(config, model, selections, ch)) { - return this._runSurroundSelectionType(config, model, selections, ch); + return this._runSurroundSelectionType(prevEditOperationType, config, model, selections, ch); } // Electric characters make sense only when dealing with a single cursor, // as multiple cursors typing brackets for example would interfer with bracket matching if (this._isTypeInterceptorElectricChar(config, model, selections)) { - const r = this._typeInterceptorElectricChar(config, model, selections[0], ch); + const r = this._typeInterceptorElectricChar(prevEditOperationType, config, model, selections[0], ch); if (r) { return r; } } - return this.typeWithoutInterceptors(config, model, selections, ch); + // A simple character type + let commands: ICommand[] = []; + for (let i = 0, len = selections.length; i < len; i++) { + commands[i] = new ReplaceCommand(selections[i], ch); + } + let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.Typing); + if (ch === ' ') { + shouldPushStackElementBefore = true; + } + return new EditOperationResult(EditOperationType.Typing, commands, { + shouldPushStackElementBefore: shouldPushStackElementBefore, + shouldPushStackElementAfter: false + }); } - public static typeWithoutInterceptors(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], str: string): EditOperationResult { + public static typeWithoutInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], str: string): EditOperationResult { let commands: ICommand[] = []; for (let i = 0, len = selections.length; i < len; i++) { commands[i] = new ReplaceCommand(selections[i], str); } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: false, + return new EditOperationResult(EditOperationType.Typing, commands, { + shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing), shouldPushStackElementAfter: false }); } diff --git a/src/vs/editor/common/controller/cursorWordOperations.ts b/src/vs/editor/common/controller/cursorWordOperations.ts index 7d8b52b17a3..8f83c1f8621 100644 --- a/src/vs/editor/common/controller/cursorWordOperations.ts +++ b/src/vs/editor/common/controller/cursorWordOperations.ts @@ -425,7 +425,9 @@ export class WordOperations { let lineNumber = position.lineNumber; let column: number; - if (position.isBeforeOrEqual(cursor.selectionStart.getStartPosition())) { + if (cursor.selectionStart.containsPosition(position)) { + column = cursor.selectionStart.endColumn; + } else if (position.isBeforeOrEqual(cursor.selectionStart.getStartPosition())) { column = startColumn; let possiblePosition = new Position(lineNumber, column); if (cursor.selectionStart.containsPosition(possiblePosition)) { diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index a346ca6ea9d..2bc38f26a22 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -15,7 +15,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { Position, IPosition } from 'vs/editor/common/core/position'; import { Range, IRange } from 'vs/editor/common/core/range'; import { Selection, ISelection } from 'vs/editor/common/core/selection'; -import { IndentRange } from 'vs/editor/common/model/indentRanges'; +import { IndentRanges } from 'vs/editor/common/model/indentRanges'; import { ITextSource } from 'vs/editor/common/model/textSource'; import { ModelRawContentChangedEvent, IModelContentChangedEvent, IModelDecorationsChangedEvent, @@ -587,11 +587,6 @@ export interface ITextModel { */ getLinesContent(): string[]; - /** - * @internal - */ - getIndentLevel(lineNumber: number): number; - /** * Get the end of line sequence predominantly used in the text buffer. * @return EOL char sequence (e.g.: '\n' or '\r\n'). @@ -903,12 +898,12 @@ export interface ITokenizedModel extends ITextModel { /** * @internal */ - getIndentRanges(): IndentRange[]; + getIndentRanges(): IndentRanges; /** * @internal */ - getLineIndentGuide(lineNumber: number): number; + getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[]; } /** diff --git a/src/vs/editor/common/model/editableTextModel.ts b/src/vs/editor/common/model/editableTextModel.ts index 77c0bd9f8a8..99478d2869e 100644 --- a/src/vs/editor/common/model/editableTextModel.ts +++ b/src/vs/editor/common/model/editableTextModel.ts @@ -469,8 +469,6 @@ export class EditableTextModel extends TextModelWithDecorations implements edito private _doApplyEdits(operations: IValidatedEditOperation[]): void { - const tabSize = this._options.tabSize; - // Sort operations descending operations.sort(EditableTextModel._sortOpsDescending); @@ -505,7 +503,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito } this._invalidateLine(currentLineNumber - 1); - this._lines[currentLineNumber - 1].applyEdits(lineEditsQueue.slice(currentLineNumberStart, i), tabSize); + this._lines[currentLineNumber - 1].applyEdits(lineEditsQueue.slice(currentLineNumberStart, i)); this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length); rawContentChanges.push( new textModelEvents.ModelRawLineChanged(currentLineNumber, this._lines[currentLineNumber - 1].text) @@ -516,7 +514,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito } this._invalidateLine(currentLineNumber - 1); - this._lines[currentLineNumber - 1].applyEdits(lineEditsQueue.slice(currentLineNumberStart, lineEditsQueue.length), tabSize); + this._lines[currentLineNumber - 1].applyEdits(lineEditsQueue.slice(currentLineNumberStart, lineEditsQueue.length)); this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length); rawContentChanges.push( new textModelEvents.ModelRawLineChanged(currentLineNumber, this._lines[currentLineNumber - 1].text) @@ -569,7 +567,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito const spliceStartLineNumber = startLineNumber + editingLinesCnt; - const endLineRemains = this._lines[endLineNumber - 1].split(endColumn, tabSize); + const endLineRemains = this._lines[endLineNumber - 1].split(endColumn); this._invalidateLine(spliceStartLineNumber - 1); const spliceCnt = endLineNumber - spliceStartLineNumber; @@ -578,7 +576,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito this._lineStarts.removeValues(spliceStartLineNumber, spliceCnt); // Reconstruct first line - this._lines[spliceStartLineNumber - 1].append(endLineRemains, tabSize); + this._lines[spliceStartLineNumber - 1].append(endLineRemains); this._lineStarts.changeValue(spliceStartLineNumber - 1, this._lines[spliceStartLineNumber - 1].text.length + this._EOL.length); rawContentChanges.push( @@ -603,7 +601,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito } // Split last line - let leftoverLine = this._lines[spliceLineNumber - 1].split(spliceColumn, tabSize); + let leftoverLine = this._lines[spliceLineNumber - 1].split(spliceColumn); this._lineStarts.changeValue(spliceLineNumber - 1, this._lines[spliceLineNumber - 1].text.length + this._EOL.length); rawContentChanges.push( new textModelEvents.ModelRawLineChanged(spliceLineNumber, this._lines[spliceLineNumber - 1].text) @@ -615,7 +613,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito let newLinesContent: string[] = []; let newLinesLengths = new Uint32Array(insertingLinesCnt - editingLinesCnt); for (let j = editingLinesCnt + 1; j <= insertingLinesCnt; j++) { - newLines.push(this._createModelLine(op.lines[j], tabSize)); + newLines.push(this._createModelLine(op.lines[j])); newLinesContent.push(op.lines[j]); newLinesLengths[j - editingLinesCnt - 1] = op.lines[j].length + this._EOL.length; } @@ -624,7 +622,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito this._lineStarts.insertValues(startLineNumber + editingLinesCnt, newLinesLengths); // Last line - this._lines[startLineNumber + insertingLinesCnt - 1].append(leftoverLine, tabSize); + this._lines[startLineNumber + insertingLinesCnt - 1].append(leftoverLine); this._lineStarts.changeValue(startLineNumber + insertingLinesCnt - 1, this._lines[startLineNumber + insertingLinesCnt - 1].text.length + this._EOL.length); rawContentChanges.push( new textModelEvents.ModelRawLinesInserted(spliceLineNumber + 1, startLineNumber + insertingLinesCnt, newLinesContent.join('\n')) diff --git a/src/vs/editor/common/model/indentRanges.ts b/src/vs/editor/common/model/indentRanges.ts index 21a5311146b..8217f69b354 100644 --- a/src/vs/editor/common/model/indentRanges.ts +++ b/src/vs/editor/common/model/indentRanges.ts @@ -7,36 +7,195 @@ import { ITextModel } from 'vs/editor/common/editorCommon'; import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration'; +import { computeIndentLevel } from 'vs/editor/common/model/modelLine'; -export class IndentRange { - _indentRangeBrand: void; - startLineNumber: number; - endLineNumber: number; - indent: number; - marker: boolean; +export const MAX_FOLDING_REGIONS = 0xFFFF; - constructor(startLineNumber: number, endLineNumber: number, indent: number, marker?: boolean) { - this.startLineNumber = startLineNumber; - this.endLineNumber = endLineNumber; - this.indent = indent; - this.marker = marker; +const MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT = 5000; +const MASK_LINE_NUMBER = 0xFFFFFF; +const MASK_INDENT = 0xFF000000; + +export class IndentRanges { + private _startIndexes: Uint32Array; + private _endIndexes: Uint32Array; + private _model: ITextModel; + + constructor(startIndexes: Uint32Array, endIndexes: Uint32Array, model: ITextModel) { + if (startIndexes.length !== endIndexes.length || startIndexes.length > MAX_FOLDING_REGIONS) { + throw new Error('invalid startIndexes or endIndexes size'); + } + this._startIndexes = startIndexes; + this._endIndexes = endIndexes; + this._model = model; + this._computeParentIndices(); } - public static deepCloneArr(indentRanges: IndentRange[]): IndentRange[] { - let result: IndentRange[] = []; - for (let i = 0, len = indentRanges.length; i < len; i++) { - let r = indentRanges[i]; - result[i] = new IndentRange(r.startLineNumber, r.endLineNumber, r.indent); + private _computeParentIndices() { + let parentIndexes = []; + let isInsideLast = (startLineNumber: number, endLineNumber: number) => { + let index = parentIndexes[parentIndexes.length - 1]; + return this.getStartLineNumber(index) <= startLineNumber && this.getEndLineNumber(index) >= endLineNumber; + }; + for (let i = 0, len = this._startIndexes.length; i < len; i++) { + let startLineNumber = this._startIndexes[i]; + let endLineNumber = this._endIndexes[i]; + if (startLineNumber > MASK_LINE_NUMBER || endLineNumber > MASK_LINE_NUMBER) { + throw new Error('startLineNumber or endLineNumber must not exceed ' + MASK_LINE_NUMBER); + } + while (parentIndexes.length > 0 && !isInsideLast(startLineNumber, endLineNumber)) { + parentIndexes.pop(); + } + let parentIndex = parentIndexes.length > 0 ? parentIndexes[parentIndexes.length - 1] : -1; + parentIndexes.push(i); + this._startIndexes[i] = startLineNumber + ((parentIndex & 0xFF) << 24); + this._endIndexes[i] = endLineNumber + ((parentIndex & 0xFF00) << 16); } - return result; + } + + public get length(): number { + return this._startIndexes.length; + } + + public getStartLineNumber(index: number): number { + return this._startIndexes[index] & MASK_LINE_NUMBER; + } + + public getEndLineNumber(index: number): number { + return this._endIndexes[index] & MASK_LINE_NUMBER; + } + + public getParentIndex(index: number) { + let parent = ((this._startIndexes[index] & MASK_INDENT) >>> 24) + ((this._endIndexes[index] & MASK_INDENT) >>> 16); + if (parent === MAX_FOLDING_REGIONS) { + return -1; + } + return parent; + } + + public getIndent(index: number) { + const lineNumber = this.getStartLineNumber(index); + const tabSize = this._model.getOptions().tabSize; + const lineContent = this._model.getLineContent(lineNumber); + return computeIndentLevel(lineContent, tabSize); + } + + public contains(index: number, line: number) { + return this.getStartLineNumber(index) <= line && this.getEndLineNumber(index) >= line; + } + + private findIndex(line: number) { + let low = 0, high = this._startIndexes.length; + if (high === 0) { + return -1; // no children + } + while (low < high) { + let mid = Math.floor((low + high) / 2); + if (line < this.getStartLineNumber(mid)) { + high = mid; + } else { + low = mid + 1; + } + } + return low - 1; + } + + + public findRange(line: number): number { + let index = this.findIndex(line); + if (index >= 0) { + let endLineNumber = this.getEndLineNumber(index); + if (endLineNumber >= line) { + return index; + } + index = this.getParentIndex(index); + while (index !== -1) { + if (this.contains(index, line)) { + return index; + } + index = this.getParentIndex(index); + } + } + return -1; + } +} +// public only for testing +export class RangesCollector { + private _startIndexes: number[]; + private _endIndexes: number[]; + private _indentOccurrences: number[]; + private _length: number; + private _foldingRegionsLimit: number; + + constructor(foldingRegionsLimit: number) { + this._startIndexes = []; + this._endIndexes = []; + this._indentOccurrences = []; + this._length = 0; + this._foldingRegionsLimit = foldingRegionsLimit; + } + + public insertFirst(startLineNumber: number, endLineNumber: number, indent: number) { + if (startLineNumber > MASK_LINE_NUMBER || endLineNumber > MASK_LINE_NUMBER) { + return; + } + let index = this._length; + this._startIndexes[index] = startLineNumber; + this._endIndexes[index] = endLineNumber; + this._length++; + if (indent < 1000) { + this._indentOccurrences[indent] = (this._indentOccurrences[indent] || 0) + 1; + } + } + + public toIndentRanges(model: ITextModel) { + if (this._length <= this._foldingRegionsLimit) { + // reverse and create arrays of the exact length + let startIndexes = new Uint32Array(this._length); + let endIndexes = new Uint32Array(this._length); + for (let i = this._length - 1, k = 0; i >= 0; i-- , k++) { + startIndexes[k] = this._startIndexes[i]; + endIndexes[k] = this._endIndexes[i]; + } + return new IndentRanges(startIndexes, endIndexes, model); + } else { + let entries = 0; + let maxIndent = this._indentOccurrences.length; + for (let i = 0; i < this._indentOccurrences.length; i++) { + let n = this._indentOccurrences[i]; + if (n) { + if (n + entries > this._foldingRegionsLimit) { + maxIndent = i; + break; + } + entries += n; + } + } + const tabSize = model.getOptions().tabSize; + // reverse and create arrays of the exact length + let startIndexes = new Uint32Array(entries); + let endIndexes = new Uint32Array(entries); + for (let i = this._length - 1, k = 0; i >= 0; i--) { + let startIndex = this._startIndexes[i]; + let lineContent = model.getLineContent(startIndex); + let indent = computeIndentLevel(lineContent, tabSize); + if (indent < maxIndent) { + startIndexes[k] = startIndex; + endIndexes[k] = this._endIndexes[i]; + k++; + } + } + return new IndentRanges(startIndexes, endIndexes, model); + } + } } + interface PreviousRegion { indent: number; line: number; marker: boolean; }; -export function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldingMarkers, minimumRangeSize: number = 1): IndentRange[] { - - let result: IndentRange[] = []; +export function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldingMarkers, foldingRegionsLimit = MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT): IndentRanges { + const tabSize = model.getOptions().tabSize; + let result = new RangesCollector(foldingRegionsLimit); let pattern = void 0; if (markers) { @@ -47,7 +206,8 @@ export function computeRanges(model: ITextModel, offSide: boolean, markers?: Fol previousRegions.push({ indent: -1, line: model.getLineCount() + 1, marker: false }); // sentinel, to make sure there's at least one entry for (let line = model.getLineCount(); line > 0; line--) { - let indent = model.getIndentLevel(line); + let lineContent = model.getLineContent(line); + let indent = computeIndentLevel(lineContent, tabSize); let previous = previousRegions[previousRegions.length - 1]; if (indent === -1) { if (offSide && !previous.marker) { @@ -57,7 +217,7 @@ export function computeRanges(model: ITextModel, offSide: boolean, markers?: Fol continue; // only whitespace } let m; - if (pattern && (m = model.getLineContent(line).match(pattern))) { + if (pattern && (m = lineContent.match(pattern))) { // folding pattern match if (m[1]) { // start pattern match // discard all regions until the folding pattern @@ -70,7 +230,7 @@ export function computeRanges(model: ITextModel, offSide: boolean, markers?: Fol previous = previousRegions[i]; // new folding range from pattern, includes the end line - result.push(new IndentRange(line, previous.line, indent, true)); + result.insertFirst(line, previous.line, indent); previous.marker = false; previous.indent = indent; previous.line = line; @@ -92,8 +252,8 @@ export function computeRanges(model: ITextModel, offSide: boolean, markers?: Fol // new folding range let endLineNumber = previous.line - 1; - if (endLineNumber - line >= minimumRangeSize) { - result.push(new IndentRange(line, endLineNumber, indent)); + if (endLineNumber - line >= 1) { // needs at east size 1 + result.insertFirst(line, endLineNumber, indent); } } if (previous.indent === indent) { @@ -103,6 +263,5 @@ export function computeRanges(model: ITextModel, offSide: boolean, markers?: Fol previousRegions.push({ indent, line, marker: false }); } } - - return result.reverse(); + return result.toIndentRanges(model); } diff --git a/src/vs/editor/common/model/modelLine.ts b/src/vs/editor/common/model/modelLine.ts index b811f40a73f..956359c82b5 100644 --- a/src/vs/editor/common/model/modelLine.ts +++ b/src/vs/editor/common/model/modelLine.ts @@ -27,10 +27,10 @@ var NO_OP_TOKENS_ADJUSTER: ITokensAdjuster = { /** * Returns: - * - 0 => the line consists of whitespace - * - otherwise => the indent level is returned value - 1 + * - -1 => the line consists of whitespace + * - otherwise => the indent level is returned value */ -function computePlusOneIndentLevel(line: string, tabSize: number): number { +export function computeIndentLevel(line: string, tabSize: number): number { let indent = 0; let i = 0; let len = line.length; @@ -48,10 +48,10 @@ function computePlusOneIndentLevel(line: string, tabSize: number): number { } if (i === len) { - return 0; // line only consists of whitespace + return -1; // line only consists of whitespace } - return indent + 1; + return indent; } export interface IModelLine { @@ -66,14 +66,10 @@ export interface IModelLine { getTokens(topLevelLanguageId: LanguageId): LineTokens; setTokens(topLevelLanguageId: LanguageId, tokens: Uint32Array): void; - // --- indentation - updateTabSize(tabSize: number): void; - getIndentLevel(): number; - // --- editing - applyEdits(edits: ILineEdit[], tabSize: number): number; - append(other: IModelLine, tabSize: number): void; - split(splitColumn: number, tabSize: number): IModelLine; + applyEdits(edits: ILineEdit[]): number; + append(other: IModelLine): void; + split(splitColumn: number): IModelLine; } export abstract class AbstractModelLine { @@ -84,13 +80,13 @@ export abstract class AbstractModelLine { /// public abstract get text(): string; - protected abstract _setText(text: string, tabSize: number): void; + protected abstract _setText(text: string): void; protected abstract _createTokensAdjuster(): ITokensAdjuster; - protected abstract _createModelLine(text: string, tabSize: number): IModelLine; + protected abstract _createModelLine(text: string): IModelLine; /// - public applyEdits(edits: ILineEdit[], tabSize: number): number { + public applyEdits(edits: ILineEdit[]): number { let deltaColumn = 0; let resultText = this.text; @@ -133,21 +129,21 @@ export abstract class AbstractModelLine { tokensAdjuster.finish(deltaColumn, resultText.length); // Save the resulting text - this._setText(resultText, tabSize); + this._setText(resultText); return deltaColumn; } - public split(splitColumn: number, tabSize: number): IModelLine { + public split(splitColumn: number): IModelLine { const myText = this.text.substring(0, splitColumn - 1); const otherText = this.text.substring(splitColumn - 1); - this._setText(myText, tabSize); - return this._createModelLine(otherText, tabSize); + this._setText(myText); + return this._createModelLine(otherText); } - public append(other: IModelLine, tabSize: number): void { - this._setText(this.text + other.text, tabSize); + public append(other: IModelLine): void { + this._setText(this.text + other.text); } } @@ -156,59 +152,33 @@ export class ModelLine extends AbstractModelLine implements IModelLine { private _text: string; public get text(): string { return this._text; } - /** - * bits 31 - 1 => indentLevel - * bit 0 => isInvalid - */ - private _metadata: number; + private _isInvalid: boolean; public isInvalid(): boolean { - return (this._metadata & 0x00000001) ? true : false; + return this._isInvalid; } public setIsInvalid(isInvalid: boolean): void { - this._metadata = (this._metadata & 0xfffffffe) | (isInvalid ? 1 : 0); - } - - /** - * Returns: - * - -1 => the line consists of whitespace - * - otherwise => the indent level is returned value - */ - public getIndentLevel(): number { - return ((this._metadata & 0xfffffffe) >> 1) - 1; - } - - private _setPlusOneIndentLevel(value: number): void { - this._metadata = (this._metadata & 0x00000001) | ((value & 0xefffffff) << 1); - } - - public updateTabSize(tabSize: number): void { - if (tabSize === 0) { - // don't care mark - this._metadata = this._metadata & 0x00000001; - } else { - this._setPlusOneIndentLevel(computePlusOneIndentLevel(this._text, tabSize)); - } + this._isInvalid = isInvalid; } private _state: IState; private _lineTokens: ArrayBuffer; - constructor(text: string, tabSize: number) { + constructor(text: string) { super(); - this._metadata = 0; - this._setText(text, tabSize); + this._isInvalid = false; + this._setText(text); this._state = null; this._lineTokens = null; } - protected _createModelLine(text: string, tabSize: number): IModelLine { - return new ModelLine(text, tabSize); + protected _createModelLine(text: string): IModelLine { + return new ModelLine(text); } - public split(splitColumn: number, tabSize: number): IModelLine { - let result = super.split(splitColumn, tabSize); + public split(splitColumn: number): IModelLine { + let result = super.split(splitColumn); // Mark overflowing tokens for deletion & delete marked tokens this._deleteMarkedTokens(this._markOverflowingTokensForDeletion(0, this.text.length)); @@ -216,10 +186,10 @@ export class ModelLine extends AbstractModelLine implements IModelLine { return result; } - public append(other: IModelLine, tabSize: number): void { + public append(other: IModelLine): void { let thisTextLength = this.text.length; - super.append(other, tabSize); + super.append(other); if (other instanceof ModelLine) { let otherRawTokens = other._lineTokens; @@ -424,20 +394,14 @@ export class ModelLine extends AbstractModelLine implements IModelLine { this._lineTokens = newTokens.buffer; } - protected _setText(text: string, tabSize: number): void { + protected _setText(text: string): void { this._text = text; - if (tabSize === 0) { - // don't care mark - this._metadata = this._metadata & 0x00000001; - } else { - this._setPlusOneIndentLevel(computePlusOneIndentLevel(text, tabSize)); - } } } /** - * A model line that cannot store any tokenization state, nor does it compute indentation levels. + * A model line that cannot store any tokenization state. * It has no fields except the text. */ export class MinimalModelLine extends AbstractModelLine implements IModelLine { @@ -452,33 +416,21 @@ export class MinimalModelLine extends AbstractModelLine implements IModelLine { public setIsInvalid(isInvalid: boolean): void { } - /** - * Returns: - * - -1 => the line consists of whitespace - * - otherwise => the indent level is returned value - */ - public getIndentLevel(): number { - return 0; - } - - public updateTabSize(tabSize: number): void { - } - - constructor(text: string, tabSize: number) { + constructor(text: string) { super(); - this._setText(text, tabSize); + this._setText(text); } - protected _createModelLine(text: string, tabSize: number): IModelLine { - return new MinimalModelLine(text, tabSize); + protected _createModelLine(text: string): IModelLine { + return new MinimalModelLine(text); } - public split(splitColumn: number, tabSize: number): IModelLine { - return super.split(splitColumn, tabSize); + public split(splitColumn: number): IModelLine { + return super.split(splitColumn); } - public append(other: IModelLine, tabSize: number): void { - super.append(other, tabSize); + public append(other: IModelLine): void { + super.append(other); } // --- BEGIN STATE @@ -514,7 +466,7 @@ export class MinimalModelLine extends AbstractModelLine implements IModelLine { return NO_OP_TOKENS_ADJUSTER; } - protected _setText(text: string, tabSize: number): void { + protected _setText(text: string): void { this._text = text; } } diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index aa93b0ed106..e4d74605063 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -121,11 +121,11 @@ export class TextModel implements editorCommon.ITextModel { this._isDisposing = false; } - protected _createModelLine(text: string, tabSize: number): IModelLine { + protected _createModelLine(text: string): IModelLine { if (this._isTooLargeForTokenization) { - return new MinimalModelLine(text, tabSize); + return new MinimalModelLine(text); } - return new ModelLine(text, tabSize); + return new ModelLine(text); } protected _assertNotDisposed(): void { @@ -167,13 +167,6 @@ export class TextModel implements editorCommon.ITextModel { let e = this._options.createChangeEvent(newOpts); this._options = newOpts; - if (e.tabSize) { - let newTabSize = this._options.tabSize; - for (let i = 0, len = this._lines.length; i < len; i++) { - this._lines[i].updateTabSize(newTabSize); - } - } - this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelOptionsChanged, e); } @@ -487,15 +480,6 @@ export class TextModel implements editorCommon.ITextModel { return this._lines[lineNumber - 1].text; } - public getIndentLevel(lineNumber: number): number { - this._assertNotDisposed(); - if (lineNumber < 1 || lineNumber > this.getLineCount()) { - throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`'); - } - - return this._lines[lineNumber - 1].getIndentLevel(); - } - public getLinesContent(): string[] { this._assertNotDisposed(); var r: string[] = []; @@ -775,12 +759,11 @@ export class TextModel implements editorCommon.ITextModel { } private _constructLines(textSource: ITextSource): void { - const tabSize = this._options.tabSize; let rawLines = textSource.lines; let modelLines: IModelLine[] = new Array(rawLines.length); for (let i = 0, len = rawLines.length; i < len; i++) { - modelLines[i] = this._createModelLine(rawLines[i], tabSize); + modelLines[i] = this._createModelLine(rawLines[i]); } this._BOM = textSource.BOM; this._mightContainRTL = textSource.containsRTL; diff --git a/src/vs/editor/common/model/textModelWithTokens.ts b/src/vs/editor/common/model/textModelWithTokens.ts index e0a17aaab0f..8d7b85746b9 100644 --- a/src/vs/editor/common/model/textModelWithTokens.ts +++ b/src/vs/editor/common/model/textModelWithTokens.ts @@ -22,7 +22,8 @@ import { getWordAtText } from 'vs/editor/common/model/wordHelper'; import { TokenizationResult2 } from 'vs/editor/common/core/token'; import { ITextSource, IRawTextSource } from 'vs/editor/common/model/textSource'; import * as textModelEvents from 'vs/editor/common/model/textModelEvents'; -import { IndentRange, computeRanges } from 'vs/editor/common/model/indentRanges'; +import { IndentRanges, computeRanges } from 'vs/editor/common/model/indentRanges'; +import { computeIndentLevel } from 'vs/editor/common/model/modelLine'; class ModelTokensChangedEventBuilder { @@ -70,7 +71,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke private _invalidLineStartIndex: number; private _lastState: IState; - private _indentRanges: IndentRange[]; + private _indentRanges: IndentRanges; private _languageRegistryListener: IDisposable; private _revalidateTokensTimeout: number; @@ -841,7 +842,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke this._indentRanges = null; } - private _getIndentRanges(): IndentRange[] { + private _getIndentRanges(): IndentRanges { if (!this._indentRanges) { let foldingRules = LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id); let offSide = foldingRules && foldingRules.offSide; @@ -851,51 +852,103 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke return this._indentRanges; } - public getIndentRanges(): IndentRange[] { - this._assertNotDisposed(); - let indentRanges = this._getIndentRanges(); - return IndentRange.deepCloneArr(indentRanges); + public getIndentRanges(): IndentRanges { + return this._getIndentRanges(); } - public getLineIndentGuide(lineNumber: number): number { + private _computeIndentLevel(lineIndex: number): number { + return computeIndentLevel(this._lines[lineIndex].text, this._options.tabSize); + } + + public getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[] { this._assertNotDisposed(); - if (lineNumber < 1 || lineNumber > this.getLineCount()) { - throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`'); + const lineCount = this.getLineCount(); + + if (startLineNumber < 1 || startLineNumber > lineCount) { + throw new Error('Illegal value ' + startLineNumber + ' for `startLineNumber`'); + } + if (endLineNumber < 1 || endLineNumber > lineCount) { + throw new Error('Illegal value ' + endLineNumber + ' for `endLineNumber`'); } - let indentRanges = this._getIndentRanges(); + const foldingRules = LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id); + const offSide = foldingRules && foldingRules.offSide; - for (let i = indentRanges.length - 1; i >= 0; i--) { - let rng = indentRanges[i]; + let result: number[] = new Array(endLineNumber - startLineNumber + 1); - if (rng.startLineNumber === lineNumber) { - return this._toValidLineIndentGuide(lineNumber, Math.ceil(rng.indent / this._options.tabSize)); + let aboveContentLineIndex = -2; /* -2 is a marker for not having computed it */ + let aboveContentLineIndent = -1; + + let belowContentLineIndex = -2; /* -2 is a marker for not having computed it */ + let belowContentLineIndent = -1; + + for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) { + let resultIndex = lineNumber - startLineNumber; + + const currentIndent = this._computeIndentLevel(lineNumber - 1); + if (currentIndent >= 0) { + // This line has content (besides whitespace) + // Use the line's indent + aboveContentLineIndex = lineNumber - 1; + aboveContentLineIndent = currentIndent; + result[resultIndex] = Math.ceil(currentIndent / this._options.tabSize); + continue; } - if (rng.startLineNumber < lineNumber && lineNumber <= rng.endLineNumber) { - return this._toValidLineIndentGuide(lineNumber, 1 + Math.floor(rng.indent / this._options.tabSize)); - } - if (rng.endLineNumber + 1 === lineNumber) { - let bestIndent = rng.indent; - while (i > 0) { - i--; - rng = indentRanges[i]; - if (rng.endLineNumber + 1 === lineNumber) { - bestIndent = rng.indent; + + if (aboveContentLineIndex === -2) { + aboveContentLineIndex = -1; + aboveContentLineIndent = -1; + + // must find previous line with content + for (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) { + let indent = this._computeIndentLevel(lineIndex); + if (indent >= 0) { + aboveContentLineIndex = lineIndex; + aboveContentLineIndent = indent; + break; } } - return this._toValidLineIndentGuide(lineNumber, Math.ceil(bestIndent / this._options.tabSize)); + } + + if (belowContentLineIndex !== -1 && (belowContentLineIndex === -2 || belowContentLineIndex < lineNumber - 1)) { + belowContentLineIndex = -1; + belowContentLineIndent = -1; + + // must find next line with content + for (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) { + let indent = this._computeIndentLevel(lineIndex); + if (indent >= 0) { + belowContentLineIndex = lineIndex; + belowContentLineIndent = indent; + break; + } + } + } + + if (aboveContentLineIndent === -1 || belowContentLineIndent === -1) { + // At the top or bottom of the file + result[resultIndex] = 0; + + } else if (aboveContentLineIndent < belowContentLineIndent) { + // we are inside the region above + result[resultIndex] = (1 + Math.floor(aboveContentLineIndent / this._options.tabSize)); + + } else if (aboveContentLineIndent === belowContentLineIndent) { + // we are in between two regions + result[resultIndex] = Math.ceil(belowContentLineIndent / this._options.tabSize); + + } else { + + if (offSide) { + // same level as region below + result[resultIndex] = Math.ceil(belowContentLineIndent / this._options.tabSize); + } else { + // we are inside the region that ends below + result[resultIndex] = (1 + Math.floor(belowContentLineIndent / this._options.tabSize)); + } + } } - - return 0; - } - - private _toValidLineIndentGuide(lineNumber: number, indentGuide: number): number { - let lineIndentLevel = this._lines[lineNumber - 1].getIndentLevel(); - if (lineIndentLevel === -1) { - return indentGuide; - } - let maxIndentGuide = Math.ceil(lineIndentLevel / this._options.tabSize); - return Math.min(maxIndentGuide, indentGuide); + return result; } } diff --git a/src/vs/editor/common/viewModel/splitLinesCollection.ts b/src/vs/editor/common/viewModel/splitLinesCollection.ts index f57572f1e38..41051777780 100644 --- a/src/vs/editor/common/viewModel/splitLinesCollection.ts +++ b/src/vs/editor/common/viewModel/splitLinesCollection.ts @@ -79,7 +79,7 @@ export interface IViewModelLinesCollection { getViewLineCount(): number; warmUpLookupCache(viewStartLineNumber: number, viewEndLineNumber: number): void; - getViewLineIndentGuide(viewLineNumber: number): number; + getViewLinesIndentGuides(viewStartLineNumber: number, viewEndLineNumber: number): number[]; getViewLineContent(viewLineNumber: number): string; getViewLineMinColumn(viewLineNumber: number): number; getViewLineMaxColumn(viewLineNumber: number): number; @@ -499,11 +499,63 @@ export class SplitLinesCollection implements IViewModelLinesCollection { this.prefixSumComputer.warmUpCache(viewStartLineNumber - 1, viewEndLineNumber - 1); } - public getViewLineIndentGuide(viewLineNumber: number): number { + public getViewLinesIndentGuides(viewStartLineNumber: number, viewEndLineNumber: number): number[] { this._ensureValidState(); - viewLineNumber = this._toValidViewLineNumber(viewLineNumber); - let r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1); - return this.model.getLineIndentGuide(r.index + 1); + viewStartLineNumber = this._toValidViewLineNumber(viewStartLineNumber); + viewEndLineNumber = this._toValidViewLineNumber(viewEndLineNumber); + + const modelStart = this.convertViewPositionToModelPosition(viewStartLineNumber, this.getViewLineMinColumn(viewStartLineNumber)); + const modelEnd = this.convertViewPositionToModelPosition(viewEndLineNumber, this.getViewLineMaxColumn(viewEndLineNumber)); + + let result: number[] = []; + let resultRepeatCount: number[] = []; + const modelStartLineIndex = modelStart.lineNumber - 1; + const modelEndLineIndex = modelEnd.lineNumber - 1; + + let reqStart: Position = null; + for (let modelLineIndex = modelStartLineIndex; modelLineIndex <= modelEndLineIndex; modelLineIndex++) { + const line = this.lines[modelLineIndex]; + if (line.isVisible()) { + let count = 0; + if (modelLineIndex === modelStartLineIndex) { + let viewLineStartIndex = line.getViewLineNumberOfModelPosition(0, modelStart.column); + let viewLineEndIndex = line.getViewLineNumberOfModelPosition(0, this.model.getLineMaxColumn(modelLineIndex + 1)); + count = viewLineEndIndex - viewLineStartIndex + 1; + } else { + let viewLineStartIndex = line.getViewLineNumberOfModelPosition(0, 1); + let viewLineEndIndex = line.getViewLineNumberOfModelPosition(0, this.model.getLineMaxColumn(modelLineIndex + 1)); + count = viewLineEndIndex - viewLineStartIndex + 1; + } + resultRepeatCount.push(count); + // merge into previous request + if (reqStart === null) { + reqStart = new Position(modelLineIndex + 1, 0); + } + } else { + // hit invisible line => flush request + if (reqStart !== null) { + result = result.concat(this.model.getLinesIndentGuides(reqStart.lineNumber, modelLineIndex)); + reqStart = null; + } + } + } + + if (reqStart !== null) { + result = result.concat(this.model.getLinesIndentGuides(reqStart.lineNumber, modelEnd.lineNumber)); + reqStart = null; + } + + const viewLineCount = viewEndLineNumber - viewStartLineNumber + 1; + let viewIndents = new Array(viewLineCount); + let currIndex = 0; + for (let i = 0, len = result.length; i < len; i++) { + let value = result[i]; + let count = Math.min(viewLineCount - currIndex, resultRepeatCount[i]); + for (let j = 0; j < count; j++) { + viewIndents[currIndex++] = value; + } + } + return viewIndents; } public getViewLineContent(viewLineNumber: number): string { @@ -720,14 +772,14 @@ export class SplitLinesCollection implements IViewModelLinesCollection { } else { // hit invisible line => flush request if (reqStart !== null) { - result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelLineIndex + 1, 1))); + result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelLineIndex + 1, 1), ownerId, filterOutValidation)); reqStart = null; } } } if (reqStart !== null) { - result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelEnd.lineNumber, modelEnd.column))); + result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation)); reqStart = null; } @@ -1149,8 +1201,13 @@ export class IdentityLinesCollection implements IViewModelLinesCollection { public warmUpLookupCache(viewStartLineNumber: number, viewEndLineNumber: number): void { } - public getViewLineIndentGuide(viewLineNumber: number): number { - return 0; + public getViewLinesIndentGuides(viewStartLineNumber: number, viewEndLineNumber: number): number[] { + const viewLineCount = viewEndLineNumber - viewStartLineNumber + 1; + let result = new Array(viewLineCount); + for (let i = 0; i < viewLineCount; i++) { + result[i] = 0; + } + return result; } public getViewLineContent(viewLineNumber: number): string { diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index 88787418a97..74e92e94582 100644 --- a/src/vs/editor/common/viewModel/viewModel.ts +++ b/src/vs/editor/common/viewModel/viewModel.ts @@ -134,7 +134,7 @@ export interface IViewModel { getTabSize(): number; getLineCount(): number; getLineContent(lineNumber: number): string; - getLineIndentGuide(lineNumber: number): number; + getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[]; getLineMinColumn(lineNumber: number): number; getLineMaxColumn(lineNumber: number): number; getLineFirstNonWhitespaceColumn(lineNumber: number): number; diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index 25a52e2f2b9..d5b4c9225b4 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -366,8 +366,8 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel this.lines.warmUpLookupCache(startLineNumber, endLineNumber); } - public getLineIndentGuide(lineNumber: number): number { - return this.lines.getViewLineIndentGuide(lineNumber); + public getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[] { + return this.lines.getViewLinesIndentGuides(startLineNumber, endLineNumber); } public getLineContent(lineNumber: number): string { diff --git a/src/vs/editor/contrib/comment/common/lineCommentCommand.ts b/src/vs/editor/contrib/comment/common/lineCommentCommand.ts index 8f0abccfd32..e1d5bec1202 100644 --- a/src/vs/editor/contrib/comment/common/lineCommentCommand.ts +++ b/src/vs/editor/contrib/comment/common/lineCommentCommand.ts @@ -270,7 +270,7 @@ export class LineCommentCommand implements editorCommon.ICommand { */ private _executeBlockComment(model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder, s: Selection): void { model.tokenizeIfCheap(s.startLineNumber); - let languageId = model.getLanguageIdAtPosition(s.startLineNumber, s.startColumn); + let languageId = model.getLanguageIdAtPosition(s.startLineNumber, 1); let config = LanguageConfigurationRegistry.getComments(languageId); if (!config || !config.blockCommentStartToken || !config.blockCommentEndToken) { // Mode does not support block comments diff --git a/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts index 57c946f76f9..743652c37a7 100644 --- a/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts +++ b/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts @@ -1002,4 +1002,20 @@ suite('Editor Contrib - Line Comment in mixed modes', () => { ); }); + test('issue #36173: Commenting code in JSX tag body', () => { + testLineCommentCommand( + [ + '
', + ' {123}', + '
', + ], + new Selection(2, 4, 2, 4), + [ + '
', + ' {/* {123} */}', + '
', + ], + new Selection(2, 8, 2, 8), + ); + }); }); diff --git a/src/vs/editor/contrib/find/browser/findWidget.ts b/src/vs/editor/contrib/find/browser/findWidget.ts index 7cb6a00b5f0..77c25acb251 100644 --- a/src/vs/editor/contrib/find/browser/findWidget.ts +++ b/src/vs/editor/contrib/find/browser/findWidget.ts @@ -921,7 +921,7 @@ class SimpleCheckbox extends Widget { this._label = document.createElement('label'); this._label.className = 'label'; - // Connect the label and the checkbox. Checkbox will get checked when the label recieves a click. + // Connect the label and the checkbox. Checkbox will get checked when the label receives a click. this._label.htmlFor = this._checkbox.id; this._label.tabIndex = -1; diff --git a/src/vs/editor/contrib/find/common/findController.ts b/src/vs/editor/contrib/find/common/findController.ts index 2c185f6f42d..4ead5ef999c 100644 --- a/src/vs/editor/contrib/find/common/findController.ts +++ b/src/vs/editor/contrib/find/common/findController.ts @@ -6,26 +6,18 @@ import * as nls from 'vs/nls'; import { HistoryNavigator } from 'vs/base/common/history'; -import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { Disposable } from 'vs/base/common/lifecycle'; import { ContextKeyExpr, RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { Range } from 'vs/editor/common/core/range'; -import { Selection } from 'vs/editor/common/core/selection'; import * as strings from 'vs/base/common/strings'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { editorAction, commonEditorContribution, ServicesAccessor, EditorAction, EditorCommand, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; +import { editorAction, ServicesAccessor, EditorAction, EditorCommand, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; import { FIND_IDS, FindModelBoundToEditorModel, ToggleCaseSensitiveKeybinding, ToggleRegexKeybinding, ToggleWholeWordKeybinding, ToggleSearchScopeKeybinding, ShowPreviousFindTermKeybinding, ShowNextFindTermKeybinding } from 'vs/editor/contrib/find/common/findModel'; import { FindReplaceState, FindReplaceStateChangedEvent, INewFindReplaceState } from 'vs/editor/contrib/find/common/findState'; import { getSelectionSearchString } from 'vs/editor/contrib/find/common/find'; -import { DocumentHighlightProviderRegistry } from 'vs/editor/common/modes'; -import { RunOnceScheduler, Delayer } from 'vs/base/common/async'; -import { CursorChangeReason, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; +import { Delayer } from 'vs/base/common/async'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; -import { overviewRulerSelectionHighlightForeground } from 'vs/platform/theme/common/colorRegistry'; -import { themeColorFromId } from 'vs/platform/theme/common/themeService'; -import { Constants } from 'vs/editor/common/core/uint'; export const enum FindStartFocusAction { NoFocusChange, @@ -515,631 +507,6 @@ export class StartFindReplaceAction extends EditorAction { } } -export interface IMultiCursorFindInput { - changeFindSearchString: boolean; - allowMultiline: boolean; - highlightFindOptions: boolean; -} - -export interface IMultiCursorFindResult { - searchText: string; - matchCase: boolean; - wholeWord: boolean; - - currentMatch: Selection; -} - -function multiCursorFind(editor: editorCommon.ICommonCodeEditor, input: IMultiCursorFindInput): IMultiCursorFindResult { - let controller = CommonFindController.get(editor); - if (!controller) { - return null; - } - let state = controller.getState(); - let searchText: string; - let currentMatch: Selection; - - // In any case, if the find widget was ever opened, the options are taken from it - let wholeWord = state.wholeWord; - let matchCase = state.matchCase; - - // Find widget owns what we search for if: - // - focus is not in the editor (i.e. it is in the find widget) - // - and the search widget is visible - // - and the search string is non-empty - if (!editor.isFocused() && state.isRevealed && state.searchString.length > 0) { - // Find widget owns what is searched for - searchText = state.searchString; - } else { - // Selection owns what is searched for - let s = editor.getSelection(); - - if (s.startLineNumber !== s.endLineNumber && !input.allowMultiline) { - // multiline forbidden - return null; - } - - if (s.isEmpty()) { - // selection is empty => expand to current word - let word = editor.getModel().getWordAtPosition(s.getStartPosition()); - if (!word) { - return null; - } - searchText = word.word; - currentMatch = new Selection(s.startLineNumber, word.startColumn, s.startLineNumber, word.endColumn); - } else { - searchText = editor.getModel().getValueInRange(s).replace(/\r\n/g, '\n'); - } - if (input.changeFindSearchString) { - controller.setSearchString(searchText); - } - } - - if (input.highlightFindOptions) { - controller.highlightFindOptions(); - } - - return { - searchText: searchText, - matchCase: matchCase, - wholeWord: wholeWord, - currentMatch: currentMatch - }; -} - -export abstract class SelectNextFindMatchAction extends EditorAction { - protected _getNextMatch(editor: editorCommon.ICommonCodeEditor): Selection { - let r = multiCursorFind(editor, { - changeFindSearchString: true, - allowMultiline: true, - highlightFindOptions: true - }); - if (!r) { - return null; - } - if (r.currentMatch) { - return r.currentMatch; - } - - let allSelections = editor.getSelections(); - let lastAddedSelection = allSelections[allSelections.length - 1]; - - let nextMatch = editor.getModel().findNextMatch(r.searchText, lastAddedSelection.getEndPosition(), false, r.matchCase, r.wholeWord ? editor.getConfiguration().wordSeparators : null, false); - - if (!nextMatch) { - return null; - } - - return new Selection(nextMatch.range.startLineNumber, nextMatch.range.startColumn, nextMatch.range.endLineNumber, nextMatch.range.endColumn); - } -} - -export abstract class SelectPreviousFindMatchAction extends EditorAction { - protected _getPreviousMatch(editor: editorCommon.ICommonCodeEditor): Selection { - let r = multiCursorFind(editor, { - changeFindSearchString: true, - allowMultiline: true, - highlightFindOptions: true - }); - if (!r) { - return null; - } - if (r.currentMatch) { - return r.currentMatch; - } - - let allSelections = editor.getSelections(); - let lastAddedSelection = allSelections[allSelections.length - 1]; - - let previousMatch = editor.getModel().findPreviousMatch(r.searchText, lastAddedSelection.getStartPosition(), false, r.matchCase, r.wholeWord ? editor.getConfiguration().wordSeparators : null, false); - - if (!previousMatch) { - return null; - } - - return new Selection(previousMatch.range.startLineNumber, previousMatch.range.startColumn, previousMatch.range.endLineNumber, previousMatch.range.endColumn); - } -} - -@editorAction -export class AddSelectionToNextFindMatchAction extends SelectNextFindMatchAction { - - constructor() { - super({ - id: FIND_IDS.AddSelectionToNextFindMatchAction, - label: nls.localize('addSelectionToNextFindMatch', "Add Selection To Next Find Match"), - alias: 'Add Selection To Next Find Match', - precondition: null, - kbOpts: { - kbExpr: EditorContextKeys.focus, - primary: KeyMod.CtrlCmd | KeyCode.KEY_D - } - }); - } - - public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { - const allSelections = editor.getSelections(); - - // If there are mulitple cursors, handle the case where they do not all select the same text. - if (allSelections.length > 1) { - const model = editor.getModel(); - const controller = CommonFindController.get(editor); - if (!controller) { - return; - } - const findState = controller.getState(); - const caseSensitive = findState.matchCase; - - let selectionsContainSameText = true; - - let selectedText = model.getValueInRange(allSelections[0]); - if (!caseSensitive) { - selectedText = selectedText.toLowerCase(); - } - for (let i = 1, len = allSelections.length; i < len; i++) { - let selection = allSelections[i]; - if (selection.isEmpty()) { - selectionsContainSameText = false; - break; - } - - let thisSelectedText = model.getValueInRange(selection); - if (!caseSensitive) { - thisSelectedText = thisSelectedText.toLowerCase(); - } - if (selectedText !== thisSelectedText) { - selectionsContainSameText = false; - break; - } - } - - if (!selectionsContainSameText) { - let resultingSelections: Selection[] = []; - for (let i = 0, len = allSelections.length; i < len; i++) { - let selection = allSelections[i]; - if (selection.isEmpty()) { - let word = editor.getModel().getWordAtPosition(selection.getStartPosition()); - if (word) { - resultingSelections[i] = new Selection(selection.startLineNumber, word.startColumn, selection.startLineNumber, word.endColumn); - continue; - } - } - resultingSelections[i] = selection; - } - editor.setSelections(resultingSelections); - return; - } - } - - let nextMatch = this._getNextMatch(editor); - - if (!nextMatch) { - return; - } - - editor.setSelections(allSelections.concat(nextMatch)); - editor.revealRangeInCenterIfOutsideViewport(nextMatch, editorCommon.ScrollType.Smooth); - } -} - -@editorAction -export class AddSelectionToPreviousFindMatchAction extends SelectPreviousFindMatchAction { - - constructor() { - super({ - id: FIND_IDS.AddSelectionToPreviousFindMatchAction, - label: nls.localize('addSelectionToPreviousFindMatch', "Add Selection To Previous Find Match"), - alias: 'Add Selection To Previous Find Match', - precondition: null - }); - } - - public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { - let previousMatch = this._getPreviousMatch(editor); - - if (!previousMatch) { - return; - } - - let allSelections = editor.getSelections(); - editor.setSelections(allSelections.concat(previousMatch)); - editor.revealRangeInCenterIfOutsideViewport(previousMatch, editorCommon.ScrollType.Smooth); - } -} - -@editorAction -export class MoveSelectionToNextFindMatchAction extends SelectNextFindMatchAction { - - constructor() { - super({ - id: FIND_IDS.MoveSelectionToNextFindMatchAction, - label: nls.localize('moveSelectionToNextFindMatch', "Move Last Selection To Next Find Match"), - alias: 'Move Last Selection To Next Find Match', - precondition: null, - kbOpts: { - kbExpr: EditorContextKeys.focus, - primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_D) - } - }); - } - - public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { - let nextMatch = this._getNextMatch(editor); - - if (!nextMatch) { - return; - } - - let allSelections = editor.getSelections(); - editor.setSelections(allSelections.slice(0, allSelections.length - 1).concat(nextMatch)); - editor.revealRangeInCenterIfOutsideViewport(nextMatch, editorCommon.ScrollType.Smooth); - } -} - -@editorAction -export class MoveSelectionToPreviousFindMatchAction extends SelectPreviousFindMatchAction { - - constructor() { - super({ - id: FIND_IDS.MoveSelectionToPreviousFindMatchAction, - label: nls.localize('moveSelectionToPreviousFindMatch', "Move Last Selection To Previous Find Match"), - alias: 'Move Last Selection To Previous Find Match', - precondition: null - }); - } - - public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { - let previousMatch = this._getPreviousMatch(editor); - - if (!previousMatch) { - return; - } - - let allSelections = editor.getSelections(); - editor.setSelections(allSelections.slice(0, allSelections.length - 1).concat(previousMatch)); - editor.revealRangeInCenterIfOutsideViewport(previousMatch, editorCommon.ScrollType.Smooth); - } -} - -export abstract class AbstractSelectHighlightsAction extends EditorAction { - public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { - const controller = CommonFindController.get(editor); - if (!controller) { - return null; - } - - let matches: editorCommon.FindMatch[] = null; - - const findState = controller.getState(); - if (findState.isRevealed && findState.isRegex && findState.searchString.length > 0) { - - matches = editor.getModel().findMatches(findState.searchString, true, findState.isRegex, findState.matchCase, findState.wholeWord ? editor.getConfiguration().wordSeparators : null, false, Constants.MAX_SAFE_SMALL_INTEGER); - - } else { - - const r = multiCursorFind(editor, { - changeFindSearchString: true, - allowMultiline: true, - highlightFindOptions: true - }); - if (!r) { - return; - } - - matches = editor.getModel().findMatches(r.searchText, true, false, r.matchCase, r.wholeWord ? editor.getConfiguration().wordSeparators : null, false, Constants.MAX_SAFE_SMALL_INTEGER); - } - - if (matches.length > 0) { - const editorSelection = editor.getSelection(); - for (let i = 0, len = matches.length; i < len; i++) { - const match = matches[i]; - let intersection = match.range.intersectRanges(editorSelection); - if (intersection) { - // bingo! - matches.splice(i, 1); - matches.unshift(match); - break; - } - } - editor.setSelections(matches.map(m => new Selection(m.range.startLineNumber, m.range.startColumn, m.range.endLineNumber, m.range.endColumn))); - } - } -} - -@editorAction -export class SelectHighlightsAction extends AbstractSelectHighlightsAction { - constructor() { - super({ - id: 'editor.action.selectHighlights', - label: nls.localize('selectAllOccurrencesOfFindMatch', "Select All Occurrences of Find Match"), - alias: 'Select All Occurrences of Find Match', - precondition: null, - kbOpts: { - kbExpr: EditorContextKeys.focus, - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_L - } - }); - } -} - -@editorAction -export class CompatChangeAll extends AbstractSelectHighlightsAction { - constructor() { - super({ - id: 'editor.action.changeAll', - label: nls.localize('changeAll.label', "Change All Occurrences"), - alias: 'Change All Occurrences', - precondition: EditorContextKeys.writable, - kbOpts: { - kbExpr: EditorContextKeys.textFocus, - primary: KeyMod.CtrlCmd | KeyCode.F2 - }, - menuOpts: { - group: '1_modification', - order: 1.2 - } - }); - } -} - -class SelectionHighlighterState { - public readonly lastWordUnderCursor: Selection; - public readonly searchText: string; - public readonly matchCase: boolean; - public readonly wordSeparators: string; - - constructor(lastWordUnderCursor: Selection, searchText: string, matchCase: boolean, wordSeparators: string) { - this.searchText = searchText; - this.matchCase = matchCase; - this.wordSeparators = wordSeparators; - } - - /** - * Everything equals except for `lastWordUnderCursor` - */ - public static softEquals(a: SelectionHighlighterState, b: SelectionHighlighterState): boolean { - if (!a && !b) { - return true; - } - if (!a || !b) { - return false; - } - return ( - a.searchText === b.searchText - && a.matchCase === b.matchCase - && a.wordSeparators === b.wordSeparators - ); - } -} - -@commonEditorContribution -export class SelectionHighlighter extends Disposable implements editorCommon.IEditorContribution { - private static ID = 'editor.contrib.selectionHighlighter'; - - private editor: editorCommon.ICommonCodeEditor; - private _isEnabled: boolean; - private decorations: string[]; - private updateSoon: RunOnceScheduler; - private state: SelectionHighlighterState; - - constructor(editor: editorCommon.ICommonCodeEditor) { - super(); - this.editor = editor; - this._isEnabled = editor.getConfiguration().contribInfo.selectionHighlight; - this.decorations = []; - this.updateSoon = this._register(new RunOnceScheduler(() => this._update(), 300)); - this.state = null; - - this._register(editor.onDidChangeConfiguration((e) => { - this._isEnabled = editor.getConfiguration().contribInfo.selectionHighlight; - })); - this._register(editor.onDidChangeCursorSelection((e: ICursorSelectionChangedEvent) => { - - if (!this._isEnabled) { - // Early exit if nothing needs to be done! - // Leave some form of early exit check here if you wish to continue being a cursor position change listener ;) - return; - } - - if (e.selection.isEmpty()) { - if (e.reason === CursorChangeReason.Explicit) { - if (this.state && (!this.state.lastWordUnderCursor || !this.state.lastWordUnderCursor.containsPosition(e.selection.getStartPosition()))) { - // no longer valid - this._setState(null); - } - this.updateSoon.schedule(); - } else { - this._setState(null); - - } - } else { - this._update(); - } - })); - this._register(editor.onDidChangeModel((e) => { - this._setState(null); - })); - this._register(CommonFindController.get(editor).getState().addChangeListener((e) => { - this._update(); - })); - } - - public getId(): string { - return SelectionHighlighter.ID; - } - - private _update(): void { - this._setState(SelectionHighlighter._createState(this._isEnabled, this.editor)); - } - - private static _createState(isEnabled: boolean, editor: editorCommon.ICommonCodeEditor): SelectionHighlighterState { - const model = editor.getModel(); - if (!model) { - return null; - } - - const config = editor.getConfiguration(); - - let lastWordUnderCursor: Selection = null; - if (!isEnabled) { - return null; - } - - const r = multiCursorFind(editor, { - changeFindSearchString: false, - allowMultiline: false, - highlightFindOptions: false - }); - if (!r) { - return null; - } - - const hasFindOccurrences = DocumentHighlightProviderRegistry.has(model); - if (r.currentMatch) { - // This is an empty selection - if (hasFindOccurrences) { - // Do not interfere with semantic word highlighting in the no selection case - return null; - } - - if (!config.contribInfo.occurrencesHighlight) { - return null; - } - - lastWordUnderCursor = r.currentMatch; - } - if (/^[ \t]+$/.test(r.searchText)) { - // whitespace only selection - return null; - } - if (r.searchText.length > 200) { - // very long selection - return null; - } - - const controller = CommonFindController.get(editor); - if (!controller) { - return null; - } - const findState = controller.getState(); - const caseSensitive = findState.matchCase; - - const selections = editor.getSelections(); - let firstSelectedText = model.getValueInRange(selections[0]); - if (!caseSensitive) { - firstSelectedText = firstSelectedText.toLowerCase(); - } - for (let i = 1; i < selections.length; i++) { - let selectedText = model.getValueInRange(selections[i]); - if (!caseSensitive) { - selectedText = selectedText.toLowerCase(); - } - if (firstSelectedText !== selectedText) { - // not all selections have the same text - return null; - } - } - - // Return early if the find widget shows the exact same matches - if (findState.isRevealed) { - let findStateSearchString = findState.searchString; - if (!caseSensitive) { - findStateSearchString = findStateSearchString.toLowerCase(); - } - - let mySearchString = r.searchText; - if (!caseSensitive) { - mySearchString = mySearchString.toLowerCase(); - } - - if (findStateSearchString === mySearchString && r.matchCase === findState.matchCase && r.wholeWord === findState.wholeWord && !findState.isRegex) { - return null; - } - } - - return new SelectionHighlighterState(lastWordUnderCursor, r.searchText, r.matchCase, r.wholeWord ? editor.getConfiguration().wordSeparators : null); - } - - - private _setState(state: SelectionHighlighterState): void { - if (SelectionHighlighterState.softEquals(this.state, state)) { - this.state = state; - return; - } - this.state = state; - - if (!this.state) { - if (this.decorations.length > 0) { - this.decorations = this.editor.deltaDecorations(this.decorations, []); - } - return; - } - - const model = this.editor.getModel(); - const hasFindOccurrences = DocumentHighlightProviderRegistry.has(model); - - let allMatches = model.findMatches(this.state.searchText, true, false, this.state.matchCase, this.state.wordSeparators, false).map(m => m.range); - allMatches.sort(Range.compareRangesUsingStarts); - - let selections = this.editor.getSelections(); - selections.sort(Range.compareRangesUsingStarts); - - // do not overlap with selection (issue #64 and #512) - let matches: Range[] = []; - for (let i = 0, j = 0, len = allMatches.length, lenJ = selections.length; i < len;) { - const match = allMatches[i]; - - if (j >= lenJ) { - // finished all editor selections - matches.push(match); - i++; - } else { - const cmp = Range.compareRangesUsingStarts(match, selections[j]); - if (cmp < 0) { - // match is before sel - matches.push(match); - i++; - } else if (cmp > 0) { - // sel is before match - j++; - } else { - // sel is equal to match - i++; - j++; - } - } - } - - const decorations = matches.map(r => { - return { - range: r, - // Show in overviewRuler only if model has no semantic highlighting - options: (hasFindOccurrences ? SelectionHighlighter._SELECTION_HIGHLIGHT : SelectionHighlighter._SELECTION_HIGHLIGHT_OVERVIEW) - }; - }); - - this.decorations = this.editor.deltaDecorations(this.decorations, decorations); - } - - private static _SELECTION_HIGHLIGHT_OVERVIEW = ModelDecorationOptions.register({ - stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - className: 'selectionHighlight', - overviewRuler: { - color: themeColorFromId(overviewRulerSelectionHighlightForeground), - darkColor: themeColorFromId(overviewRulerSelectionHighlightForeground), - position: editorCommon.OverviewRulerLane.Center - } - }); - - private static _SELECTION_HIGHLIGHT = ModelDecorationOptions.register({ - stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - className: 'selectionHighlight', - }); - - public dispose(): void { - this._setState(null); - super.dispose(); - } -} @editorAction export class ShowNextFindTermAction extends MatchFindAction { diff --git a/src/vs/editor/contrib/find/common/findModel.ts b/src/vs/editor/contrib/find/common/findModel.ts index dda6ca2f533..1536e8c9541 100644 --- a/src/vs/editor/contrib/find/common/findModel.ts +++ b/src/vs/editor/contrib/find/common/findModel.ts @@ -50,10 +50,6 @@ export const FIND_IDS = { PreviousMatchFindAction: 'editor.action.previousMatchFindAction', NextSelectionMatchFindAction: 'editor.action.nextSelectionMatchFindAction', PreviousSelectionMatchFindAction: 'editor.action.previousSelectionMatchFindAction', - AddSelectionToNextFindMatchAction: 'editor.action.addSelectionToNextFindMatch', - AddSelectionToPreviousFindMatchAction: 'editor.action.addSelectionToPreviousFindMatch', - MoveSelectionToNextFindMatchAction: 'editor.action.moveSelectionToNextFindMatch', - MoveSelectionToPreviousFindMatchAction: 'editor.action.moveSelectionToPreviousFindMatch', StartFindReplaceAction: 'editor.action.startFindReplaceAction', CloseFindWidgetCommand: 'closeFindWidget', ToggleCaseSensitiveCommand: 'toggleFindCaseSensitive', @@ -130,6 +126,10 @@ export class FindModelBoundToEditorModel { // The find model is disposed during a find state changed event return; } + if (!this._editor.getModel()) { + // The find model will be disposed momentarily + return; + } if (e.searchString || e.isReplaceRevealed || e.isRegex || e.wholeWord || e.matchCase || e.searchScope) { if (e.searchScope) { this.research(e.moveCursor, this._state.searchScope); diff --git a/src/vs/editor/contrib/find/common/findState.ts b/src/vs/editor/contrib/find/common/findState.ts index 0dccd531f7a..000ee49bfd5 100644 --- a/src/vs/editor/contrib/find/common/findState.ts +++ b/src/vs/editor/contrib/find/common/findState.ts @@ -25,17 +25,36 @@ export interface FindReplaceStateChangedEvent { currentMatch: boolean; } +export const enum FindOptionOverride { + NotSet = 0, + True = 1, + False = 2 +} + export interface INewFindReplaceState { searchString?: string; replaceString?: string; isRevealed?: boolean; isReplaceRevealed?: boolean; isRegex?: boolean; + isRegexOverride?: FindOptionOverride; wholeWord?: boolean; + wholeWordOverride?: FindOptionOverride; matchCase?: boolean; + matchCaseOverride?: FindOptionOverride; searchScope?: Range; } +function effectiveOptionValue(override: FindOptionOverride, value: boolean): boolean { + if (override === FindOptionOverride.True) { + return true; + } + if (override === FindOptionOverride.False) { + return false; + } + return value; +} + export class FindReplaceState implements IDisposable { private static _CHANGED_EVENT = 'changed'; @@ -45,8 +64,11 @@ export class FindReplaceState implements IDisposable { private _isRevealed: boolean; private _isReplaceRevealed: boolean; private _isRegex: boolean; + private _isRegexOverride: FindOptionOverride; private _wholeWord: boolean; + private _wholeWordOverride: FindOptionOverride; private _matchCase: boolean; + private _matchCaseOverride: FindOptionOverride; private _searchScope: Range; private _matchesPosition: number; private _matchesCount: number; @@ -57,9 +79,9 @@ export class FindReplaceState implements IDisposable { public get replaceString(): string { return this._replaceString; } public get isRevealed(): boolean { return this._isRevealed; } public get isReplaceRevealed(): boolean { return this._isReplaceRevealed; } - public get isRegex(): boolean { return this._isRegex; } - public get wholeWord(): boolean { return this._wholeWord; } - public get matchCase(): boolean { return this._matchCase; } + public get isRegex(): boolean { return effectiveOptionValue(this._isRegexOverride, this._isRegex); } + public get wholeWord(): boolean { return effectiveOptionValue(this._wholeWordOverride, this._wholeWord); } + public get matchCase(): boolean { return effectiveOptionValue(this._matchCaseOverride, this._matchCase); } public get searchScope(): Range { return this._searchScope; } public get matchesPosition(): number { return this._matchesPosition; } public get matchesCount(): number { return this._matchesCount; } @@ -71,8 +93,11 @@ export class FindReplaceState implements IDisposable { this._isRevealed = false; this._isReplaceRevealed = false; this._isRegex = false; + this._isRegexOverride = FindOptionOverride.NotSet; this._wholeWord = false; + this._wholeWordOverride = FindOptionOverride.NotSet; this._matchCase = false; + this._matchCaseOverride = FindOptionOverride.NotSet; this._searchScope = null; this._matchesPosition = 0; this._matchesCount = 0; @@ -155,6 +180,10 @@ export class FindReplaceState implements IDisposable { }; let somethingChanged = false; + const oldEffectiveIsRegex = this.isRegex; + const oldEffectiveWholeWords = this.wholeWord; + const oldEffectiveMatchCase = this.matchCase; + if (typeof newState.searchString !== 'undefined') { if (this._searchString !== newState.searchString) { this._searchString = newState.searchString; @@ -184,25 +213,13 @@ export class FindReplaceState implements IDisposable { } } if (typeof newState.isRegex !== 'undefined') { - if (this._isRegex !== newState.isRegex) { - this._isRegex = newState.isRegex; - changeEvent.isRegex = true; - somethingChanged = true; - } + this._isRegex = newState.isRegex; } if (typeof newState.wholeWord !== 'undefined') { - if (this._wholeWord !== newState.wholeWord) { - this._wholeWord = newState.wholeWord; - changeEvent.wholeWord = true; - somethingChanged = true; - } + this._wholeWord = newState.wholeWord; } if (typeof newState.matchCase !== 'undefined') { - if (this._matchCase !== newState.matchCase) { - this._matchCase = newState.matchCase; - changeEvent.matchCase = true; - somethingChanged = true; - } + this._matchCase = newState.matchCase; } if (typeof newState.searchScope !== 'undefined') { if (!Range.equalsRange(this._searchScope, newState.searchScope)) { @@ -212,6 +229,24 @@ export class FindReplaceState implements IDisposable { } } + // Overrides get set when they explicitly come in and get reset anytime something else changes + this._isRegexOverride = (typeof newState.isRegexOverride !== 'undefined' ? newState.isRegexOverride : FindOptionOverride.NotSet); + this._wholeWordOverride = (typeof newState.wholeWordOverride !== 'undefined' ? newState.wholeWordOverride : FindOptionOverride.NotSet); + this._matchCaseOverride = (typeof newState.matchCaseOverride !== 'undefined' ? newState.matchCaseOverride : FindOptionOverride.NotSet); + + if (oldEffectiveIsRegex !== this.isRegex) { + somethingChanged = true; + changeEvent.isRegex = true; + } + if (oldEffectiveWholeWords !== this.wholeWord) { + somethingChanged = true; + changeEvent.wholeWord = true; + } + if (oldEffectiveMatchCase !== this.matchCase) { + somethingChanged = true; + changeEvent.matchCase = true; + } + if (somethingChanged) { this._eventEmitter.emit(FindReplaceState._CHANGED_EVENT, changeEvent); } diff --git a/src/vs/editor/contrib/find/test/common/findController.test.ts b/src/vs/editor/contrib/find/test/common/findController.test.ts index 20559f5713b..323f3f0ce42 100644 --- a/src/vs/editor/contrib/find/test/common/findController.test.ts +++ b/src/vs/editor/contrib/find/test/common/findController.test.ts @@ -11,20 +11,16 @@ import { EditOperation } from 'vs/editor/common/core/editOperation'; import { Position } from 'vs/editor/common/core/position'; import { Selection } from 'vs/editor/common/core/selection'; import { Range } from 'vs/editor/common/core/range'; -import { EndOfLineSequence, ICommonCodeEditor, Handler } from 'vs/editor/common/editorCommon'; -import { - CommonFindController, FindStartFocusAction, IFindStartOptions, - NextMatchFindAction, StartFindAction, SelectHighlightsAction, - AddSelectionToNextFindMatchAction -} from 'vs/editor/contrib/find/common/findController'; -import { MockCodeEditor, withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor'; +import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; +import { CommonFindController, FindStartFocusAction, IFindStartOptions, NextMatchFindAction, StartFindAction } from 'vs/editor/contrib/find/common/findController'; +import { withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor'; import { HistoryNavigator } from 'vs/base/common/history'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { Delayer } from 'vs/base/common/async'; -class TestFindController extends CommonFindController { +export class TestFindController extends CommonFindController { public hasFocus: boolean; public delayUpdateHistory: boolean = false; @@ -188,60 +184,6 @@ suite('FindController', () => { }); }); - test('issue #8817: Cursor position changes when you cancel multicursor', () => { - withMockCodeEditor([ - 'var x = (3 * 5)', - 'var y = (3 * 5)', - 'var z = (3 * 5)', - ], { serviceCollection: serviceCollection }, (editor, cursor) => { - - let findController = editor.registerAndInstantiateContribution(TestFindController); - let selectHighlightsAction = new SelectHighlightsAction(); - - editor.setSelection(new Selection(2, 9, 2, 16)); - - selectHighlightsAction.run(null, editor); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [2, 9, 2, 16], - [1, 9, 1, 16], - [3, 9, 3, 16], - ]); - - editor.trigger('test', 'removeSecondaryCursors', null); - - assert.deepEqual(fromRange(editor.getSelection()), [2, 9, 2, 16]); - - findController.dispose(); - }); - }); - - test('issue #5400: "Select All Occurrences of Find Match" does not select all if find uses regex', () => { - withMockCodeEditor([ - 'something', - 'someething', - 'someeething', - 'nothing' - ], { serviceCollection: serviceCollection }, (editor, cursor) => { - - let findController = editor.registerAndInstantiateContribution(TestFindController); - let selectHighlightsAction = new SelectHighlightsAction(); - - editor.setSelection(new Selection(1, 1, 1, 1)); - findController.getState().change({ searchString: 'some+thing', isRegex: true, isRevealed: true }, false); - - selectHighlightsAction.run(null, editor); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [1, 1, 1, 10], - [2, 1, 2, 11], - [3, 1, 3, 12], - ]); - - assert.equal(findController.getState().searchString, 'some+thing'); - - findController.dispose(); - }); - }); - test('issue #9043: Clear search scope when find widget is hidden', () => { withMockCodeEditor([ 'var x = (3 * 5)', @@ -380,119 +322,6 @@ suite('FindController', () => { }); }); - test('AddSelectionToNextFindMatchAction can work with multiline', () => { - withMockCodeEditor([ - '', - 'qwe', - 'rty', - '', - 'qwe', - '', - 'rty', - 'qwe', - 'rty' - ], { serviceCollection: serviceCollection }, (editor, cursor) => { - - let findController = editor.registerAndInstantiateContribution(TestFindController); - let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); - - editor.setSelection(new Selection(2, 1, 3, 4)); - - addSelectionToNextFindMatch.run(null, editor); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [2, 1, 3, 4], - [8, 1, 9, 4] - ]); - - editor.trigger('test', 'removeSecondaryCursors', null); - - assert.deepEqual(fromRange(editor.getSelection()), [2, 1, 3, 4]); - - findController.dispose(); - }); - }); - - test('issue #6661: AddSelectionToNextFindMatchAction can work with touching ranges', () => { - withMockCodeEditor([ - 'abcabc', - 'abc', - 'abcabc', - ], { serviceCollection: serviceCollection }, (editor, cursor) => { - - let findController = editor.registerAndInstantiateContribution(TestFindController); - let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); - - editor.setSelection(new Selection(1, 1, 1, 4)); - - addSelectionToNextFindMatch.run(null, editor); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [1, 1, 1, 4], - [1, 4, 1, 7] - ]); - - addSelectionToNextFindMatch.run(null, editor); - addSelectionToNextFindMatch.run(null, editor); - addSelectionToNextFindMatch.run(null, editor); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [1, 1, 1, 4], - [1, 4, 1, 7], - [2, 1, 2, 4], - [3, 1, 3, 4], - [3, 4, 3, 7] - ]); - - editor.trigger('test', Handler.Type, { text: 'z' }); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [1, 2, 1, 2], - [1, 3, 1, 3], - [2, 2, 2, 2], - [3, 2, 3, 2], - [3, 3, 3, 3] - ]); - assert.equal(editor.getValue(), [ - 'zz', - 'z', - 'zz', - ].join('\n')); - - findController.dispose(); - }); - }); - - test('issue #23541: Multiline Ctrl+D does not work in CRLF files', () => { - withMockCodeEditor([ - '', - 'qwe', - 'rty', - '', - 'qwe', - '', - 'rty', - 'qwe', - 'rty' - ], { serviceCollection: serviceCollection }, (editor, cursor) => { - - editor.getModel().setEOL(EndOfLineSequence.CRLF); - - let findController = editor.registerAndInstantiateContribution(TestFindController); - let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); - - editor.setSelection(new Selection(2, 1, 3, 4)); - - addSelectionToNextFindMatch.run(null, editor); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [2, 1, 3, 4], - [8, 1, 9, 4] - ]); - - editor.trigger('test', 'removeSecondaryCursors', null); - - assert.deepEqual(fromRange(editor.getSelection()), [2, 1, 3, 4]); - - findController.dispose(); - }); - }); - test('issue #18111: Regex replace with single space replaces with no space', () => { withMockCodeEditor([ 'HRESULT OnAmbientPropertyChange(DISPID dispid);' @@ -555,237 +384,6 @@ suite('FindController', () => { } return result; } - - function testAddSelectionToNextFindMatchAction(text: string[], callback: (editor: MockCodeEditor, action: AddSelectionToNextFindMatchAction, findController: TestFindController) => void): void { - withMockCodeEditor(text, { serviceCollection: serviceCollection }, (editor, cursor) => { - - let findController = editor.registerAndInstantiateContribution(TestFindController); - - let action = new AddSelectionToNextFindMatchAction(); - - callback(editor, action, findController); - - findController.dispose(); - }); - } - - test('AddSelectionToNextFindMatchAction starting with single collapsed selection', () => { - const text = [ - 'abc pizza', - 'abc house', - 'abc bar' - ]; - testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { - editor.setSelections([ - new Selection(1, 2, 1, 2), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - }); - }); - - test('AddSelectionToNextFindMatchAction starting with two selections, one being collapsed 1)', () => { - const text = [ - 'abc pizza', - 'abc house', - 'abc bar' - ]; - testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { - editor.setSelections([ - new Selection(1, 1, 1, 4), - new Selection(2, 2, 2, 2), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - }); - }); - - test('AddSelectionToNextFindMatchAction starting with two selections, one being collapsed 2)', () => { - const text = [ - 'abc pizza', - 'abc house', - 'abc bar' - ]; - testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { - editor.setSelections([ - new Selection(1, 2, 1, 2), - new Selection(2, 1, 2, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - }); - }); - - test('AddSelectionToNextFindMatchAction starting with all collapsed selections', () => { - const text = [ - 'abc pizza', - 'abc house', - 'abc bar' - ]; - testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { - editor.setSelections([ - new Selection(1, 2, 1, 2), - new Selection(2, 2, 2, 2), - new Selection(3, 1, 3, 1), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - }); - }); - - test('AddSelectionToNextFindMatchAction starting with all collapsed selections on different words', () => { - const text = [ - 'abc pizza', - 'abc house', - 'abc bar' - ]; - testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { - editor.setSelections([ - new Selection(1, 6, 1, 6), - new Selection(2, 6, 2, 6), - new Selection(3, 6, 3, 6), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 5, 1, 10), - new Selection(2, 5, 2, 10), - new Selection(3, 5, 3, 8), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 5, 1, 10), - new Selection(2, 5, 2, 10), - new Selection(3, 5, 3, 8), - ]); - }); - }); - - test('issue #20651: AddSelectionToNextFindMatchAction case insensitive', () => { - const text = [ - 'test', - 'testte', - 'Test', - 'testte', - 'test' - ]; - testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { - editor.setSelections([ - new Selection(1, 1, 1, 5), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 5), - new Selection(2, 1, 2, 5), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 5), - new Selection(2, 1, 2, 5), - new Selection(3, 1, 3, 5), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 5), - new Selection(2, 1, 2, 5), - new Selection(3, 1, 3, 5), - new Selection(4, 1, 4, 5), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 5), - new Selection(2, 1, 2, 5), - new Selection(3, 1, 3, 5), - new Selection(4, 1, 4, 5), - new Selection(5, 1, 5, 5), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 5), - new Selection(2, 1, 2, 5), - new Selection(3, 1, 3, 5), - new Selection(4, 1, 4, 5), - new Selection(5, 1, 5, 5), - ]); - }); - }); }); suite('FindController query options persistence', () => { diff --git a/src/vs/editor/contrib/folding/browser/folding.ts b/src/vs/editor/contrib/folding/browser/folding.ts index e9f50ac58f7..0c3602f5968 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -13,12 +13,11 @@ import { RunOnceScheduler, Delayer } from 'vs/base/common/async'; import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; -import { ICommonCodeEditor, ScrollType } from 'vs/editor/common/editorCommon'; +import { ICommonCodeEditor, ScrollType, IModel } from 'vs/editor/common/editorCommon'; import { editorAction, ServicesAccessor, EditorAction, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; -import { FoldingModel, setCollapseStateAtLevel, setCollapseStateDown, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp } from 'vs/editor/contrib/folding/common/foldingModel'; -import { computeRanges, limitByIndent } from 'vs/editor/contrib/folding/common/indentFoldStrategy'; +import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp } from 'vs/editor/contrib/folding/common/foldingModel'; import { FoldingDecorationProvider } from './foldingDecorations'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; @@ -166,15 +165,9 @@ export class FoldingController { this.onModelContentChanged(); } - private computeRanges() { - let editorModel = this.editor.getModel(); - if (editorModel) { - let ranges = computeRanges(editorModel); - ranges = limitByIndent(ranges, FoldingController.MAX_FOLDING_REGIONS).sort((r1, r2) => r1.startLineNumber - r2.startLineNumber); - return ranges; - } - - return []; + private computeRanges(editorModel: IModel) { + let ranges = editorModel.getIndentRanges(); + return ranges; } public getFoldingModel() { @@ -184,7 +177,7 @@ export class FoldingController { private onModelContentChanged() { this.foldingModelPromise = this.updateScheduler.trigger(() => { if (this.foldingModel) { // null if editor has been disposed, or folding turned off - this.foldingModel.update(this.computeRanges()); + this.foldingModel.update(this.computeRanges(this.foldingModel.textModel)); } return this.foldingModel; }); @@ -211,7 +204,7 @@ export class FoldingController { for (let selection of selections) { let lineNumber = selection.selectionStartLineNumber; if (this.hiddenRangeModel.isHidden(lineNumber)) { - let toToggle = foldingModel.getAllRegionsAtLine(lineNumber, r => r.isCollapsed && lineNumber > r.range.startLineNumber); + let toToggle = foldingModel.getAllRegionsAtLine(lineNumber, r => r.isCollapsed && lineNumber > r.startLineNumber); foldingModel.toggleCollapseState(toToggle); } } @@ -406,9 +399,9 @@ class UnfoldAction extends FoldingAction { let levels = args && args.levels || 1; let lineNumbers = this.getLineNumbers(args, editor); if (args && args.direction === 'up') { - setCollapseStateLevelsUp(foldingModel, levels, false, lineNumbers); + setCollapseStateLevelsUp(foldingModel, false, levels, lineNumbers); } else { - setCollapseStateLevelsDown(foldingModel, levels, false, lineNumbers); + setCollapseStateLevelsDown(foldingModel, false, levels, lineNumbers); } } } @@ -430,7 +423,7 @@ class UnFoldRecursivelyAction extends FoldingAction { } invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICommonCodeEditor, args: any): void { - setCollapseStateDown(foldingModel, false, this.getSelectedLines(editor)); + setCollapseStateLevelsDown(foldingModel, false, Number.MAX_VALUE, this.getSelectedLines(editor)); } } @@ -471,9 +464,9 @@ class FoldAction extends FoldingAction { let levels = args && args.levels || 1; let lineNumbers = this.getLineNumbers(args, editor); if (args && args.direction === 'up') { - setCollapseStateLevelsUp(foldingModel, levels, true, lineNumbers); + setCollapseStateLevelsUp(foldingModel, true, levels, lineNumbers); } else { - setCollapseStateLevelsDown(foldingModel, levels, true, lineNumbers); + setCollapseStateLevelsDown(foldingModel, true, levels, lineNumbers); } } } @@ -496,7 +489,7 @@ class FoldRecursivelyAction extends FoldingAction { invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICommonCodeEditor): void { let selectedLines = this.getSelectedLines(editor); - setCollapseStateDown(foldingModel, true, selectedLines); + setCollapseStateLevelsDown(foldingModel, true, Number.MAX_VALUE, selectedLines); if (selectedLines.length > 0) { foldingController.reveal(selectedLines[0]); } @@ -521,7 +514,7 @@ class FoldAllAction extends FoldingAction { } invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICommonCodeEditor): void { - setCollapseStateDown(foldingModel, true); + setCollapseStateLevelsDown(foldingModel, true); } } @@ -542,7 +535,7 @@ class UnfoldAllAction extends FoldingAction { } invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICommonCodeEditor): void { - setCollapseStateDown(foldingModel, false); + setCollapseStateLevelsDown(foldingModel, false); } } diff --git a/src/vs/editor/contrib/folding/common/foldingModel.ts b/src/vs/editor/contrib/folding/common/foldingModel.ts index 61429293e21..f0eb43ed984 100644 --- a/src/vs/editor/contrib/folding/common/foldingModel.ts +++ b/src/vs/editor/contrib/folding/common/foldingModel.ts @@ -5,24 +5,13 @@ import { IModel, IModelDecorationOptions } from 'vs/editor/common/editorCommon'; import Event, { Emitter } from 'vs/base/common/event'; - -export interface IFoldingRange extends ILineRange { - indent: number; -} +import { IndentRanges } from 'vs/editor/common/model/indentRanges'; export interface ILineRange { startLineNumber: number; endLineNumber: number; } -export function toString(range: IFoldingRange): string { - return (range ? range.startLineNumber + '/' + range.endLineNumber : 'null') + ' - ' + range.indent; -} - -export interface IFoldingRangeProvider { - getFoldingRanges(textModel: IModel): Thenable; -} - export interface IDecorationProvider { getDecorationOption(region: FoldingRegion): IModelDecorationOptions; } @@ -39,6 +28,8 @@ export class FoldingModel { private _decorationProvider: IDecorationProvider; private _regions: FoldingRegion[] = []; + private _ranges: IndentRanges; + private _updateEventEmitter = new Emitter(); public get regions(): FoldingRegion[] { return this._regions; }; @@ -57,7 +48,7 @@ export class FoldingModel { let processed = {}; this._textModel.changeDecorations(accessor => { for (let region of regions) { - if (!processed[region.editorDecorationId]) { + if (region.editorDecorationId && !processed[region.editorDecorationId]) { processed[region.editorDecorationId] = true; region.isCollapsed = !region.isCollapsed; accessor.changeDecorationOptions(region.editorDecorationId, this._decorationProvider.getDecorationOption(region)); @@ -67,20 +58,20 @@ export class FoldingModel { this._updateEventEmitter.fire({ model: this, collapseStateChanged: regions }); } - public update(newRanges: IFoldingRange[]): void { + public update(newRanges: IndentRanges): void { let editorDecorationIds = []; let newEditorDecorations = []; // remember the latest start line numbers of the collapsed regions let collapsedStartLineNumbers: number[] = []; for (let region of this._regions) { - if (region.isCollapsed) { - let decRange = this._textModel.getDecorationRange(region.editorDecorationId); - if (decRange) { - collapsedStartLineNumbers.push(decRange.startLineNumber); - } - } if (region.editorDecorationId) { + if (region.isCollapsed) { + let decRange = this._textModel.getDecorationRange(region.editorDecorationId); + if (decRange) { + collapsedStartLineNumbers.push(decRange.startLineNumber); + } + } editorDecorationIds.push(region.editorDecorationId); } } @@ -88,12 +79,12 @@ export class FoldingModel { let recycleBin = this._regions; let newRegions = []; - let newRegion = (range: IFoldingRange, isCollapsed: boolean) => { + let newRegion = (ranges: IndentRanges, index: number, isCollapsed: boolean) => { let region = recycleBin.length ? recycleBin.pop() : new FoldingRegion(); - region.init(range, isCollapsed); + region.init(ranges, index, isCollapsed); newRegions.push(region); - let startLineNumber = range.startLineNumber; + let startLineNumber = region.startLineNumber; let maxColumn = this._textModel.getLineMaxColumn(startLineNumber); let decorationRange = { startLineNumber: startLineNumber, @@ -107,23 +98,23 @@ export class FoldingModel { let k = 0, i = 0; while (i < collapsedStartLineNumbers.length && k < newRanges.length) { let collapsedStartLineNumber = collapsedStartLineNumbers[i]; - while (k < newRanges.length && collapsedStartLineNumber > newRanges[k].startLineNumber) { - newRegion(newRanges[k], false); + while (k < newRanges.length && collapsedStartLineNumber > newRanges.getStartLineNumber(k)) { + newRegion(newRanges, k, false); k++; } if (k < newRanges.length) { - let currRange = newRanges[k]; - if (collapsedStartLineNumber < currRange.startLineNumber) { + let currStartLineNumber = newRanges.getStartLineNumber(k); + if (collapsedStartLineNumber < currStartLineNumber) { i++; - } else if (collapsedStartLineNumber === currRange.startLineNumber) { - newRegion(newRanges[k], true); + } else if (collapsedStartLineNumber === currStartLineNumber) { + newRegion(newRanges, k, true); i++; k++; } } } while (k < newRanges.length) { - newRegion(newRanges[k], false); + newRegion(newRanges, k, false); k++; } @@ -133,6 +124,7 @@ export class FoldingModel { } this._regions = newRegions; + this._ranges = newRanges; this._updateEventEmitter.fire({ model: this }); } @@ -146,7 +138,7 @@ export class FoldingModel { let range = this._textModel.getDecorationRange(region.editorDecorationId); if (range) { let startLineNumber = range.startLineNumber; - let endLineNumber = range.endLineNumber + region.range.endLineNumber - region.range.startLineNumber; + let endLineNumber = range.endLineNumber + region.endLineNumber - region.startLineNumber; collapsedRanges.push({ startLineNumber, endLineNumber }); } } @@ -184,68 +176,52 @@ export class FoldingModel { this._textModel.deltaDecorations(editorDecorationIds, []); } - getAllRegionsAtLine(lineNumber: number, filter?: (r: FoldingRegion) => boolean): FoldingRegion[] { + getAllRegionsAtLine(lineNumber: number, filter?: (r: FoldingRegion, level: number) => boolean): FoldingRegion[] { let result: FoldingRegion[] = []; - for (let i = 0, len = this.regions.length; i < len; i++) { - let current = this.regions[i]; - if (current.range.endLineNumber < lineNumber) { - continue; - } - let startLineNumber = current.range.startLineNumber; - if (startLineNumber <= lineNumber) { - if (!filter || filter(current)) { + if (this._ranges) { + let index = this._ranges.findRange(lineNumber); + let level = 1; + while (index >= 0) { + let current = this._regions[index]; + if (!filter || filter(current, level)) { result.push(current); } - } else { - break; + level++; + index = current.parentIndex; } } return result; } - getRegionAtLine(lineNumber: number): FoldingRegion { - let result: FoldingRegion; - for (let i = 0, len = this.regions.length; i < len; i++) { - let current = this.regions[i]; - if (current.range.endLineNumber < lineNumber) { - continue; - } - let startLineNumber = current.range.startLineNumber; - if (startLineNumber <= lineNumber) { - result = current; - } else { - break; - } + if (this._ranges) { + let index = this._ranges.findRange(lineNumber); + if (index >= 0) { + return this._regions[index]; + }; } - return result; + return null; } - getRegionsInside(range: ILineRange, filter?: (r: FoldingRegion, level?: number) => boolean): FoldingRegion[] { + getRegionsInside(region: FoldingRegion, filter?: (r: FoldingRegion, level?: number) => boolean): FoldingRegion[] { let result = []; let trackLevel = filter && filter.length === 2; - let levelStack: ILineRange[] = trackLevel ? [range] : null;; - - for (let i = 0, len = this.regions.length; i < len; i++) { + let levelStack: FoldingRegion[] = trackLevel ? [] : null; + let index = region ? region.regionIndex + 1 : 0; + let endLineNumber = region ? region.endLineNumber : Number.MAX_VALUE; + for (let i = index, len = this.regions.length; i < len; i++) { let current = this.regions[i]; - let endLineNumber = current.range.endLineNumber; - if (endLineNumber <= range.startLineNumber) { - continue; - } - let startLineNumber = current.range.startLineNumber; - if (startLineNumber < range.endLineNumber) { - if (endLineNumber <= range.endLineNumber && startLineNumber >= range.startLineNumber) { - if (trackLevel) { - while (!current.containedBy(levelStack[levelStack.length - 1])) { - levelStack.pop(); - } - levelStack.push(current.range); - if (filter(current, levelStack.length - 1)) { - result.push(current); - } - } else if (!filter || filter(current)) { + if (current.startLineNumber < endLineNumber) { + if (trackLevel) { + while (levelStack.length > 0 && !current.containedBy(levelStack[levelStack.length - 1])) { + levelStack.pop(); + } + levelStack.push(current); + if (filter(current, levelStack.length)) { result.push(current); } + } else if (!filter || filter(current)) { + result.push(current); } } else { break; @@ -260,85 +236,94 @@ export class FoldingRegion { public editorDecorationId: string; public isCollapsed: boolean; - public range: IFoldingRange; + private index: number; + private indentRanges: IndentRanges; constructor() { } - public init(range: IFoldingRange, isCollapsed: boolean): void { - this.range = range; + public init(indentRanges: IndentRanges, index: number, isCollapsed: boolean): void { + this.indentRanges = indentRanges; + this.index = index; this.isCollapsed = isCollapsed; this.editorDecorationId = void 0; } + + public get startLineNumber() { + return this.indentRanges.getStartLineNumber(this.index); + } + + public get endLineNumber() { + return this.indentRanges.getEndLineNumber(this.index); + } + + public get regionIndex() { + return this.index; + } + + public get parentIndex() { + return this.indentRanges.getParentIndex(this.index); + } + isAfterLine(lineNumber: number): boolean { - return lineNumber < this.range.startLineNumber; + return lineNumber < this.startLineNumber; } isBeforeLine(lineNumber: number): boolean { - return lineNumber > this.range.endLineNumber; + return lineNumber > this.endLineNumber; } contains(range: ILineRange): boolean { - return this.range.startLineNumber <= range.startLineNumber && this.range.endLineNumber >= range.endLineNumber; + return this.startLineNumber <= range.startLineNumber && this.endLineNumber >= range.endLineNumber; } containedBy(range: ILineRange): boolean { - return range.startLineNumber <= this.range.startLineNumber && range.endLineNumber >= this.range.endLineNumber; + return range.startLineNumber <= this.startLineNumber && range.endLineNumber >= this.endLineNumber; } containsLine(lineNumber: number) { - return this.range.startLineNumber <= lineNumber && lineNumber <= this.range.endLineNumber; + return this.startLineNumber <= lineNumber && lineNumber <= this.endLineNumber; } hidesLine(lineNumber: number) { - return this.range.startLineNumber < lineNumber && lineNumber <= this.range.endLineNumber; + return this.startLineNumber < lineNumber && lineNumber <= this.endLineNumber; } } -export function setCollapseStateLevelsDown(foldingModel: FoldingModel, levels: number, doCollapse: boolean, lineNumbers?: number[]) { - let toToggle = []; - for (let lineNumber of lineNumbers) { - let region = foldingModel.getRegionAtLine(lineNumber); - if (region) { - if (levels === 1) { - if (region.isCollapsed !== doCollapse) { - toToggle.push(region); - } - } else { - let regionsInside = foldingModel.getRegionsInside(region.range, (r, level) => r.isCollapsed !== doCollapse && level <= levels); - toToggle.push(...regionsInside); - } - } - } - foldingModel.toggleCollapseState(toToggle); -} - -export function setCollapseStateLevelsUp(foldingModel: FoldingModel, levels: number, doCollapse: boolean, lineNumbers?: number[]) { - let toToggle = []; - for (let lineNumber of lineNumbers) { - let regions = foldingModel.getAllRegionsAtLine(lineNumber); - for (let i = 0; i < levels && regions.length > 0; i++) { - let region = regions.pop(); - if (region.isCollapsed !== doCollapse) { - toToggle.push(region); - } - } - } - foldingModel.toggleCollapseState(toToggle); -} - /** * Collapse or expand the regions at the given locations including all children. * @param doCollapse Wheter to collase or expand - * @param lineNumbers the regions to fold, or if not set all regions in the model. + * @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels. + * @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model. */ -export function setCollapseStateDown(foldingModel: FoldingModel, doCollapse: boolean, lineNumbers?: number[]): void { +export function setCollapseStateLevelsDown(foldingModel: FoldingModel, doCollapse: boolean, levels = Number.MAX_VALUE, lineNumbers?: number[]) { let toToggle = []; - if (!lineNumbers) { - toToggle = foldingModel.regions.filter(region => region.isCollapsed !== doCollapse); - } else { + if (lineNumbers && lineNumbers.length > 0) { for (let lineNumber of lineNumbers) { let region = foldingModel.getRegionAtLine(lineNumber); if (region) { - let regionsInside = foldingModel.getRegionsInside(region.range, r => r.isCollapsed !== doCollapse); - toToggle.push(...regionsInside); + if (region.isCollapsed !== doCollapse) { + toToggle.push(region); + } + if (levels > 1) { + let regionsInside = foldingModel.getRegionsInside(region, (r, level) => r.isCollapsed !== doCollapse && level < levels); + toToggle.push(...regionsInside); + } } } + } else { + let regionsInside = foldingModel.getRegionsInside(null, (r, level) => r.isCollapsed !== doCollapse && level < levels); + toToggle.push(...regionsInside); + } + foldingModel.toggleCollapseState(toToggle); +} + +/** + * Collapse or expand the regions at the given locations including all parents. + * @param doCollapse Wheter to collase or expand + * @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels. + * @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model. + */ +export function setCollapseStateLevelsUp(foldingModel: FoldingModel, doCollapse: boolean, levels: number, lineNumbers: number[]) { + let toToggle = []; + for (let lineNumber of lineNumbers) { + let regions = foldingModel.getAllRegionsAtLine(lineNumber, (region, level) => region.isCollapsed !== doCollapse && level <= levels); + toToggle.push(...regions); } foldingModel.toggleCollapseState(toToggle); } @@ -351,6 +336,6 @@ export function setCollapseStateDown(foldingModel: FoldingModel, doCollapse: boo */ export function setCollapseStateAtLevel(foldingModel: FoldingModel, foldLevel: number, doCollapse: boolean, blockedLineNumbers: number[]): void { let filter = (region, level) => level === foldLevel && region.isCollapsed !== doCollapse && !blockedLineNumbers.some(line => region.containsLine(line)); - let toToggle = foldingModel.getRegionsInside({ startLineNumber: 1, endLineNumber: Number.MAX_VALUE }, filter); + let toToggle = foldingModel.getRegionsInside(null, filter); foldingModel.toggleCollapseState(toToggle); } \ No newline at end of file diff --git a/src/vs/editor/contrib/folding/common/hiddenRangeModel.ts b/src/vs/editor/contrib/folding/common/hiddenRangeModel.ts index aee78bfc692..aa008c4a74d 100644 --- a/src/vs/editor/contrib/folding/common/hiddenRangeModel.ts +++ b/src/vs/editor/contrib/folding/common/hiddenRangeModel.ts @@ -5,7 +5,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { Range, IRange } from 'vs/editor/common/core/range'; -import { FoldingRegion, FoldingModel, IFoldingRange, CollapseMemento } from 'vs/editor/contrib/folding/common/foldingModel'; +import { FoldingRegion, FoldingModel, CollapseMemento } from 'vs/editor/contrib/folding/common/foldingModel'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Selection } from 'vs/editor/common/core/selection'; import { findFirst } from 'vs/base/common/arrays'; @@ -36,12 +36,12 @@ export class HiddenRangeModel { let regions = this._foldingModel.regions; for (let region of regions) { - if (!region.isCollapsed || lastCollapsed && lastCollapsed.contains(region.range)) { + if (!region.isCollapsed || lastCollapsed && lastCollapsed.contains(region)) { // ignore ranges contained in collapsed regions continue; } lastCollapsed = region; - let range = region.range; + let range = region; if (!updateHiddenAreas && i < this._hiddenRanges.length && matchesHiddenRange(this._hiddenRanges[i], range)) { newHiddenAreas.push(this._hiddenRanges[i]); @@ -128,7 +128,7 @@ export class HiddenRangeModel { } } -function matchesHiddenRange(hr: IRange, range: IFoldingRange) { +function matchesHiddenRange(hr: IRange, range: FoldingRegion) { return hr.startLineNumber === range.startLineNumber + 1 && hr.endLineNumber === range.endLineNumber; } function isInside(line: number, range: IRange) { diff --git a/src/vs/editor/contrib/folding/common/indentFoldStrategy.ts b/src/vs/editor/contrib/folding/common/indentFoldStrategy.ts deleted file mode 100644 index 39f3b5aa635..00000000000 --- a/src/vs/editor/contrib/folding/common/indentFoldStrategy.ts +++ /dev/null @@ -1,42 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -import { IModel } from 'vs/editor/common/editorCommon'; -import { IFoldingRange } from 'vs/editor/contrib/folding/common/foldingModel'; - -export function computeRanges(model: IModel): IFoldingRange[] { - // we get here a clone of the model's indent ranges - return model.getIndentRanges(); -} - -/** - * Limits the number of folding ranges by removing ranges with larger indent levels - */ -export function limitByIndent(ranges: IFoldingRange[], maxEntries: number): IFoldingRange[] { - if (ranges.length <= maxEntries) { - return ranges; - } - - let indentOccurrences: number[] = []; - ranges.forEach(r => { - if (r.indent < 1000) { - indentOccurrences[r.indent] = (indentOccurrences[r.indent] || 0) + 1; - } - }); - let maxIndent = indentOccurrences.length; - for (let i = 0; i < indentOccurrences.length; i++) { - if (indentOccurrences[i]) { - maxEntries -= indentOccurrences[i]; - if (maxEntries < 0) { - maxIndent = i; - break; - } - } - - } - return ranges.filter(r => r.indent < maxIndent); -} \ No newline at end of file diff --git a/src/vs/editor/contrib/folding/test/foldingModel.test.ts b/src/vs/editor/contrib/folding/test/foldingModel.test.ts index f0c89473edf..6e49943a64d 100644 --- a/src/vs/editor/contrib/folding/test/foldingModel.test.ts +++ b/src/vs/editor/contrib/folding/test/foldingModel.test.ts @@ -5,7 +5,7 @@ 'use strict'; import * as assert from 'assert'; -import { FoldingModel, FoldingRegion, setCollapseStateDown, setCollapseStateAtLevel, setCollapseStateLevelsDown, setCollapseStateLevelsUp } from 'vs/editor/contrib/folding/common/foldingModel'; +import { FoldingModel, FoldingRegion, setCollapseStateAtLevel, setCollapseStateLevelsDown, setCollapseStateLevelsUp } from 'vs/editor/contrib/folding/common/foldingModel'; import { Model } from 'vs/editor/common/model/model'; import { computeRanges } from 'vs/editor/common/model/indentRanges'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; @@ -40,18 +40,18 @@ suite('Folding Model', () => { function assertRegion(actual: FoldingRegion, expected: ExpectedRegion, message?: string) { assert.equal(!!actual, !!expected, message); if (actual) { - assert.equal(actual.range.startLineNumber, expected.startLineNumber, message); - assert.equal(actual.range.endLineNumber, expected.endLineNumber, message); + assert.equal(actual.startLineNumber, expected.startLineNumber, message); + assert.equal(actual.endLineNumber, expected.endLineNumber, message); assert.equal(actual.isCollapsed, expected.isCollapsed, message); } } function assertFoldedRegions(foldingModel: FoldingModel, expectedRegions: ExpectedRegion[], message?: string) { - assert.deepEqual(foldingModel.regions.filter(r => r.isCollapsed).map(r => ({ startLineNumber: r.range.startLineNumber, endLineNumber: r.range.endLineNumber, isCollapsed: false })), expectedRegions, message); + assert.deepEqual(foldingModel.regions.filter(r => r.isCollapsed).map(r => ({ startLineNumber: r.startLineNumber, endLineNumber: r.endLineNumber, isCollapsed: false })), expectedRegions, message); } function assertRegions(actual: FoldingRegion[], expectedRegions: ExpectedRegion[], message?: string) { - assert.deepEqual(actual.map(r => ({ startLineNumber: r.range.startLineNumber, endLineNumber: r.range.endLineNumber, isCollapsed: r.isCollapsed })), expectedRegions, message); + assert.deepEqual(actual.map(r => ({ startLineNumber: r.startLineNumber, endLineNumber: r.endLineNumber, isCollapsed: r.isCollapsed })), expectedRegions, message); } test('getRegionAtLine', () => { @@ -66,25 +66,31 @@ suite('Folding Model', () => { /* 8*/ '}']; let textModel = Model.createFromString(lines.join('\n')); - let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); - let ranges = computeRanges(textModel, false, null); - foldingModel.update(ranges); + let ranges = computeRanges(textModel, false, null); + foldingModel.update(ranges); - let r1 = r(1, 3, false); - let r2 = r(4, 7, false); - let r3 = r(5, 6, false); + let r1 = r(1, 3, false); + let r2 = r(4, 7, false); + let r3 = r(5, 6, false); + + assertRegions(foldingModel.regions, [r1, r2, r3]); + + assertRegion(foldingModel.getRegionAtLine(1), r1, '1'); + assertRegion(foldingModel.getRegionAtLine(2), r1, '2'); + assertRegion(foldingModel.getRegionAtLine(3), r1, '3'); + assertRegion(foldingModel.getRegionAtLine(4), r2, '4'); + assertRegion(foldingModel.getRegionAtLine(5), r3, '5'); + assertRegion(foldingModel.getRegionAtLine(6), r3, '5'); + assertRegion(foldingModel.getRegionAtLine(7), r2, '6'); + assertRegion(foldingModel.getRegionAtLine(8), null, '7'); + } finally { + textModel.dispose(); + } - assertRegions(foldingModel.regions, [r1, r2, r3]); - assertRegion(foldingModel.getRegionAtLine(1), r1, '1'); - assertRegion(foldingModel.getRegionAtLine(2), r1, '2'); - assertRegion(foldingModel.getRegionAtLine(3), r1, '3'); - assertRegion(foldingModel.getRegionAtLine(4), r2, '4'); - assertRegion(foldingModel.getRegionAtLine(5), r3, '5'); - assertRegion(foldingModel.getRegionAtLine(6), r3, '5'); - assertRegion(foldingModel.getRegionAtLine(7), r2, '6'); - assertRegion(foldingModel.getRegionAtLine(8), null, '7'); }); test('collapse', () => { @@ -99,31 +105,37 @@ suite('Folding Model', () => { /* 8*/ '}']; let textModel = Model.createFromString(lines.join('\n')); - let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); - let ranges = computeRanges(textModel, false, null); - foldingModel.update(ranges); + let ranges = computeRanges(textModel, false, null); + foldingModel.update(ranges); - let r1 = r(1, 3, false); - let r2 = r(4, 7, false); - let r3 = r(5, 6, false); + let r1 = r(1, 3, false); + let r2 = r(4, 7, false); + let r3 = r(5, 6, false); - assertRegions(foldingModel.regions, [r1, r2, r3]); + assertRegions(foldingModel.regions, [r1, r2, r3]); - foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(1)]); - foldingModel.update(ranges); + foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(1)]); + foldingModel.update(ranges); - assertRegions(foldingModel.regions, [r(1, 3, true), r2, r3]); + assertRegions(foldingModel.regions, [r(1, 3, true), r2, r3]); - foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(5)]); - foldingModel.update(ranges); + foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(5)]); + foldingModel.update(ranges); - assertRegions(foldingModel.regions, [r(1, 3, true), r2, r(5, 6, true)]); + assertRegions(foldingModel.regions, [r(1, 3, true), r2, r(5, 6, true)]); - foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(7)]); - foldingModel.update(ranges); + foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(7)]); + foldingModel.update(ranges); - assertRegions(foldingModel.regions, [r(1, 3, true), r(4, 7, true), r(5, 6, true)]); + assertRegions(foldingModel.regions, [r(1, 3, true), r(4, 7, true), r(5, 6, true)]); + + textModel.dispose(); + } finally { + textModel.dispose(); + } }); @@ -139,23 +151,27 @@ suite('Folding Model', () => { /* 8*/ '}']; let textModel = Model.createFromString(lines.join('\n')); - let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); - let ranges = computeRanges(textModel, false, null); - foldingModel.update(ranges); + let ranges = computeRanges(textModel, false, null); + foldingModel.update(ranges); - let r1 = r(1, 3, false); - let r2 = r(4, 7, false); - let r3 = r(5, 6, false); + let r1 = r(1, 3, false); + let r2 = r(4, 7, false); + let r3 = r(5, 6, false); - assertRegions(foldingModel.regions, [r1, r2, r3]); - foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(2), foldingModel.getRegionAtLine(5)]); + assertRegions(foldingModel.regions, [r1, r2, r3]); + foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(2), foldingModel.getRegionAtLine(5)]); - textModel.applyEdits([EditOperation.insert(new Position(4, 1), '//hello\n')]); + textModel.applyEdits([EditOperation.insert(new Position(4, 1), '//hello\n')]); - foldingModel.update(computeRanges(textModel, false, null)); + foldingModel.update(computeRanges(textModel, false, null)); - assertRegions(foldingModel.regions, [r(1, 3, true), r(5, 8, false), r(6, 7, true)]); + assertRegions(foldingModel.regions, [r(1, 3, true), r(5, 8, false), r(6, 7, true)]); + } finally { + textModel.dispose(); + } }); test('getRegionsInside', () => { @@ -170,23 +186,28 @@ suite('Folding Model', () => { /* 8*/ '}']; let textModel = Model.createFromString(lines.join('\n')); - let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); - let ranges = computeRanges(textModel, false, null); - foldingModel.update(ranges); + let ranges = computeRanges(textModel, false, null); + foldingModel.update(ranges); - let r1 = r(1, 3, false); - let r2 = r(4, 7, false); - let r3 = r(5, 6, false); + let r1 = r(1, 3, false); + let r2 = r(4, 7, false); + let r3 = r(5, 6, false); - assertRegions(foldingModel.regions, [r1, r2, r3]); + assertRegions(foldingModel.regions, [r1, r2, r3]); + let region1 = foldingModel.getRegionAtLine(r1.startLineNumber); + let region2 = foldingModel.getRegionAtLine(r2.startLineNumber); + let region3 = foldingModel.getRegionAtLine(r3.startLineNumber); - assertRegions(foldingModel.getRegionsInside(r(1, 8)), [r1, r2, r3], '1'); - assertRegions(foldingModel.getRegionsInside(r(1, 3)), [r1], '2'); - assertRegions(foldingModel.getRegionsInside(r(4, 7)), [r2, r3], '3'); - assertRegions(foldingModel.getRegionsInside(r(4, 6)), [r3], '4'); - assertRegions(foldingModel.getRegionsInside(r(2, 5)), [], '5'); - assertRegions(foldingModel.getRegionsInside(r(6, 8)), [], '6'); + assertRegions(foldingModel.getRegionsInside(null), [r1, r2, r3], '1'); + assertRegions(foldingModel.getRegionsInside(region1), [], '2'); + assertRegions(foldingModel.getRegionsInside(region2), [r3], '3'); + assertRegions(foldingModel.getRegionsInside(region3), [], '4'); + } finally { + textModel.dispose(); + } }); @@ -206,27 +227,39 @@ suite('Folding Model', () => { /* 12*/ '}']; let textModel = Model.createFromString(lines.join('\n')); - let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + try { - let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); - foldingModel.update(ranges); + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); - let r1 = r(1, 2, false); - let r2 = r(3, 11, false); - let r3 = r(4, 10, false); - let r4 = r(5, 6, false); - let r5 = r(8, 9, false); + let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); + foldingModel.update(ranges); - assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); + let r1 = r(1, 2, false); + let r2 = r(3, 11, false); + let r3 = r(4, 10, false); + let r4 = r(5, 6, false); + let r5 = r(8, 9, false); - assertRegions(foldingModel.getRegionsInside(r(1, 12), (r, level) => level === 1), [r1, r2], '1'); - assertRegions(foldingModel.getRegionsInside(r(1, 12), (r, level) => level === 2), [r3], '2'); - assertRegions(foldingModel.getRegionsInside(r(1, 12), (r, level) => level === 3), [r4, r5], '3'); + let region1 = foldingModel.getRegionAtLine(r1.startLineNumber); + let region2 = foldingModel.getRegionAtLine(r2.startLineNumber); + let region3 = foldingModel.getRegionAtLine(r3.startLineNumber); - assertRegions(foldingModel.getRegionsInside(r(4, 11), (r, level) => level === 1), [r3], '4'); - assertRegions(foldingModel.getRegionsInside(r(4, 11), (r, level) => level === 2), [r4, r5], '5'); + assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); - assertRegions(foldingModel.getRegionsInside(r(1, 10), (r) => !r.hidesLine(9)), [r1, r4], '6'); + assertRegions(foldingModel.getRegionsInside(null, (r, level) => level === 1), [r1, r2], '1'); + assertRegions(foldingModel.getRegionsInside(null, (r, level) => level === 2), [r3], '2'); + assertRegions(foldingModel.getRegionsInside(null, (r, level) => level === 3), [r4, r5], '3'); + + assertRegions(foldingModel.getRegionsInside(region2, (r, level) => level === 1), [r3], '4'); + assertRegions(foldingModel.getRegionsInside(region2, (r, level) => level === 2), [r4, r5], '5'); + assertRegions(foldingModel.getRegionsInside(region3, (r, level) => level === 1), [r4, r5], '6'); + + assertRegions(foldingModel.getRegionsInside(region2, (r, level) => r.hidesLine(9)), [r3, r5], '7'); + + assertRegions(foldingModel.getRegionsInside(region1, (r, level) => level === 1), [], '8'); + } finally { + textModel.dispose(); + } }); @@ -245,29 +278,33 @@ suite('Folding Model', () => { /* 11*/ '']; let textModel = Model.createFromString(lines.join('\n')); - let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); - let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); - foldingModel.update(ranges); + let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); + foldingModel.update(ranges); - let r1 = r(1, 10, false); - let r2 = r(2, 8, false); - let r3 = r(3, 7, false); - let r4 = r(4, 5, false); + let r1 = r(1, 10, false); + let r2 = r(2, 8, false); + let r3 = r(3, 7, false); + let r4 = r(4, 5, false); - assertRegions(foldingModel.regions, [r1, r2, r3, r4]); + assertRegions(foldingModel.regions, [r1, r2, r3, r4]); - assertRegions(foldingModel.getAllRegionsAtLine(1), [r1], '1'); - assertRegions(foldingModel.getAllRegionsAtLine(2), [r1, r2], '2'); - assertRegions(foldingModel.getAllRegionsAtLine(3), [r1, r2, r3], '3'); - assertRegions(foldingModel.getAllRegionsAtLine(4), [r1, r2, r3, r4], '4'); - assertRegions(foldingModel.getAllRegionsAtLine(5), [r1, r2, r3, r4], '5'); - assertRegions(foldingModel.getAllRegionsAtLine(6), [r1, r2, r3], '6'); - assertRegions(foldingModel.getAllRegionsAtLine(7), [r1, r2, r3], '7'); - assertRegions(foldingModel.getAllRegionsAtLine(8), [r1, r2], '8'); - assertRegions(foldingModel.getAllRegionsAtLine(9), [r1], '9'); - assertRegions(foldingModel.getAllRegionsAtLine(10), [r1], '10'); - assertRegions(foldingModel.getAllRegionsAtLine(11), [], '10'); + assertRegions(foldingModel.getAllRegionsAtLine(1), [r1], '1'); + assertRegions(foldingModel.getAllRegionsAtLine(2), [r1, r2].reverse(), '2'); + assertRegions(foldingModel.getAllRegionsAtLine(3), [r1, r2, r3].reverse(), '3'); + assertRegions(foldingModel.getAllRegionsAtLine(4), [r1, r2, r3, r4].reverse(), '4'); + assertRegions(foldingModel.getAllRegionsAtLine(5), [r1, r2, r3, r4].reverse(), '5'); + assertRegions(foldingModel.getAllRegionsAtLine(6), [r1, r2, r3].reverse(), '6'); + assertRegions(foldingModel.getAllRegionsAtLine(7), [r1, r2, r3].reverse(), '7'); + assertRegions(foldingModel.getAllRegionsAtLine(8), [r1, r2].reverse(), '8'); + assertRegions(foldingModel.getAllRegionsAtLine(9), [r1], '9'); + assertRegions(foldingModel.getAllRegionsAtLine(10), [r1], '10'); + assertRegions(foldingModel.getAllRegionsAtLine(11), [], '10'); + } finally { + textModel.dispose(); + } }); test('setCollapseStateRecursivly', () => { @@ -287,35 +324,39 @@ suite('Folding Model', () => { /* 13*/ '}']; let textModel = Model.createFromString(lines.join('\n')); - let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); - let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); - foldingModel.update(ranges); + let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); + foldingModel.update(ranges); - let r1 = r(1, 2, false); - let r2 = r(3, 12, false); - let r3 = r(4, 11, false); - let r4 = r(5, 6, false); - let r5 = r(9, 10, false); - assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); + let r1 = r(1, 2, false); + let r2 = r(3, 12, false); + let r3 = r(4, 11, false); + let r4 = r(5, 6, false); + let r5 = r(9, 10, false); + assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); - setCollapseStateDown(foldingModel, true, [4]); - assertFoldedRegions(foldingModel, [r3, r4, r5], '1'); + setCollapseStateLevelsDown(foldingModel, true, Number.MAX_VALUE, [4]); + assertFoldedRegions(foldingModel, [r3, r4, r5], '1'); - setCollapseStateDown(foldingModel, false, [8]); - assertFoldedRegions(foldingModel, [], '2'); + setCollapseStateLevelsDown(foldingModel, false, Number.MAX_VALUE, [8]); + assertFoldedRegions(foldingModel, [], '2'); - setCollapseStateDown(foldingModel, true, [12]); - assertFoldedRegions(foldingModel, [r2, r3, r4, r5], '1'); + setCollapseStateLevelsDown(foldingModel, true, Number.MAX_VALUE, [12]); + assertFoldedRegions(foldingModel, [r2, r3, r4, r5], '1'); - setCollapseStateDown(foldingModel, false, [7]); - assertFoldedRegions(foldingModel, [r2], '1'); + setCollapseStateLevelsDown(foldingModel, false, Number.MAX_VALUE, [7]); + assertFoldedRegions(foldingModel, [r2], '1'); - setCollapseStateDown(foldingModel, false); - assertFoldedRegions(foldingModel, [], '1'); + setCollapseStateLevelsDown(foldingModel, false); + assertFoldedRegions(foldingModel, [], '1'); - setCollapseStateDown(foldingModel, true); - assertFoldedRegions(foldingModel, [r1, r2, r3, r4, r5], '1'); + setCollapseStateLevelsDown(foldingModel, true); + assertFoldedRegions(foldingModel, [r1, r2, r3, r4, r5], '1'); + } finally { + textModel.dispose(); + } }); @@ -336,36 +377,39 @@ suite('Folding Model', () => { /* 13*/ '}']; let textModel = Model.createFromString(lines.join('\n')); - let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); - let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); - foldingModel.update(ranges); + let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); + foldingModel.update(ranges); - let r1 = r(1, 2, false); - let r2 = r(3, 12, false); - let r3 = r(4, 11, false); - let r4 = r(5, 6, false); - let r5 = r(9, 10, false); - assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); + let r1 = r(1, 2, false); + let r2 = r(3, 12, false); + let r3 = r(4, 11, false); + let r4 = r(5, 6, false); + let r5 = r(9, 10, false); + assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); - setCollapseStateAtLevel(foldingModel, 1, true, []); - assertFoldedRegions(foldingModel, [r1, r2], '1'); + setCollapseStateAtLevel(foldingModel, 1, true, []); + assertFoldedRegions(foldingModel, [r1, r2], '1'); - setCollapseStateAtLevel(foldingModel, 1, false, [5]); - assertFoldedRegions(foldingModel, [r2], '1'); + setCollapseStateAtLevel(foldingModel, 1, false, [5]); + assertFoldedRegions(foldingModel, [r2], '1'); - setCollapseStateAtLevel(foldingModel, 1, false, [1]); - assertFoldedRegions(foldingModel, [], '1'); + setCollapseStateAtLevel(foldingModel, 1, false, [1]); + assertFoldedRegions(foldingModel, [], '1'); - setCollapseStateAtLevel(foldingModel, 2, true, []); - assertFoldedRegions(foldingModel, [r3], '1'); + setCollapseStateAtLevel(foldingModel, 2, true, []); + assertFoldedRegions(foldingModel, [r3], '1'); - setCollapseStateAtLevel(foldingModel, 3, true, [4, 9]); - assertFoldedRegions(foldingModel, [r3, r4], '1'); - - setCollapseStateAtLevel(foldingModel, 3, false, [4, 9]); - assertFoldedRegions(foldingModel, [r3], '1'); + setCollapseStateAtLevel(foldingModel, 3, true, [4, 9]); + assertFoldedRegions(foldingModel, [r3, r4], '1'); + setCollapseStateAtLevel(foldingModel, 3, false, [4, 9]); + assertFoldedRegions(foldingModel, [r3], '1'); + } finally { + textModel.dispose(); + } }); test('setCollapseStateLevelsDown', () => { @@ -385,36 +429,39 @@ suite('Folding Model', () => { /* 13*/ '}']; let textModel = Model.createFromString(lines.join('\n')); - let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); - let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); - foldingModel.update(ranges); + let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); + foldingModel.update(ranges); - let r1 = r(1, 2, false); - let r2 = r(3, 12, false); - let r3 = r(4, 11, false); - let r4 = r(5, 6, false); - let r5 = r(9, 10, false); - assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); + let r1 = r(1, 2, false); + let r2 = r(3, 12, false); + let r3 = r(4, 11, false); + let r4 = r(5, 6, false); + let r5 = r(9, 10, false); + assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); - setCollapseStateLevelsDown(foldingModel, 1, true, [4]); - assertFoldedRegions(foldingModel, [r3], '1'); + setCollapseStateLevelsDown(foldingModel, true, 1, [4]); + assertFoldedRegions(foldingModel, [r3], '1'); - setCollapseStateLevelsDown(foldingModel, 2, true, [4]); - assertFoldedRegions(foldingModel, [r3, r4, r5], '2'); + setCollapseStateLevelsDown(foldingModel, true, 2, [4]); + assertFoldedRegions(foldingModel, [r3, r4, r5], '2'); - setCollapseStateLevelsDown(foldingModel, 2, false, [3]); - assertFoldedRegions(foldingModel, [r4, r5], '3'); + setCollapseStateLevelsDown(foldingModel, false, 2, [3]); + assertFoldedRegions(foldingModel, [r4, r5], '3'); - setCollapseStateLevelsDown(foldingModel, 2, false, [2]); - assertFoldedRegions(foldingModel, [r4, r5], '4'); + setCollapseStateLevelsDown(foldingModel, false, 2, [2]); + assertFoldedRegions(foldingModel, [r4, r5], '4'); - setCollapseStateLevelsDown(foldingModel, 4, true, [2]); - assertFoldedRegions(foldingModel, [r1, r4, r5], '5'); - - setCollapseStateLevelsDown(foldingModel, 4, false, [2, 3]); - assertFoldedRegions(foldingModel, [], '6'); + setCollapseStateLevelsDown(foldingModel, true, 4, [2]); + assertFoldedRegions(foldingModel, [r1, r4, r5], '5'); + setCollapseStateLevelsDown(foldingModel, false, 4, [2, 3]); + assertFoldedRegions(foldingModel, [], '6'); + } finally { + textModel.dispose(); + } }); test('setCollapseStateLevelsUp', () => { @@ -434,30 +481,33 @@ suite('Folding Model', () => { /* 13*/ '}']; let textModel = Model.createFromString(lines.join('\n')); - let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); - let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); - foldingModel.update(ranges); + let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); + foldingModel.update(ranges); - let r1 = r(1, 2, false); - let r2 = r(3, 12, false); - let r3 = r(4, 11, false); - let r4 = r(5, 6, false); - let r5 = r(9, 10, false); - assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); + let r1 = r(1, 2, false); + let r2 = r(3, 12, false); + let r3 = r(4, 11, false); + let r4 = r(5, 6, false); + let r5 = r(9, 10, false); + assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); - setCollapseStateLevelsUp(foldingModel, 1, true, [4]); - assertFoldedRegions(foldingModel, [r3], '1'); + setCollapseStateLevelsUp(foldingModel, true, 1, [4]); + assertFoldedRegions(foldingModel, [r3], '1'); - setCollapseStateLevelsUp(foldingModel, 2, true, [4]); - assertFoldedRegions(foldingModel, [r2, r3], '2'); + setCollapseStateLevelsUp(foldingModel, true, 2, [4]); + assertFoldedRegions(foldingModel, [r2, r3], '2'); - setCollapseStateLevelsUp(foldingModel, 4, false, [1, 3, 4]); - assertFoldedRegions(foldingModel, [], '3'); - - setCollapseStateLevelsUp(foldingModel, 2, true, [10]); - assertFoldedRegions(foldingModel, [r3, r5], '4'); + setCollapseStateLevelsUp(foldingModel, false, 4, [1, 3, 4]); + assertFoldedRegions(foldingModel, [], '3'); + setCollapseStateLevelsUp(foldingModel, true, 2, [10]); + assertFoldedRegions(foldingModel, [r3, r5], '4'); + } finally { + textModel.dispose(); + } }); diff --git a/src/vs/editor/contrib/folding/test/indentFold.test.ts b/src/vs/editor/contrib/folding/test/indentFold.test.ts index bae8d357857..7109691b177 100644 --- a/src/vs/editor/contrib/folding/test/indentFold.test.ts +++ b/src/vs/editor/contrib/folding/test/indentFold.test.ts @@ -5,25 +5,73 @@ 'use strict'; import * as assert from 'assert'; -import { IFoldingRange } from 'vs/editor/contrib/folding/common/foldingModel'; -import { limitByIndent } from 'vs/editor/contrib/folding/common/indentFoldStrategy'; +import { computeRanges } from 'vs/editor/common/model/indentRanges'; +import { Model } from 'vs/editor/common/model/model'; + +interface IndentRange { + startLineNumber: number; + endLineNumber: number; +} suite('Indentation Folding', () => { - function r(startLineNumber: number, endLineNumber: number, indent: number): IFoldingRange { - return { startLineNumber, endLineNumber, indent }; + function r(startLineNumber: number, endLineNumber: number): IndentRange { + return { startLineNumber, endLineNumber }; } test('Limit By indent', () => { - let ranges = [r(1, 4, 0), r(3, 4, 2), r(5, 8, 0), r(6, 7, 1), r(9, 15, 0), r(10, 15, 10), r(11, 12, 2000), r(14, 15, 2000)]; - assert.deepEqual(limitByIndent(ranges, 8), [r(1, 4, 0), r(3, 4, 2), r(5, 8, 0), r(6, 7, 1), r(9, 15, 0), r(10, 15, 10), r(11, 12, 2000), r(14, 15, 2000)]); - assert.deepEqual(limitByIndent(ranges, 7), [r(1, 4, 0), r(3, 4, 2), r(5, 8, 0), r(6, 7, 1), r(9, 15, 0), r(10, 15, 10)]); - assert.deepEqual(limitByIndent(ranges, 6), [r(1, 4, 0), r(3, 4, 2), r(5, 8, 0), r(6, 7, 1), r(9, 15, 0), r(10, 15, 10)]); - assert.deepEqual(limitByIndent(ranges, 5), [r(1, 4, 0), r(3, 4, 2), r(5, 8, 0), r(6, 7, 1), r(9, 15, 0)]); - assert.deepEqual(limitByIndent(ranges, 4), [r(1, 4, 0), r(5, 8, 0), r(6, 7, 1), r(9, 15, 0)]); - assert.deepEqual(limitByIndent(ranges, 3), [r(1, 4, 0), r(5, 8, 0), r(9, 15, 0)]); - assert.deepEqual(limitByIndent(ranges, 2), []); - assert.deepEqual(limitByIndent(ranges, 1), []); - assert.deepEqual(limitByIndent(ranges, 0), []); + + + let lines = [ + /* 1*/ 'A', + /* 2*/ ' A', + /* 3*/ ' A', + /* 4*/ ' A', + /* 5*/ ' A', + /* 6*/ ' A', + /* 7*/ ' A', + /* 8*/ ' A', + /* 9*/ ' A', + /* 10*/ ' A', + /* 11*/ ' A', + /* 12*/ ' A', + /* 13*/ ' A', + /* 14*/ ' A', + /* 15*/ 'A', + /* 16*/ ' A' + ]; + let r1 = r(1, 14); + let r2 = r(3, 11); + let r3 = r(4, 5); + let r4 = r(6, 11); + let r5 = r(8, 9); + let r6 = r(10, 11); + let r7 = r(12, 14); + let r8 = r(13, 14); + let r9 = r(15, 16); + + let model = Model.createFromString(lines.join('\n')); + + function assertLimit(maxEntries: number, expectedRanges: IndentRange[], message: string) { + let indentRanges = computeRanges(model, true, null, maxEntries); + assert.ok(indentRanges.length <= maxEntries, 'max ' + message); + assert.equal(indentRanges.length, expectedRanges.length, 'len ' + message); + for (let i = 0; i < expectedRanges.length; i++) { + assert.equal(indentRanges.getStartLineNumber(i), expectedRanges[i].startLineNumber, 'start ' + message); + assert.equal(indentRanges.getEndLineNumber(i), expectedRanges[i].endLineNumber, 'end ' + message); + } + } + + assertLimit(1000, [r1, r2, r3, r4, r5, r6, r7, r8, r9], '1'); + assertLimit(9, [r1, r2, r3, r4, r5, r6, r7, r8, r9], '2'); + assertLimit(8, [r1, r2, r3, r4, r5, r6, r7, r9], '3'); + assertLimit(7, [r1, r2, r3, r4, r7, r9], '4'); + assertLimit(6, [r1, r2, r3, r4, r7, r9], '5'); + assertLimit(5, [r1, r2, r7, r9], '6'); + assertLimit(4, [r1, r2, r7, r9], '7'); + assertLimit(3, [r1, r9], '8'); + assertLimit(2, [r1, r9], '9'); + assertLimit(1, [], '10'); + assertLimit(0, [], '11'); }); }); diff --git a/src/vs/editor/contrib/hover/browser/modesContentHover.ts b/src/vs/editor/contrib/hover/browser/modesContentHover.ts index c26f35eb3f4..d6dc2864e1e 100644 --- a/src/vs/editor/contrib/hover/browser/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/browser/modesContentHover.ts @@ -14,7 +14,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { getHover } from '../common/hover'; import { HoverOperation, IHoverComputer } from './hoverOperation'; import { ContentHoverWidget } from './hoverWidgets'; -import { IMarkdownString, MarkdownString, isEmptyMarkdownString } from 'vs/base/common/htmlContent'; +import { IMarkdownString, MarkdownString, isEmptyMarkdownString, markedStringsEquals } from 'vs/base/common/htmlContent'; import { MarkdownRenderer } from 'vs/editor/contrib/markdown/browser/markdownRenderer'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; import { ColorPickerModel } from 'vs/editor/contrib/colorPicker/browser/colorPickerModel'; @@ -243,6 +243,9 @@ export class ModesContentHoverWidget extends ContentHoverWidget { } } if (filteredMessages.length > 0) { + if (hoverContentsEquals(filteredMessages, this._messages)) { + return; + } this._renderMessages(range, filteredMessages); } else { this.hide(); @@ -406,3 +409,23 @@ export class ModesContentHoverWidget extends ContentHoverWidget { className: 'hoverHighlight' }); } + +function hoverContentsEquals(first: HoverPart[], second: HoverPart[]): boolean { + if ((!first && second) || (first && !second) || first.length !== second.length) { + return false; + } + for (let i = 0; i < first.length; i++) { + const firstElement = first[i]; + const secondElement = second[i]; + if (firstElement instanceof ColorHover) { + return false; + } + if (secondElement instanceof ColorHover) { + return false; + } + if (!markedStringsEquals(firstElement.contents, secondElement.contents)) { + return false; + } + } + return true; +} diff --git a/src/vs/editor/contrib/indentation/common/indentation.ts b/src/vs/editor/contrib/indentation/common/indentation.ts index cd9add8748f..41fb47db826 100644 --- a/src/vs/editor/contrib/indentation/common/indentation.ts +++ b/src/vs/editor/contrib/indentation/common/indentation.ts @@ -323,7 +323,9 @@ export class ReindentLinesAction extends EditorAction { } let edits = getReindentEditOperations(model, 1, model.getLineCount()); if (edits) { + editor.pushUndoStop(); editor.executeEdits(this.id, edits); + editor.pushUndoStop(); } } } diff --git a/src/vs/editor/contrib/linesOperations/common/linesOperations.ts b/src/vs/editor/contrib/linesOperations/common/linesOperations.ts index 3c5229de450..2a81b32df9c 100644 --- a/src/vs/editor/contrib/linesOperations/common/linesOperations.ts +++ b/src/vs/editor/contrib/linesOperations/common/linesOperations.ts @@ -14,6 +14,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ReplaceCommand, ReplaceCommandThatPreservesSelection } from 'vs/editor/common/commands/replaceCommand'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; +import { Position } from 'vs/editor/common/core/position'; import { editorAction, ServicesAccessor, IActionOptions, EditorAction } from 'vs/editor/common/editorCommonExtensions'; import { CopyLinesCommand } from './copyLinesCommand'; import { DeleteLinesCommand } from './deleteLinesCommand'; @@ -206,9 +207,17 @@ export class TrimTrailingWhitespaceAction extends EditorAction { }); } - public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { + public run(accessor: ServicesAccessor, editor: ICommonCodeEditor, args: any): void { - var command = new TrimTrailingWhitespaceCommand(editor.getSelection()); + let cursors: Position[] = []; + if (args.reason === 'auto-save') { + // See https://github.com/editorconfig/editorconfig-vscode/issues/47 + // It is very convenient for the editor config extension to invoke this action. + // So, if we get a reason:'auto-save' passed in, let's preserve cursor positions. + cursors = editor.getSelections().map(s => new Position(s.positionLineNumber, s.positionColumn)); + } + + var command = new TrimTrailingWhitespaceCommand(editor.getSelection(), cursors); editor.pushUndoStop(); editor.executeCommands(this.id, [command]); @@ -407,7 +416,9 @@ export abstract class AbstractDeleteAllToBoundaryAction extends EditorAction { return EditOperation.replace(range, ''); }); + editor.pushUndoStop(); editor.executeEdits(this.id, edits, endCursorState); + editor.pushUndoStop(); } /** @@ -673,8 +684,9 @@ export class JoinLinesAction extends EditorAction { } endCursorState.unshift(endPrimaryCursor); + editor.pushUndoStop(); editor.executeEdits(this.id, edits, endCursorState); - + editor.pushUndoStop(); } } diff --git a/src/vs/editor/contrib/linesOperations/test/common/linesOperations.test.ts b/src/vs/editor/contrib/linesOperations/test/common/linesOperations.test.ts index 64c67e2cb9a..3e7578ef9e8 100644 --- a/src/vs/editor/contrib/linesOperations/test/common/linesOperations.test.ts +++ b/src/vs/editor/contrib/linesOperations/test/common/linesOperations.test.ts @@ -73,6 +73,32 @@ suite('Editor Contrib - Line Operations', () => { assert.equal(model.getLineContent(5), 'horlworld', '005'); }); }); + + test('issue #36234: should push undo stop', () => { + withMockCodeEditor( + [ + 'one', + 'two', + 'three' + ], {}, (editor, cursor) => { + let model = editor.getModel(); + let deleteAllLeftAction = new DeleteAllLeftAction(); + + editor.setSelection(new Selection(1, 1, 1, 1)); + + editor.trigger('keyboard', Handler.Type, { text: 'Typing some text here on line ' }); + assert.equal(model.getLineContent(1), 'Typing some text here on line one'); + assert.deepEqual(editor.getSelection(), new Selection(1, 31, 1, 31)); + + deleteAllLeftAction.run(null, editor); + assert.equal(model.getLineContent(1), 'one'); + assert.deepEqual(editor.getSelection(), new Selection(1, 1, 1, 1)); + + editor.trigger('keyboard', Handler.Undo, {}); + assert.equal(model.getLineContent(1), 'Typing some text here on line one'); + assert.deepEqual(editor.getSelection(), new Selection(1, 31, 1, 31)); + }); + }); }); suite('JoinLinesAction', () => { @@ -164,6 +190,31 @@ suite('Editor Contrib - Line Operations', () => { assert.deepEqual(editor.getSelection().toString(), new Selection(3, 4, 3, 8).toString(), '003'); }); }); + + test('should push undo stop', function () { + withMockCodeEditor( + [ + 'hello', + 'world' + ], {}, (editor, cursor) => { + let model = editor.getModel(); + let joinLinesAction = new JoinLinesAction(); + + editor.setSelection(new Selection(1, 6, 1, 6)); + + editor.trigger('keyboard', Handler.Type, { text: ' my dear' }); + assert.equal(model.getLineContent(1), 'hello my dear'); + assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 14)); + + joinLinesAction.run(null, editor); + assert.equal(model.getLineContent(1), 'hello my dear world'); + assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 14)); + + editor.trigger('keyboard', Handler.Undo, {}); + assert.equal(model.getLineContent(1), 'hello my dear'); + assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 14)); + }); + }); }); test('transpose', function () { diff --git a/src/vs/editor/contrib/multicursor/common/multicursor.ts b/src/vs/editor/contrib/multicursor/common/multicursor.ts index 0f6b2fdec41..a45a8226d0d 100644 --- a/src/vs/editor/contrib/multicursor/common/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/common/multicursor.ts @@ -5,14 +5,24 @@ 'use strict'; import * as nls from 'vs/nls'; -import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { ICommonCodeEditor, ScrollType } from 'vs/editor/common/editorCommon'; +import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes'; +import { RunOnceScheduler } from 'vs/base/common/async'; +import { ICommonCodeEditor, ScrollType, IEditorContribution, FindMatch, TrackedRangeStickiness, OverviewRulerLane, IModel } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; +import { editorAction, commonEditorContribution, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; +import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; -import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; +import { CursorChangeReason, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { CursorMoveCommands } from 'vs/editor/common/controller/cursorMoveCommands'; import { CursorState, RevealTarget } from 'vs/editor/common/controller/cursorCommon'; +import { Constants } from 'vs/editor/common/core/uint'; +import { DocumentHighlightProviderRegistry } from 'vs/editor/common/modes'; +import { CommonFindController } from 'vs/editor/contrib/find/common/findController'; +import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; +import { overviewRulerSelectionHighlightForeground } from 'vs/platform/theme/common/colorRegistry'; +import { themeColorFromId } from 'vs/platform/theme/common/themeService'; +import { INewFindReplaceState, FindOptionOverride } from 'vs/editor/contrib/find/common/findState'; @editorAction export class InsertCursorAbove extends EditorAction { @@ -139,3 +149,764 @@ class InsertCursorAtEndOfEachLineSelected extends EditorAction { } } } + +export class MultiCursorSessionResult { + constructor( + public readonly selections: Selection[], + public readonly revealRange: Range, + public readonly revealScrollType: ScrollType + ) { } +} + +export class MultiCursorSession { + + public static create(editor: ICommonCodeEditor, findController: CommonFindController): MultiCursorSession { + const findState = findController.getState(); + + // Find widget owns entirely what we search for if: + // - focus is not in the editor (i.e. it is in the find widget) + // - and the search widget is visible + // - and the search string is non-empty + if (!editor.isFocused() && findState.isRevealed && findState.searchString.length > 0) { + // Find widget owns what is searched for + return new MultiCursorSession(editor, findController, false, findState.searchString, findState.wholeWord, findState.matchCase, null); + } + + // Otherwise, the selection gives the search text, and the find widget gives the search settings + // The exception is the find state disassociation case: when beginning with a single, collapsed selection + let isDisconnectedFromFindController = false; + let wholeWord: boolean; + let matchCase: boolean; + const selections = editor.getSelections(); + if (selections.length === 1 && selections[0].isEmpty()) { + isDisconnectedFromFindController = true; + wholeWord = true; + matchCase = true; + } else { + wholeWord = findState.wholeWord; + matchCase = findState.matchCase; + } + + // Selection owns what is searched for + const s = editor.getSelection(); + + let searchText: string; + let currentMatch: Selection = null; + + if (s.isEmpty()) { + // selection is empty => expand to current word + const word = editor.getModel().getWordAtPosition(s.getStartPosition()); + if (!word) { + return null; + } + searchText = word.word; + currentMatch = new Selection(s.startLineNumber, word.startColumn, s.startLineNumber, word.endColumn); + } else { + searchText = editor.getModel().getValueInRange(s).replace(/\r\n/g, '\n'); + } + + return new MultiCursorSession(editor, findController, isDisconnectedFromFindController, searchText, wholeWord, matchCase, currentMatch); + } + + constructor( + private readonly _editor: ICommonCodeEditor, + public readonly findController: CommonFindController, + public readonly isDisconnectedFromFindController: boolean, + public readonly searchText: string, + public readonly wholeWord: boolean, + public readonly matchCase: boolean, + public currentMatch: Selection + ) { } + + public addSelectionToNextFindMatch(): MultiCursorSessionResult { + const nextMatch = this._getNextMatch(); + if (!nextMatch) { + return null; + } + + const allSelections = this._editor.getSelections(); + return new MultiCursorSessionResult(allSelections.concat(nextMatch), nextMatch, ScrollType.Smooth); + } + + public moveSelectionToNextFindMatch(): MultiCursorSessionResult { + const nextMatch = this._getNextMatch(); + if (!nextMatch) { + return null; + } + + const allSelections = this._editor.getSelections(); + return new MultiCursorSessionResult(allSelections.slice(0, allSelections.length - 1).concat(nextMatch), nextMatch, ScrollType.Smooth); + } + + private _getNextMatch(): Selection { + if (this.currentMatch) { + const result = this.currentMatch; + this.currentMatch = null; + return result; + } + + this.findController.highlightFindOptions(); + + const allSelections = this._editor.getSelections(); + const lastAddedSelection = allSelections[allSelections.length - 1]; + const nextMatch = this._editor.getModel().findNextMatch(this.searchText, lastAddedSelection.getEndPosition(), false, this.matchCase, this.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false); + + if (!nextMatch) { + return null; + } + return new Selection(nextMatch.range.startLineNumber, nextMatch.range.startColumn, nextMatch.range.endLineNumber, nextMatch.range.endColumn); + } + + public addSelectionToPreviousFindMatch(): MultiCursorSessionResult { + const previousMatch = this._getPreviousMatch(); + if (!previousMatch) { + return null; + } + + const allSelections = this._editor.getSelections(); + return new MultiCursorSessionResult(allSelections.concat(previousMatch), previousMatch, ScrollType.Smooth); + } + + public moveSelectionToPreviousFindMatch(): MultiCursorSessionResult { + const previousMatch = this._getPreviousMatch(); + if (!previousMatch) { + return null; + } + + const allSelections = this._editor.getSelections(); + return new MultiCursorSessionResult(allSelections.slice(0, allSelections.length - 1).concat(previousMatch), previousMatch, ScrollType.Smooth); + } + + private _getPreviousMatch(): Selection { + if (this.currentMatch) { + const result = this.currentMatch; + this.currentMatch = null; + return result; + } + + this.findController.highlightFindOptions(); + + const allSelections = this._editor.getSelections(); + const lastAddedSelection = allSelections[allSelections.length - 1]; + const previousMatch = this._editor.getModel().findPreviousMatch(this.searchText, lastAddedSelection.getStartPosition(), false, this.matchCase, this.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false); + + if (!previousMatch) { + return null; + } + return new Selection(previousMatch.range.startLineNumber, previousMatch.range.startColumn, previousMatch.range.endLineNumber, previousMatch.range.endColumn); + } + + public selectAll(): FindMatch[] { + this.findController.highlightFindOptions(); + + return this._editor.getModel().findMatches(this.searchText, true, false, this.matchCase, this.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false, Constants.MAX_SAFE_SMALL_INTEGER); + } +} + +@commonEditorContribution +export class MultiCursorSelectionController extends Disposable implements IEditorContribution { + + private static ID = 'editor.contrib.multiCursorController'; + + private readonly _editor: ICommonCodeEditor; + private _ignoreSelectionChange: boolean; + private _session: MultiCursorSession; + private _sessionDispose: IDisposable[]; + + public static get(editor: ICommonCodeEditor): MultiCursorSelectionController { + return editor.getContribution(MultiCursorSelectionController.ID); + } + + constructor(editor: ICommonCodeEditor) { + super(); + this._editor = editor; + this._ignoreSelectionChange = false; + this._session = null; + this._sessionDispose = []; + } + + public dispose(): void { + this._endSession(); + super.dispose(); + } + + public getId(): string { + return MultiCursorSelectionController.ID; + } + + private _beginSessionIfNeeded(findController: CommonFindController): void { + if (!this._session) { + // Create a new session + const session = MultiCursorSession.create(this._editor, findController); + if (!session) { + return; + } + + this._session = session; + + const newState: INewFindReplaceState = { searchString: this._session.searchText }; + if (this._session.isDisconnectedFromFindController) { + newState.wholeWordOverride = FindOptionOverride.True; + newState.matchCaseOverride = FindOptionOverride.True; + newState.isRegexOverride = FindOptionOverride.False; + } + findController.getState().change(newState, false); + + this._sessionDispose = [ + this._editor.onDidChangeCursorSelection((e) => { + if (this._ignoreSelectionChange) { + return; + } + this._endSession(); + }), + this._editor.onDidBlurEditorText(() => { + this._endSession(); + }), + findController.getState().addChangeListener((e) => { + if (e.matchCase || e.wholeWord) { + this._endSession(); + } + }) + ]; + } + } + + private _endSession(): void { + this._sessionDispose = dispose(this._sessionDispose); + if (this._session && this._session.isDisconnectedFromFindController) { + const newState: INewFindReplaceState = { + wholeWordOverride: FindOptionOverride.NotSet, + matchCaseOverride: FindOptionOverride.NotSet, + isRegexOverride: FindOptionOverride.NotSet, + }; + this._session.findController.getState().change(newState, false); + } + this._session = null; + } + + private _setSelections(selections: Selection[]): void { + this._ignoreSelectionChange = true; + this._editor.setSelections(selections); + this._ignoreSelectionChange = false; + } + + private _expandEmptyToWord(model: IModel, selection: Selection): Selection { + if (!selection.isEmpty()) { + return selection; + } + const word = model.getWordAtPosition(selection.getStartPosition()); + if (!word) { + return selection; + } + return new Selection(selection.startLineNumber, word.startColumn, selection.startLineNumber, word.endColumn); + } + + private _applySessionResult(result: MultiCursorSessionResult): void { + if (!result) { + return; + } + this._setSelections(result.selections); + if (result.revealRange) { + this._editor.revealRangeInCenterIfOutsideViewport(result.revealRange, result.revealScrollType); + } + } + + public getSession(findController: CommonFindController): MultiCursorSession { + return this._session; + } + + public addSelectionToNextFindMatch(findController: CommonFindController): void { + if (!this._session) { + // If there are multiple cursors, handle the case where they do not all select the same text. + const allSelections = this._editor.getSelections(); + if (allSelections.length > 1) { + const findState = findController.getState(); + const matchCase = findState.matchCase; + const selectionsContainSameText = modelRangesContainSameText(this._editor.getModel(), allSelections, matchCase); + if (!selectionsContainSameText) { + const model = this._editor.getModel(); + let resultingSelections: Selection[] = []; + for (let i = 0, len = allSelections.length; i < len; i++) { + resultingSelections[i] = this._expandEmptyToWord(model, allSelections[i]); + } + this._editor.setSelections(resultingSelections); + return; + } + } + } + this._beginSessionIfNeeded(findController); + if (this._session) { + this._applySessionResult(this._session.addSelectionToNextFindMatch()); + } + } + + public addSelectionToPreviousFindMatch(findController: CommonFindController): void { + this._beginSessionIfNeeded(findController); + if (this._session) { + this._applySessionResult(this._session.addSelectionToPreviousFindMatch()); + } + } + + public moveSelectionToNextFindMatch(findController: CommonFindController): void { + this._beginSessionIfNeeded(findController); + if (this._session) { + this._applySessionResult(this._session.moveSelectionToNextFindMatch()); + } + } + + public moveSelectionToPreviousFindMatch(findController: CommonFindController): void { + this._beginSessionIfNeeded(findController); + if (this._session) { + this._applySessionResult(this._session.addSelectionToPreviousFindMatch()); + } + } + + public selectAll(findController: CommonFindController): void { + let matches: FindMatch[] = null; + + const findState = findController.getState(); + + // Special case: find widget owns entirely what we search for if: + // - focus is not in the editor (i.e. it is in the find widget) + // - and the search widget is visible + // - and the search string is non-empty + // - and we're searching for a regex + if (!this._editor.isFocused() && findState.isRevealed && findState.searchString.length > 0 && findState.isRegex) { + + matches = this._editor.getModel().findMatches(findState.searchString, true, findState.isRegex, findState.matchCase, findState.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false, Constants.MAX_SAFE_SMALL_INTEGER); + + } else { + + this._beginSessionIfNeeded(findController); + if (!this._session) { + return; + } + + matches = this._session.selectAll(); + } + + if (matches.length > 0) { + const editorSelection = this._editor.getSelection(); + // Have the primary cursor remain the one where the action was invoked + for (let i = 0, len = matches.length; i < len; i++) { + const match = matches[i]; + const intersection = match.range.intersectRanges(editorSelection); + if (intersection) { + // bingo! + matches[i] = matches[0]; + matches[0] = match; + break; + } + } + + this._setSelections(matches.map(m => new Selection(m.range.startLineNumber, m.range.startColumn, m.range.endLineNumber, m.range.endColumn))); + } + } +} + +export abstract class MultiCursorSelectionControllerAction extends EditorAction { + + public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { + const multiCursorController = MultiCursorSelectionController.get(editor); + if (!multiCursorController) { + return; + } + const findController = CommonFindController.get(editor); + if (!findController) { + return null; + } + this._run(multiCursorController, findController); + } + + protected abstract _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void; +} + +@editorAction +export class AddSelectionToNextFindMatchAction extends MultiCursorSelectionControllerAction { + constructor() { + super({ + id: 'editor.action.addSelectionToNextFindMatch', + label: nls.localize('addSelectionToNextFindMatch', "Add Selection To Next Find Match"), + alias: 'Add Selection To Next Find Match', + precondition: null, + kbOpts: { + kbExpr: EditorContextKeys.focus, + primary: KeyMod.CtrlCmd | KeyCode.KEY_D + } + }); + } + protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { + multiCursorController.addSelectionToNextFindMatch(findController); + } +} + +@editorAction +export class AddSelectionToPreviousFindMatchAction extends MultiCursorSelectionControllerAction { + constructor() { + super({ + id: 'editor.action.addSelectionToPreviousFindMatch', + label: nls.localize('addSelectionToPreviousFindMatch', "Add Selection To Previous Find Match"), + alias: 'Add Selection To Previous Find Match', + precondition: null + }); + } + protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { + multiCursorController.addSelectionToPreviousFindMatch(findController); + } +} + +@editorAction +export class MoveSelectionToNextFindMatchAction extends MultiCursorSelectionControllerAction { + constructor() { + super({ + id: 'editor.action.moveSelectionToNextFindMatch', + label: nls.localize('moveSelectionToNextFindMatch', "Move Last Selection To Next Find Match"), + alias: 'Move Last Selection To Next Find Match', + precondition: null, + kbOpts: { + kbExpr: EditorContextKeys.focus, + primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_D) + } + }); + } + protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { + multiCursorController.moveSelectionToNextFindMatch(findController); + } +} + +@editorAction +export class MoveSelectionToPreviousFindMatchAction extends MultiCursorSelectionControllerAction { + constructor() { + super({ + id: 'editor.action.moveSelectionToPreviousFindMatch', + label: nls.localize('moveSelectionToPreviousFindMatch', "Move Last Selection To Previous Find Match"), + alias: 'Move Last Selection To Previous Find Match', + precondition: null + }); + } + protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { + multiCursorController.moveSelectionToPreviousFindMatch(findController); + } +} + +@editorAction +export class SelectHighlightsAction extends MultiCursorSelectionControllerAction { + constructor() { + super({ + id: 'editor.action.selectHighlights', + label: nls.localize('selectAllOccurrencesOfFindMatch', "Select All Occurrences of Find Match"), + alias: 'Select All Occurrences of Find Match', + precondition: null, + kbOpts: { + kbExpr: EditorContextKeys.focus, + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_L + } + }); + } + protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { + multiCursorController.selectAll(findController); + } +} + +@editorAction +export class CompatChangeAll extends MultiCursorSelectionControllerAction { + constructor() { + super({ + id: 'editor.action.changeAll', + label: nls.localize('changeAll.label', "Change All Occurrences"), + alias: 'Change All Occurrences', + precondition: EditorContextKeys.writable, + kbOpts: { + kbExpr: EditorContextKeys.textFocus, + primary: KeyMod.CtrlCmd | KeyCode.F2 + }, + menuOpts: { + group: '1_modification', + order: 1.2 + } + }); + } + protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { + multiCursorController.selectAll(findController); + } +} + +class SelectionHighlighterState { + public readonly lastWordUnderCursor: Selection; + public readonly searchText: string; + public readonly matchCase: boolean; + public readonly wordSeparators: string; + + constructor(lastWordUnderCursor: Selection, searchText: string, matchCase: boolean, wordSeparators: string) { + this.lastWordUnderCursor = lastWordUnderCursor; + this.searchText = searchText; + this.matchCase = matchCase; + this.wordSeparators = wordSeparators; + } + + /** + * Everything equals except for `lastWordUnderCursor` + */ + public static softEquals(a: SelectionHighlighterState, b: SelectionHighlighterState): boolean { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return ( + a.searchText === b.searchText + && a.matchCase === b.matchCase + && a.wordSeparators === b.wordSeparators + ); + } +} + +@commonEditorContribution +export class SelectionHighlighter extends Disposable implements IEditorContribution { + private static ID = 'editor.contrib.selectionHighlighter'; + + private editor: ICommonCodeEditor; + private _isEnabled: boolean; + private decorations: string[]; + private updateSoon: RunOnceScheduler; + private state: SelectionHighlighterState; + + constructor(editor: ICommonCodeEditor) { + super(); + this.editor = editor; + this._isEnabled = editor.getConfiguration().contribInfo.selectionHighlight; + this.decorations = []; + this.updateSoon = this._register(new RunOnceScheduler(() => this._update(), 300)); + this.state = null; + + this._register(editor.onDidChangeConfiguration((e) => { + this._isEnabled = editor.getConfiguration().contribInfo.selectionHighlight; + })); + this._register(editor.onDidChangeCursorSelection((e: ICursorSelectionChangedEvent) => { + + if (!this._isEnabled) { + // Early exit if nothing needs to be done! + // Leave some form of early exit check here if you wish to continue being a cursor position change listener ;) + return; + } + + if (e.selection.isEmpty()) { + if (e.reason === CursorChangeReason.Explicit) { + if (this.state && (!this.state.lastWordUnderCursor || !this.state.lastWordUnderCursor.containsPosition(e.selection.getStartPosition()))) { + // no longer valid + this._setState(null); + } + this.updateSoon.schedule(); + } else { + this._setState(null); + + } + } else { + this._update(); + } + })); + this._register(editor.onDidChangeModel((e) => { + this._setState(null); + })); + this._register(CommonFindController.get(editor).getState().addChangeListener((e) => { + this._update(); + })); + } + + public getId(): string { + return SelectionHighlighter.ID; + } + + private _update(): void { + this._setState(SelectionHighlighter._createState(this._isEnabled, this.editor)); + } + + private static _createState(isEnabled: boolean, editor: ICommonCodeEditor): SelectionHighlighterState { + if (!isEnabled) { + return null; + } + const model = editor.getModel(); + if (!model) { + return null; + } + const s = editor.getSelection(); + if (s.startLineNumber !== s.endLineNumber) { + // multiline forbidden for perf reasons + return null; + } + const multiCursorController = MultiCursorSelectionController.get(editor); + if (!multiCursorController) { + return null; + } + const findController = CommonFindController.get(editor); + if (!findController) { + return null; + } + let r = multiCursorController.getSession(findController); + if (!r) { + const allSelections = editor.getSelections(); + if (allSelections.length > 1) { + const findState = findController.getState(); + const matchCase = findState.matchCase; + const selectionsContainSameText = modelRangesContainSameText(editor.getModel(), allSelections, matchCase); + if (!selectionsContainSameText) { + return null; + } + } + + r = MultiCursorSession.create(editor, findController); + } + if (!r) { + return null; + } + + let lastWordUnderCursor: Selection = null; + const hasFindOccurrences = DocumentHighlightProviderRegistry.has(model); + if (r.currentMatch) { + // This is an empty selection + if (hasFindOccurrences) { + // Do not interfere with semantic word highlighting in the no selection case + return null; + } + + const config = editor.getConfiguration(); + if (!config.contribInfo.occurrencesHighlight) { + return null; + } + + lastWordUnderCursor = r.currentMatch; + } + if (/^[ \t]+$/.test(r.searchText)) { + // whitespace only selection + return null; + } + if (r.searchText.length > 200) { + // very long selection + return null; + } + + // TODO: better handling of this case + const findState = findController.getState(); + const caseSensitive = findState.matchCase; + + // Return early if the find widget shows the exact same matches + if (findState.isRevealed) { + let findStateSearchString = findState.searchString; + if (!caseSensitive) { + findStateSearchString = findStateSearchString.toLowerCase(); + } + + let mySearchString = r.searchText; + if (!caseSensitive) { + mySearchString = mySearchString.toLowerCase(); + } + + if (findStateSearchString === mySearchString && r.matchCase === findState.matchCase && r.wholeWord === findState.wholeWord && !findState.isRegex) { + return null; + } + } + + return new SelectionHighlighterState(lastWordUnderCursor, r.searchText, r.matchCase, r.wholeWord ? editor.getConfiguration().wordSeparators : null); + } + + private _setState(state: SelectionHighlighterState): void { + if (SelectionHighlighterState.softEquals(this.state, state)) { + this.state = state; + return; + } + this.state = state; + + if (!this.state) { + if (this.decorations.length > 0) { + this.decorations = this.editor.deltaDecorations(this.decorations, []); + } + return; + } + + const model = this.editor.getModel(); + const hasFindOccurrences = DocumentHighlightProviderRegistry.has(model); + + let allMatches = model.findMatches(this.state.searchText, true, false, this.state.matchCase, this.state.wordSeparators, false).map(m => m.range); + allMatches.sort(Range.compareRangesUsingStarts); + + let selections = this.editor.getSelections(); + selections.sort(Range.compareRangesUsingStarts); + + // do not overlap with selection (issue #64 and #512) + let matches: Range[] = []; + for (let i = 0, j = 0, len = allMatches.length, lenJ = selections.length; i < len;) { + const match = allMatches[i]; + + if (j >= lenJ) { + // finished all editor selections + matches.push(match); + i++; + } else { + const cmp = Range.compareRangesUsingStarts(match, selections[j]); + if (cmp < 0) { + // match is before sel + matches.push(match); + i++; + } else if (cmp > 0) { + // sel is before match + j++; + } else { + // sel is equal to match + i++; + j++; + } + } + } + + const decorations = matches.map(r => { + return { + range: r, + // Show in overviewRuler only if model has no semantic highlighting + options: (hasFindOccurrences ? SelectionHighlighter._SELECTION_HIGHLIGHT : SelectionHighlighter._SELECTION_HIGHLIGHT_OVERVIEW) + }; + }); + + this.decorations = this.editor.deltaDecorations(this.decorations, decorations); + } + + private static _SELECTION_HIGHLIGHT_OVERVIEW = ModelDecorationOptions.register({ + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + className: 'selectionHighlight', + overviewRuler: { + color: themeColorFromId(overviewRulerSelectionHighlightForeground), + darkColor: themeColorFromId(overviewRulerSelectionHighlightForeground), + position: OverviewRulerLane.Center + } + }); + + private static _SELECTION_HIGHLIGHT = ModelDecorationOptions.register({ + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + className: 'selectionHighlight', + }); + + public dispose(): void { + this._setState(null); + super.dispose(); + } +} + +function modelRangesContainSameText(model: IModel, ranges: Range[], matchCase: boolean): boolean { + const selectedText = getValueInRange(model, ranges[0], !matchCase); + for (let i = 1, len = ranges.length; i < len; i++) { + const range = ranges[i]; + if (range.isEmpty()) { + return false; + } + const thisSelectedText = getValueInRange(model, range, !matchCase); + if (selectedText !== thisSelectedText) { + return false; + } + } + return true; +} + +function getValueInRange(model: IModel, range: Range, toLowerCase: boolean): string { + const text = model.getValueInRange(range); + return (toLowerCase ? text.toLowerCase() : text); +} diff --git a/src/vs/editor/contrib/multicursor/test/common/multicursor.test.ts b/src/vs/editor/contrib/multicursor/test/common/multicursor.test.ts index 7824a0df71e..93c8377b9d0 100644 --- a/src/vs/editor/contrib/multicursor/test/common/multicursor.test.ts +++ b/src/vs/editor/contrib/multicursor/test/common/multicursor.test.ts @@ -5,11 +5,14 @@ 'use strict'; import * as assert from 'assert'; -import { withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor'; +import { withMockCodeEditor, MockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor'; import { Selection } from 'vs/editor/common/core/selection'; -import { InsertCursorAbove, InsertCursorBelow } from 'vs/editor/contrib/multicursor/common/multicursor'; -import { Handler } from 'vs/editor/common/editorCommon'; - +import { Range } from 'vs/editor/common/core/range'; +import { InsertCursorAbove, InsertCursorBelow, MultiCursorSelectionController, SelectHighlightsAction, AddSelectionToNextFindMatchAction } from 'vs/editor/contrib/multicursor/common/multicursor'; +import { Handler, EndOfLineSequence } from 'vs/editor/common/editorCommon'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { CommonFindController } from 'vs/editor/contrib/find/common/findController'; suite('Multicursor', () => { @@ -42,3 +45,525 @@ suite('Multicursor', () => { }); }); + +function fromRange(rng: Range): number[] { + return [rng.startLineNumber, rng.startColumn, rng.endLineNumber, rng.endColumn]; +} + +suite('Multicursor selection', () => { + let queryState: { [key: string]: any; } = {}; + let serviceCollection = new ServiceCollection(); + serviceCollection.set(IStorageService, { + get: (key: string) => queryState[key], + getBoolean: (key: string) => !!queryState[key], + store: (key: string, value: any) => { queryState[key] = value; } + }); + + test('issue #8817: Cursor position changes when you cancel multicursor', () => { + withMockCodeEditor([ + 'var x = (3 * 5)', + 'var y = (3 * 5)', + 'var z = (3 * 5)', + ], { serviceCollection: serviceCollection }, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let selectHighlightsAction = new SelectHighlightsAction(); + + editor.setSelection(new Selection(2, 9, 2, 16)); + + selectHighlightsAction.run(null, editor); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [2, 9, 2, 16], + [1, 9, 1, 16], + [3, 9, 3, 16], + ]); + + editor.trigger('test', 'removeSecondaryCursors', null); + + assert.deepEqual(fromRange(editor.getSelection()), [2, 9, 2, 16]); + + multiCursorSelectController.dispose(); + findController.dispose(); + }); + }); + + test('issue #5400: "Select All Occurrences of Find Match" does not select all if find uses regex', () => { + withMockCodeEditor([ + 'something', + 'someething', + 'someeething', + 'nothing' + ], { serviceCollection: serviceCollection }, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let selectHighlightsAction = new SelectHighlightsAction(); + + editor._isFocused = false; + + editor.setSelection(new Selection(1, 1, 1, 1)); + findController.getState().change({ searchString: 'some+thing', isRegex: true, isRevealed: true }, false); + + selectHighlightsAction.run(null, editor); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [1, 1, 1, 10], + [2, 1, 2, 11], + [3, 1, 3, 12], + ]); + + assert.equal(findController.getState().searchString, 'some+thing'); + + multiCursorSelectController.dispose(); + findController.dispose(); + }); + }); + + test('AddSelectionToNextFindMatchAction can work with multiline', () => { + withMockCodeEditor([ + '', + 'qwe', + 'rty', + '', + 'qwe', + '', + 'rty', + 'qwe', + 'rty' + ], { serviceCollection: serviceCollection }, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); + + editor.setSelection(new Selection(2, 1, 3, 4)); + + addSelectionToNextFindMatch.run(null, editor); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [2, 1, 3, 4], + [8, 1, 9, 4] + ]); + + editor.trigger('test', 'removeSecondaryCursors', null); + + assert.deepEqual(fromRange(editor.getSelection()), [2, 1, 3, 4]); + + multiCursorSelectController.dispose(); + findController.dispose(); + }); + }); + + test('issue #6661: AddSelectionToNextFindMatchAction can work with touching ranges', () => { + withMockCodeEditor([ + 'abcabc', + 'abc', + 'abcabc', + ], { serviceCollection: serviceCollection }, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); + + editor.setSelection(new Selection(1, 1, 1, 4)); + + addSelectionToNextFindMatch.run(null, editor); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [1, 1, 1, 4], + [1, 4, 1, 7] + ]); + + addSelectionToNextFindMatch.run(null, editor); + addSelectionToNextFindMatch.run(null, editor); + addSelectionToNextFindMatch.run(null, editor); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [1, 1, 1, 4], + [1, 4, 1, 7], + [2, 1, 2, 4], + [3, 1, 3, 4], + [3, 4, 3, 7] + ]); + + editor.trigger('test', Handler.Type, { text: 'z' }); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [1, 2, 1, 2], + [1, 3, 1, 3], + [2, 2, 2, 2], + [3, 2, 3, 2], + [3, 3, 3, 3] + ]); + assert.equal(editor.getValue(), [ + 'zz', + 'z', + 'zz', + ].join('\n')); + + multiCursorSelectController.dispose(); + findController.dispose(); + }); + }); + + test('issue #23541: Multiline Ctrl+D does not work in CRLF files', () => { + withMockCodeEditor([ + '', + 'qwe', + 'rty', + '', + 'qwe', + '', + 'rty', + 'qwe', + 'rty' + ], { serviceCollection: serviceCollection }, (editor, cursor) => { + + editor.getModel().setEOL(EndOfLineSequence.CRLF); + + let findController = editor.registerAndInstantiateContribution(CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); + + editor.setSelection(new Selection(2, 1, 3, 4)); + + addSelectionToNextFindMatch.run(null, editor); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [2, 1, 3, 4], + [8, 1, 9, 4] + ]); + + editor.trigger('test', 'removeSecondaryCursors', null); + + assert.deepEqual(fromRange(editor.getSelection()), [2, 1, 3, 4]); + + multiCursorSelectController.dispose(); + findController.dispose(); + }); + }); + + function testMulticursor(text: string[], callback: (editor: MockCodeEditor, findController: CommonFindController) => void): void { + withMockCodeEditor(text, { serviceCollection: serviceCollection }, (editor, cursor) => { + let findController = editor.registerAndInstantiateContribution(CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + + callback(editor, findController); + + multiCursorSelectController.dispose(); + findController.dispose(); + }); + } + + function testAddSelectionToNextFindMatchAction(text: string[], callback: (editor: MockCodeEditor, action: AddSelectionToNextFindMatchAction, findController: CommonFindController) => void): void { + testMulticursor(text, (editor, findController) => { + let action = new AddSelectionToNextFindMatchAction(); + callback(editor, action, findController); + }); + } + + test('AddSelectionToNextFindMatchAction starting with single collapsed selection', () => { + const text = [ + 'abc pizza', + 'abc house', + 'abc bar' + ]; + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 2, 1, 2), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + }); + }); + + test('AddSelectionToNextFindMatchAction starting with two selections, one being collapsed 1)', () => { + const text = [ + 'abc pizza', + 'abc house', + 'abc bar' + ]; + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 1, 1, 4), + new Selection(2, 2, 2, 2), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + }); + }); + + test('AddSelectionToNextFindMatchAction starting with two selections, one being collapsed 2)', () => { + const text = [ + 'abc pizza', + 'abc house', + 'abc bar' + ]; + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 2, 1, 2), + new Selection(2, 1, 2, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + }); + }); + + test('AddSelectionToNextFindMatchAction starting with all collapsed selections', () => { + const text = [ + 'abc pizza', + 'abc house', + 'abc bar' + ]; + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 2, 1, 2), + new Selection(2, 2, 2, 2), + new Selection(3, 1, 3, 1), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + }); + }); + + test('AddSelectionToNextFindMatchAction starting with all collapsed selections on different words', () => { + const text = [ + 'abc pizza', + 'abc house', + 'abc bar' + ]; + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 6, 1, 6), + new Selection(2, 6, 2, 6), + new Selection(3, 6, 3, 6), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 5, 1, 10), + new Selection(2, 5, 2, 10), + new Selection(3, 5, 3, 8), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 5, 1, 10), + new Selection(2, 5, 2, 10), + new Selection(3, 5, 3, 8), + ]); + }); + }); + + test('issue #20651: AddSelectionToNextFindMatchAction case insensitive', () => { + const text = [ + 'test', + 'testte', + 'Test', + 'testte', + 'test' + ]; + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 1, 1, 5), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 5), + new Selection(2, 1, 2, 5), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 5), + new Selection(2, 1, 2, 5), + new Selection(3, 1, 3, 5), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 5), + new Selection(2, 1, 2, 5), + new Selection(3, 1, 3, 5), + new Selection(4, 1, 4, 5), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 5), + new Selection(2, 1, 2, 5), + new Selection(3, 1, 3, 5), + new Selection(4, 1, 4, 5), + new Selection(5, 1, 5, 5), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 5), + new Selection(2, 1, 2, 5), + new Selection(3, 1, 3, 5), + new Selection(4, 1, 4, 5), + new Selection(5, 1, 5, 5), + ]); + }); + }); + + suite('Find state disassociation', () => { + + const text = [ + 'app', + 'apples', + 'whatsapp', + 'app', + 'App', + ' app' + ]; + + test('enters mode', () => { + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 2, 1, 2), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(4, 1, 4, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(4, 1, 4, 4), + new Selection(6, 2, 6, 5), + ]); + }); + }); + + test('leaves mode when selection changes', () => { + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 2, 1, 2), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(4, 1, 4, 4), + ]); + + // change selection + editor.setSelections([ + new Selection(1, 1, 1, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + ]); + }); + }); + + test('Select Highlights respects mode ', () => { + testMulticursor(text, (editor, findController) => { + let action = new SelectHighlightsAction(); + editor.setSelections([ + new Selection(1, 2, 1, 2), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(4, 1, 4, 4), + new Selection(6, 2, 6, 5), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(4, 1, 4, 4), + new Selection(6, 2, 6, 5), + ]); + }); + }); + + }); +}); diff --git a/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts b/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts index 3ab3d31ffe2..b920ccb714d 100644 --- a/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts +++ b/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts @@ -12,6 +12,7 @@ import { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveM import * as dom from 'vs/base/browser/dom'; import { ICodeEditor, IContentWidget, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; import { QuickFixComputeEvent } from './quickFixModel'; +import { computeIndentLevel } from 'vs/editor/common/model/modelLine'; export class LightBulbWidget implements IDisposable, IContentWidget { @@ -138,7 +139,9 @@ export class LightBulbWidget implements IDisposable, IContentWidget { } const { lineNumber } = this._model.position; const model = this._editor.getModel(); - const indent = model.getIndentLevel(lineNumber); + const tabSize = model.getOptions().tabSize; + const lineContent = model.getLineContent(lineNumber); + const indent = computeIndentLevel(lineContent, tabSize); const lineHasSpace = config.fontInfo.spaceWidth * indent > 22; let effectiveLineNumber = lineNumber; diff --git a/src/vs/editor/contrib/snippet/browser/snippet.md b/src/vs/editor/contrib/snippet/browser/snippet.md index 458cccbdb96..403cda77438 100644 --- a/src/vs/editor/contrib/snippet/browser/snippet.md +++ b/src/vs/editor/contrib/snippet/browser/snippet.md @@ -25,7 +25,7 @@ With `$name` or `${name:default}` you can insert the value of a variable. When a * `TM_LINE_INDEX` The zero-index based line number * `TM_LINE_NUMBER` The one-index based line number * `TM_FILENAME` The filename of the current document -* `TM_DIRECTORY` The direcorty of the current document +* `TM_DIRECTORY` The directory of the current document * `TM_FILEPATH` The full file path of the current document Variable-Transform diff --git a/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts index 573f8f08a9e..7f563dc6e31 100644 --- a/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts @@ -11,7 +11,7 @@ import { onUnexpectedExternalError } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { CommonEditorRegistry, commonEditorContribution } from 'vs/editor/common/editorCommonExtensions'; +import { CommonEditorRegistry, commonEditorContribution, EditorAction, IActionOptions, editorAction } from 'vs/editor/common/editorCommonExtensions'; import { DocumentHighlight, DocumentHighlightKind, DocumentHighlightProviderRegistry } from 'vs/editor/common/modes'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Position } from 'vs/editor/common/core/position'; @@ -19,6 +19,11 @@ import { registerColor, editorSelectionHighlight, activeContrastBorder, overview import { registerThemingParticipant, themeColorFromId } from 'vs/platform/theme/common/themeService'; import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; +import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { firstIndex } from 'vs/base/common/arrays'; export const editorWordHighlight = registerColor('editor.wordHighlightBackground', { dark: '#575757B8', light: '#57575740', hc: null }, nls.localize('wordHighlight', 'Background color of a symbol during read-access, like reading a variable.')); export const editorWordHighlightStrong = registerColor('editor.wordHighlightStrongBackground', { dark: '#004972B8', light: '#0e639c40', hc: null }, nls.localize('wordHighlightStrong', 'Background color of a symbol during write-access, like writing to a variable.')); @@ -26,6 +31,8 @@ export const editorWordHighlightStrong = registerColor('editor.wordHighlightStro export const overviewRulerWordHighlightForeground = registerColor('editorOverviewRuler.wordHighlightForeground', { dark: '#A0A0A0', light: '#A0A0A0', hc: '#A0A0A0' }, nls.localize('overviewRulerWordHighlightForeground', 'Overview ruler marker color for symbol highlights.')); export const overviewRulerWordHighlightStrongForeground = registerColor('editorOverviewRuler.wordHighlightStrongForeground', { dark: '#C0A0C0', light: '#C0A0C0', hc: '#C0A0C0' }, nls.localize('overviewRulerWordHighlightStrongForeground', 'Overview ruler marker color for write-access symbol highlights.')); +export const ctxHasWordHighlights = new RawContextKey('hasWordHighlights', false); + export function getOccurrencesAtPosition(model: editorCommon.IReadOnlyModel, position: Position): TPromise { const orderedByScore = DocumentHighlightProviderRegistry.ordered(model); @@ -76,13 +83,23 @@ class WordHighlighter { private lastCursorPositionChangeTime: number = 0; private renderDecorationsTimer: number = -1; - constructor(editor: editorCommon.ICommonCodeEditor) { + private _hasWordHighlights: IContextKey; + private _ignorePositionChangeEvent: boolean; + + constructor(editor: editorCommon.ICommonCodeEditor, contextKeyService: IContextKeyService) { this.editor = editor; + this._hasWordHighlights = ctxHasWordHighlights.bindTo(contextKeyService); + this._ignorePositionChangeEvent = false; this.occurrencesHighlight = this.editor.getConfiguration().contribInfo.occurrencesHighlight; this.model = this.editor.getModel(); this.toUnhook = []; this.toUnhook.push(editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { + if (this._ignorePositionChangeEvent) { + // We are changing the position => ignore this event + return; + } + if (!this.occurrencesHighlight) { // Early exit if nothing needs to be done! // Leave some form of early exit check here if you wish to continue being a cursor position change listener ;) @@ -127,10 +144,45 @@ class WordHighlighter { this._run(); } + private _getSortedHighlights(): Range[] { + return this._decorationIds + .map((id) => this.model.getDecorationRange(id)) + .sort(Range.compareRangesUsingStarts); + } + + public moveNext() { + let highlights = this._getSortedHighlights(); + let index = firstIndex(highlights, (range) => range.containsPosition(this.editor.getPosition())); + let newIndex = ((index + 1) % highlights.length); + let dest = highlights[newIndex]; + try { + this._ignorePositionChangeEvent = true; + this.editor.setPosition(dest.getStartPosition()); + this.editor.revealRangeInCenter(dest); + } finally { + this._ignorePositionChangeEvent = false; + } + } + + public moveBack() { + let highlights = this._getSortedHighlights(); + let index = firstIndex(highlights, (range) => range.containsPosition(this.editor.getPosition())); + let newIndex = ((index - 1 + highlights.length) % highlights.length); + let dest = highlights[newIndex]; + try { + this._ignorePositionChangeEvent = true; + this.editor.setPosition(dest.getStartPosition()); + this.editor.revealRangeInCenter(dest); + } finally { + this._ignorePositionChangeEvent = false; + } + } + private _removeDecorations(): void { if (this._decorationIds.length > 0) { // remove decorations this._decorationIds = this.editor.deltaDecorations(this._decorationIds, []); + this._hasWordHighlights.set(false); } } @@ -296,6 +348,7 @@ class WordHighlighter { } this._decorationIds = this.editor.deltaDecorations(this._decorationIds, decorations); + this._hasWordHighlights.set(this.hasDecorations()); } private static _getDecorationOptions(kind: DocumentHighlightKind): ModelDecorationOptions { @@ -344,15 +397,21 @@ class WordHighlighter { } } + + @commonEditorContribution class WordHighlighterContribution implements editorCommon.IEditorContribution { private static ID = 'editor.contrib.wordHighlighter'; + public static get(editor: editorCommon.ICommonCodeEditor): WordHighlighterContribution { + return editor.getContribution(WordHighlighterContribution.ID); + } + private wordHighligher: WordHighlighter; - constructor(editor: editorCommon.ICommonCodeEditor) { - this.wordHighligher = new WordHighlighter(editor); + constructor(editor: editorCommon.ICommonCodeEditor, @IContextKeyService contextKeyService: IContextKeyService) { + this.wordHighligher = new WordHighlighter(editor, contextKeyService); } public getId(): string { @@ -366,6 +425,14 @@ class WordHighlighterContribution implements editorCommon.IEditorContribution { return false; } + public moveNext() { + this.wordHighligher.moveNext(); + } + + public moveBack() { + this.wordHighligher.moveBack(); + } + public restoreViewState(state: boolean | undefined): void { if (state) { this.wordHighligher.restore(); @@ -398,4 +465,59 @@ registerThemingParticipant((theme, collector) => { collector.addRule(`.monaco-editor .wordHighlightStrong { border: 1px dashed ${hcOutline}; box-sizing: border-box; }`); } -}); \ No newline at end of file +}); + +class WordHighlightNavigationAction extends EditorAction { + + private _isNext: boolean; + + constructor(next: boolean, opts: IActionOptions) { + super(opts); + this._isNext = next; + } + + public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { + const controller = WordHighlighterContribution.get(editor); + if (!controller) { + return; + } + + if (this._isNext) { + controller.moveNext(); + } else { + controller.moveBack(); + } + } +} + +@editorAction +class NextWordHighlightAction extends WordHighlightNavigationAction { + constructor() { + super(true, { + id: 'editor.action.wordHighlight.next', + label: nls.localize('wordHighlight.next.label', "Go to Next Symbol Highlight"), + alias: 'Go to Next Symbol Highlight', + precondition: ctxHasWordHighlights, + kbOpts: { + kbExpr: EditorContextKeys.textFocus, + primary: KeyCode.F7 + } + }); + } +} + +@editorAction +class PrevWordHighlightAction extends WordHighlightNavigationAction { + constructor() { + super(false, { + id: 'editor.action.wordHighlight.prev', + label: nls.localize('wordHighlight.previous.label', "Go to Previous Symbol Highlight"), + alias: 'Go to Previous Symbol Highlight', + precondition: ctxHasWordHighlights, + kbOpts: { + kbExpr: EditorContextKeys.textFocus, + primary: KeyMod.Shift | KeyCode.F7 + } + }); + } +} \ No newline at end of file diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 5bfb927109a..7b0a82667a1 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -139,7 +139,7 @@ export class SimpleEditorService implements IEditorService { let schema = data.resource.scheme; if (schema === Schemas.http || schema === Schemas.https) { // This is a fully qualified http or https URL - window.open(data.resource.toString()); + dom.windowOpenNoOpener(data.resource.toString()); return this.editor; } } @@ -464,30 +464,30 @@ export class SimpleConfigurationService implements IConfigurationService { getConfiguration(section: string, overrides: IConfigurationOverrides): T getConfiguration(arg1?: any, arg2?: any): any { const section = typeof arg1 === 'string' ? arg1 : void 0; - const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0; - return this.configuration().getSection(section, overrides); + const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : {}; + return this.configuration().getSection(section, overrides, null); } - public getValue(key: string, options?: IConfigurationOverrides): C { - return this.configuration().getValue(key, options); + public getValue(key: string, options: IConfigurationOverrides = {}): C { + return this.configuration().getValue(key, options, null); } public updateValue(key: string, value: any, arg3?: any, arg4?: any): TPromise { return TPromise.as(null); } - public inspect(key: string, options?: IConfigurationOverrides): { + public inspect(key: string, options: IConfigurationOverrides = {}): { default: C, user: C, workspace: C, workspaceFolder: C value: C, } { - return this.configuration().lookup(key, options); + return this.configuration().lookup(key, options, null); } public keys() { - return this.configuration().keys(); + return this.configuration().keys(null); } public reloadConfiguration(): TPromise { @@ -598,12 +598,4 @@ export class SimpleWorkspaceContextService implements IWorkspaceContextService { public isCurrentWorkspace(workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): boolean { return true; } - - public addFolders(foldersToAdd: URI[]): TPromise { - return TPromise.as(void 0); - } - - public removeFolders(foldersToRemove: URI[]): TPromise { - return TPromise.as(void 0); - } } diff --git a/src/vs/editor/test/common/commands/trimTrailingWhitespaceCommand.test.ts b/src/vs/editor/test/common/commands/trimTrailingWhitespaceCommand.test.ts index 08a1664cbe0..e780615c263 100644 --- a/src/vs/editor/test/common/commands/trimTrailingWhitespaceCommand.test.ts +++ b/src/vs/editor/test/common/commands/trimTrailingWhitespaceCommand.test.ts @@ -14,7 +14,7 @@ import { withEditorModel } from 'vs/editor/test/common/editorTestUtils'; function assertTrimTrailingWhitespaceCommand(text: string[], expected: IIdentifiedSingleEditOperation[]): void { return withEditorModel(text, (model) => { - var op = new TrimTrailingWhitespaceCommand(new Selection(1, 1, 1, 1)); + var op = new TrimTrailingWhitespaceCommand(new Selection(1, 1, 1, 1), []); var actual = getEditOperation(model, op); assert.deepEqual(actual, expected); }); diff --git a/src/vs/editor/test/common/controller/cursor.test.ts b/src/vs/editor/test/common/controller/cursor.test.ts index 8b8a9bd46c4..63eae2816d3 100644 --- a/src/vs/editor/test/common/controller/cursor.test.ts +++ b/src/vs/editor/test/common/controller/cursor.test.ts @@ -1453,9 +1453,9 @@ suite('Editor Controller - Regression tests', () => { cursorCommand(cursor, H.Undo); assert.equal(model.getValue(), [ - 'some lines', - 'and more lines', - 'just some text', + ' some lines', + ' and more lines', + ' just some text', ].join('\n'), '002'); cursorCommand(cursor, H.Undo); @@ -1464,6 +1464,13 @@ suite('Editor Controller - Regression tests', () => { 'and more lines', 'just some text', ].join('\n'), '003'); + + cursorCommand(cursor, H.Undo); + assert.equal(model.getValue(), [ + 'some lines', + 'and more lines', + 'just some text', + ].join('\n'), '004'); }); model.dispose(); @@ -1622,6 +1629,24 @@ suite('Editor Controller - Regression tests', () => { }); }); + test('issue #33788: Wrong cursor position when double click to select a word', () => { + let model = Model.createFromString( + [ + 'Just some text' + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + CoreNavigationCommands.WordSelect.runCoreEditorCommand(cursor, { position: new Position(1, 8) }); + assert.deepEqual(cursor.getSelection(), new Selection(1, 6, 1, 10)); + + CoreNavigationCommands.WordSelectDrag.runCoreEditorCommand(cursor, { position: new Position(1, 8) }); + assert.deepEqual(cursor.getSelection(), new Selection(1, 6, 1, 10)); + }); + + model.dispose(); + }); + test('issue #9675: Undo/Redo adds a stop in between CHN Characters', () => { usingCursor({ text: [ @@ -1716,6 +1741,49 @@ suite('Editor Controller - Regression tests', () => { assertCursor(cursor, new Selection(1, 1, 1, 1)); }); }); + + test('issue #36740: wordwrap creates an extra step / character at the wrapping point', () => { + // a single model line => 4 view lines + withMockCodeEditor([ + [ + 'Lorem ipsum ', + 'dolor sit amet ', + 'consectetur ', + 'adipiscing elit', + ].join('') + ], { wordWrap: 'wordWrapColumn', wordWrapColumn: 16 }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(1, 7, 1, 7)]); + + moveRight(cursor); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + moveRight(cursor); + assertCursor(cursor, new Selection(1, 9, 1, 9)); + + moveRight(cursor); + assertCursor(cursor, new Selection(1, 10, 1, 10)); + + moveRight(cursor); + assertCursor(cursor, new Selection(1, 11, 1, 11)); + + moveRight(cursor); + assertCursor(cursor, new Selection(1, 12, 1, 12)); + + moveRight(cursor); + assertCursor(cursor, new Selection(1, 13, 1, 13)); + + // moving to view line 2 + moveRight(cursor); + assertCursor(cursor, new Selection(1, 14, 1, 14)); + + moveLeft(cursor); + assertCursor(cursor, new Selection(1, 13, 1, 13)); + + // moving back to view line 1 + moveLeft(cursor); + assertCursor(cursor, new Selection(1, 12, 1, 12)); + }); + }); }); suite('Editor Controller - Cursor Configuration', () => { @@ -3106,6 +3174,93 @@ suite('Editor Controller - Indentation Rules', () => { assert.equal(model.getLineContent(3), '}'); }); }); + + test('issue #36090: JS: editor.autoIndent seems to be broken', () => { + class JSMode extends MockMode { + private static _id = new LanguageIdentifier('indentRulesMode', 4); + constructor() { + super(JSMode._id); + this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), { + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + indentationRules: { + // ^(.*\*/)?\s*\}.*$ + decreaseIndentPattern: /^((?!.*?\/\*).*\*\/)?\s*[\}\]\)].*$/, + // ^.*\{[^}"']*$ + increaseIndentPattern: /^((?!\/\/).)*(\{[^}"'`]*|\([^)"'`]*|\[[^\]"'`]*)$/ + }, + onEnterRules: [ + { + // e.g. /** | */ + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + afterText: /^\s*\*\/$/, + action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' } + }, { + // e.g. /** ...| + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + action: { indentAction: IndentAction.None, appendText: ' * ' } + }, { + // e.g. * ...| + beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/, + action: { indentAction: IndentAction.None, appendText: '* ' } + }, { + // e.g. */| + beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/, + action: { indentAction: IndentAction.None, removeText: 1 } + }, + { + // e.g. *-----*/| + beforeText: /^(\t|(\ \ ))*\ \*[^/]*\*\/\s*$/, + action: { indentAction: IndentAction.None, removeText: 1 } + } + ] + })); + } + } + + let mode = new JSMode(); + let model = Model.createFromString( + [ + 'class ItemCtrl {', + ' getPropertiesByItemId(id) {', + ' return this.fetchItem(id)', + ' .then(item => {', + ' return this.getPropertiesOfItem(item);', + ' });', + ' }', + '}', + ].join('\n'), + undefined, + mode.getLanguageIdentifier() + ); + + withMockCodeEditor(null, { model: model, autoIndent: false }, (editor, cursor) => { + moveTo(cursor, 7, 6, false); + assertCursor(cursor, new Selection(7, 6, 7, 6)); + + cursorCommand(cursor, H.Type, { text: '\n' }, 'keyboard'); + assert.equal(model.getValue(), + [ + 'class ItemCtrl {', + ' getPropertiesByItemId(id) {', + ' return this.fetchItem(id)', + ' .then(item => {', + ' return this.getPropertiesOfItem(item);', + ' });', + ' }', + ' ', + '}', + ].join('\n') + ); + assertCursor(cursor, new Selection(8, 5, 8, 5)); + }); + + model.dispose(); + mode.dispose(); + }); }); interface ICursorOpts { @@ -3728,3 +3883,232 @@ suite('autoClosingPairs', () => { }); }); }); + +suite('Undo stops', () => { + + test('there is an undo stop between typing and deleting left', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(1, 3, 1, 3)]); + cursorCommand(cursor, H.Type, { text: 'first' }, 'keyboard'); + assert.equal(model.getLineContent(1), 'A first line'); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(1), 'A fir line'); + assertCursor(cursor, new Selection(1, 6, 1, 6)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A first line'); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A line'); + assertCursor(cursor, new Selection(1, 3, 1, 3)); + }); + }); + + test('there is an undo stop between typing and deleting right', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(1, 3, 1, 3)]); + cursorCommand(cursor, H.Type, { text: 'first' }, 'keyboard'); + assert.equal(model.getLineContent(1), 'A first line'); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(1), 'A firstine'); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A first line'); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A line'); + assertCursor(cursor, new Selection(1, 3, 1, 3)); + }); + }); + + test('there is an undo stop between deleting left and typing', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(2, 8, 2, 8)]); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(2), ' line'); + assertCursor(cursor, new Selection(2, 1, 2, 1)); + + cursorCommand(cursor, H.Type, { text: 'Second' }, 'keyboard'); + assert.equal(model.getLineContent(2), 'Second line'); + assertCursor(cursor, new Selection(2, 7, 2, 7)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), ' line'); + assertCursor(cursor, new Selection(2, 1, 2, 1)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), 'Another line'); + assertCursor(cursor, new Selection(2, 8, 2, 8)); + }); + }); + + test('there is an undo stop between deleting left and deleting right', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(2, 8, 2, 8)]); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(2), ' line'); + assertCursor(cursor, new Selection(2, 1, 2, 1)); + + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(2), ''); + assertCursor(cursor, new Selection(2, 1, 2, 1)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), ' line'); + assertCursor(cursor, new Selection(2, 1, 2, 1)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), 'Another line'); + assertCursor(cursor, new Selection(2, 8, 2, 8)); + }); + }); + + test('there is an undo stop between deleting right and typing', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(2, 9, 2, 9)]); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(2), 'Another '); + assertCursor(cursor, new Selection(2, 9, 2, 9)); + + cursorCommand(cursor, H.Type, { text: 'text' }, 'keyboard'); + assert.equal(model.getLineContent(2), 'Another text'); + assertCursor(cursor, new Selection(2, 13, 2, 13)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), 'Another '); + assertCursor(cursor, new Selection(2, 9, 2, 9)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), 'Another line'); + assertCursor(cursor, new Selection(2, 9, 2, 9)); + }); + }); + + test('there is an undo stop between deleting right and deleting left', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(2, 9, 2, 9)]); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(2), 'Another '); + assertCursor(cursor, new Selection(2, 9, 2, 9)); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(2), 'An'); + assertCursor(cursor, new Selection(2, 3, 2, 3)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), 'Another '); + assertCursor(cursor, new Selection(2, 9, 2, 9)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), 'Another line'); + assertCursor(cursor, new Selection(2, 9, 2, 9)); + }); + }); + + test('inserts undo stop when typing space', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(1, 3, 1, 3)]); + cursorCommand(cursor, H.Type, { text: 'first and interesting' }, 'keyboard'); + assert.equal(model.getLineContent(1), 'A first and interesting line'); + assertCursor(cursor, new Selection(1, 24, 1, 24)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A first and line'); + assertCursor(cursor, new Selection(1, 12, 1, 12)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A first line'); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A line'); + assertCursor(cursor, new Selection(1, 3, 1, 3)); + }); + }); + +}); diff --git a/src/vs/editor/test/common/mocks/mockCodeEditor.ts b/src/vs/editor/test/common/mocks/mockCodeEditor.ts index afb99c73774..33621c3d209 100644 --- a/src/vs/editor/test/common/mocks/mockCodeEditor.ts +++ b/src/vs/editor/test/common/mocks/mockCodeEditor.ts @@ -18,6 +18,9 @@ import * as editorOptions from 'vs/editor/common/config/editorOptions'; import { IDisposable } from 'vs/base/common/lifecycle'; export class MockCodeEditor extends CommonCodeEditor { + + public _isFocused = true; + protected _createConfiguration(options: editorOptions.IEditorOptions): CommonEditorConfiguration { return new TestConfiguration(options); } @@ -25,7 +28,7 @@ export class MockCodeEditor extends CommonCodeEditor { public layout(dimension?: editorCommon.IDimension): void { } public focus(): void { } - public isFocused(): boolean { return true; } + public isFocused(): boolean { return this._isFocused; } public hasWidgetFocus(): boolean { return true; }; protected _enableEmptySelectionClipboard(): boolean { return false; } diff --git a/src/vs/editor/test/common/model/indentRanges.test.ts b/src/vs/editor/test/common/model/indentRanges.test.ts index 6d09f3f1ce2..a703fcc42d5 100644 --- a/src/vs/editor/test/common/model/indentRanges.test.ts +++ b/src/vs/editor/test/common/model/indentRanges.test.ts @@ -7,30 +7,33 @@ import * as assert from 'assert'; import { Model } from 'vs/editor/common/model/model'; -import { computeRanges } from 'vs/editor/common/model/indentRanges'; +import { computeRanges, MAX_FOLDING_REGIONS } from 'vs/editor/common/model/indentRanges'; import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration'; -export interface IndentRange { +export interface ExpectedIndentRange { startLineNumber: number; endLineNumber: number; indent: number; - marker: boolean; + parentIndex: number; } -function assertRanges(lines: string[], expected: IndentRange[], offside: boolean, markers?: FoldingMarkers): void { +function assertRanges(lines: string[], expected: ExpectedIndentRange[], offside: boolean, markers?: FoldingMarkers): void { let model = Model.createFromString(lines.join('\n')); let actual = computeRanges(model, offside, markers); - actual.sort((r1, r2) => r1.startLineNumber - r2.startLineNumber); - assert.deepEqual(actual, expected); + + let actualRanges = []; + for (let i = 0; i < actual.length; i++) { + actualRanges[i] = r(actual.getStartLineNumber(i), actual.getEndLineNumber(i), actual.getIndent(i), actual.getParentIndex(i)); + } + assert.deepEqual(actualRanges, expected); model.dispose(); } -function r(startLineNumber: number, endLineNumber: number, indent: number, marker?: boolean): IndentRange { - return { startLineNumber, endLineNumber, indent, marker }; +function r(startLineNumber: number, endLineNumber: number, indent: number, parentIndex: number, marker = false): ExpectedIndentRange { + return { startLineNumber, endLineNumber, indent, parentIndex }; } suite('Indentation Folding', () => { - test('Fold one level', () => { let range = [ 'A', @@ -38,8 +41,8 @@ suite('Indentation Folding', () => { ' A', ' A' ]; - assertRanges(range, [r(1, 4, 0)], true); - assertRanges(range, [r(1, 4, 0)], false); + assertRanges(range, [r(1, 4, 0, -1)], true); + assertRanges(range, [r(1, 4, 0, -1)], false); }); test('Fold two levels', () => { @@ -50,8 +53,8 @@ suite('Indentation Folding', () => { ' A', ' A' ]; - assertRanges(range, [r(1, 5, 0), r(3, 5, 2)], true); - assertRanges(range, [r(1, 5, 0), r(3, 5, 2)], false); + assertRanges(range, [r(1, 5, 0, -1), r(3, 5, 2, 0)], true); + assertRanges(range, [r(1, 5, 0, -1), r(3, 5, 2, 0)], false); }); test('Fold three levels', () => { @@ -62,8 +65,8 @@ suite('Indentation Folding', () => { ' A', 'A' ]; - assertRanges(range, [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)], true); - assertRanges(range, [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)], false); + assertRanges(range, [r(1, 4, 0, -1), r(2, 4, 2, 0), r(3, 4, 4, 1)], true); + assertRanges(range, [r(1, 4, 0, -1), r(2, 4, 2, 0), r(3, 4, 4, 1)], false); }); test('Fold decreasing indent', () => { @@ -91,7 +94,7 @@ suite('Indentation Folding', () => { /*11*/ 'interface B {', /*12*/ ' void bar();', /*13*/ '}', - ], [r(1, 9, 0), r(2, 4, 2), r(7, 8, 2), r(11, 12, 0)], false); + ], [r(1, 9, 0, -1), r(2, 4, 2, 0), r(7, 8, 2, 0), r(11, 12, 0, -1)], false); }); test('Fold Javadoc', () => { @@ -103,7 +106,7 @@ suite('Indentation Folding', () => { /* 5*/ ' void foo() {', /* 6*/ ' }', /* 7*/ '}', - ], [r(1, 3, 0), r(4, 6, 0)], false); + ], [r(1, 3, 0, -1), r(4, 6, 0, -1)], false); }); test('Fold Whitespace Java', () => { assertRanges([ @@ -115,7 +118,7 @@ suite('Indentation Folding', () => { /* 6*/ ' }', /* 7*/ ' ', /* 8*/ '}', - ], [r(1, 7, 0), r(3, 5, 2)], false); + ], [r(1, 7, 0, -1), r(3, 5, 2, 0)], false); }); test('Fold Whitespace Python', () => { @@ -128,7 +131,7 @@ suite('Indentation Folding', () => { /* 6*/ ' ', /* 7*/ ' ', /* 8*/ 'def c: # since there was a deintent here' - ], [r(1, 5, 0), r(4, 5, 2)], true); + ], [r(1, 5, 0, -1), r(4, 5, 2, 0)], true); }); test('Fold Tabs', () => { @@ -141,7 +144,7 @@ suite('Indentation Folding', () => { /* 6*/ ' \t}', /* 7*/ ' ', /* 8*/ '}', - ], [r(1, 7, 0), r(3, 5, 4)], false); + ], [r(1, 7, 0, -1), r(3, 5, 4, 0)], false); }); }); @@ -161,7 +164,7 @@ suite('Folding with regions', () => { /* 6*/ ' }', /* 7*/ ' #endregion', /* 8*/ '}', - ], [r(1, 7, 0), r(2, 7, 2, true), r(3, 5, 2)], false, markers); + ], [r(1, 7, 0, -1), r(2, 7, 2, 0, true), r(3, 5, 2, 1)], false, markers); }); test('Inside region, not indented', () => { assertRanges([ @@ -173,7 +176,7 @@ suite('Folding with regions', () => { /* 6*/ ' }', /* 7*/ '#endregion', /* 8*/ '', - ], [r(2, 7, 0, true), r(3, 6, 0)], false, markers); + ], [r(2, 7, 0, -1, true), r(3, 6, 0, 0)], false, markers); }); test('Empty Regions', () => { assertRanges([ @@ -184,7 +187,7 @@ suite('Folding with regions', () => { /* 5*/ '', /* 6*/ '#endregion', /* 7*/ 'var y;', - ], [r(2, 3, 0, true), r(4, 6, 0, true)], false, markers); + ], [r(2, 3, 0, -1, true), r(4, 6, 0, -1, true)], false, markers); }); test('Nested Regions', () => { assertRanges([ @@ -195,7 +198,7 @@ suite('Folding with regions', () => { /* 5*/ '#endregion', /* 6*/ '#endregion', /* 7*/ 'var y;', - ], [r(2, 6, 0, true), r(3, 5, 0, true)], false, markers); + ], [r(2, 6, 0, -1, true), r(3, 5, 0, 0, true)], false, markers); }); test('Nested Regions 2', () => { assertRanges([ @@ -208,7 +211,7 @@ suite('Folding with regions', () => { /* 7*/ ' // comment', /* 8*/ ' #endregion', /* 9*/ '}', - ], [r(1, 8, 0), r(2, 8, 2, true), r(4, 6, 2, true)], false, markers); + ], [r(1, 8, 0, -1), r(2, 8, 2, 0, true), r(4, 6, 2, 1, true)], false, markers); }); test('Incomplete Regions', () => { assertRanges([ @@ -216,7 +219,7 @@ suite('Folding with regions', () => { /* 2*/ '#region', /* 3*/ ' // comment', /* 4*/ '}', - ], [r(2, 3, 0)], false, markers); + ], [r(2, 3, 0, -1)], false, markers); }); test('Incomplete Regions 2', () => { assertRanges([ @@ -228,7 +231,7 @@ suite('Folding with regions', () => { /* 6*/ '#endregion', /* 7*/ '#endregion', /* 8*/ ' // hello', - ], [r(3, 7, 0, true), r(4, 6, 0, true)], false, markers); + ], [r(3, 7, 0, -1, true), r(4, 6, 0, 0, true)], false, markers); }); test('Indented region before', () => { assertRanges([ @@ -238,7 +241,7 @@ suite('Folding with regions', () => { /* 4*/ '#region', /* 5*/ ' // comment', /* 6*/ '#endregion', - ], [r(1, 3, 0), r(4, 6, 0, true)], false, markers); + ], [r(1, 3, 0, -1), r(4, 6, 0, -1, true)], false, markers); }); test('Indented region before 2', () => { assertRanges([ @@ -248,7 +251,7 @@ suite('Folding with regions', () => { /* 4*/ ' #region', /* 5*/ ' // comment', /* 6*/ ' #endregion', - ], [r(1, 6, 0), r(2, 6, 2), r(4, 6, 4, true)], false, markers); + ], [r(1, 6, 0, -1), r(2, 6, 2, 0), r(4, 6, 4, 1, true)], false, markers); }); test('Indented region in-between', () => { assertRanges([ @@ -258,7 +261,7 @@ suite('Folding with regions', () => { /* 4*/ ' return;', /* 5*/ '', /* 6*/ '#endregion', - ], [r(1, 6, 0, true), r(3, 5, 2)], false, markers); + ], [r(1, 6, 0, -1, true), r(3, 5, 2, 0)], false, markers); }); test('Indented region after', () => { assertRanges([ @@ -268,7 +271,7 @@ suite('Folding with regions', () => { /* 4*/ '#endregion', /* 5*/ ' if (x)', /* 6*/ ' return;', - ], [r(1, 4, 0, true), r(5, 6, 2)], false, markers); + ], [r(1, 4, 0, -1, true), r(5, 6, 2, -1)], false, markers); }); test('With off-side', () => { assertRanges([ @@ -277,7 +280,7 @@ suite('Folding with regions', () => { /* 3*/ '', /* 4*/ '#endregion', /* 5*/ '', - ], [r(1, 4, 0, true)], true, markers); + ], [r(1, 4, 0, -1, true)], true, markers); }); test('Nested with off-side', () => { assertRanges([ @@ -289,7 +292,7 @@ suite('Folding with regions', () => { /* 6*/ '', /* 7*/ '#endregion', /* 8*/ '', - ], [r(1, 7, 0, true), r(3, 5, 0, true)], true, markers); + ], [r(1, 7, 0, -1, true), r(3, 5, 0, 0, true)], true, markers); }); test('Issue 35981', () => { assertRanges([ @@ -302,7 +305,7 @@ suite('Folding with regions', () => { /* 7*/ 'function thisFoldsProperly() {', /* 8*/ ' const foo = "bar"', /* 9*/ '}', - ], [r(1, 4, 0), r(2, 4, 2), r(7, 8, 0)], false, markers); + ], [r(1, 4, 0, -1), r(2, 4, 2, 0), r(7, 8, 0, -1)], false, markers); }); test('Misspelled Markers', () => { assertRanges([ @@ -316,4 +319,70 @@ suite('Folding with regions', () => { /* 8*/ '#endregionff', ], [], true, markers); }); + + test('test max folding regions', () => { + let lines = []; + let nRegions = MAX_FOLDING_REGIONS; + for (let i = 0; i < nRegions; i++) { + lines.push('#region'); + } + for (let i = 0; i < nRegions; i++) { + lines.push('#endregion'); + } + let model = Model.createFromString(lines.join('\n')); + let actual = computeRanges(model, false, markers, MAX_FOLDING_REGIONS); + assert.equal(actual.length, nRegions, 'len'); + for (let i = 0; i < nRegions; i++) { + assert.equal(actual.getStartLineNumber(i), i + 1, 'start' + i); + assert.equal(actual.getEndLineNumber(i), nRegions * 2 - i, 'end' + i); + assert.equal(actual.getParentIndex(i), i - 1, 'parent' + i); + } + + }); + + test('findRange', () => { + let lines = [ + /* 1*/ '#region', + /* 2*/ '#endregion', + /* 3*/ 'class A {', + /* 4*/ ' void foo() {', + /* 5*/ ' if (true) {', + /* 6*/ ' return;', + /* 7*/ ' }', + /* 8*/ '', + /* 9*/ ' if (true) {', + /* 10*/ ' return;', + /* 11*/ ' }', + /* 12*/ ' }', + /* 13*/ '}']; + + let textModel = Model.createFromString(lines.join('\n')); + try { + let actual = computeRanges(textModel, false, markers); + // let r0 = r(1, 2); + // let r1 = r(3, 12); + // let r2 = r(4, 11); + // let r3 = r(5, 6); + // let r4 = r(9, 10); + + assert.equal(actual.findRange(1), 0, '1'); + assert.equal(actual.findRange(2), 0, '2'); + assert.equal(actual.findRange(3), 1, '3'); + assert.equal(actual.findRange(4), 2, '4'); + assert.equal(actual.findRange(5), 3, '5'); + assert.equal(actual.findRange(6), 3, '6'); + assert.equal(actual.findRange(7), 2, '7'); + assert.equal(actual.findRange(8), 2, '8'); + assert.equal(actual.findRange(9), 4, '9'); + assert.equal(actual.findRange(10), 4, '10'); + assert.equal(actual.findRange(11), 2, '11'); + assert.equal(actual.findRange(12), 1, '12'); + assert.equal(actual.findRange(13), -1, '13'); + } finally { + textModel.dispose(); + } + + + }); + }); \ No newline at end of file diff --git a/src/vs/editor/test/common/model/model.line.test.ts b/src/vs/editor/test/common/model/model.line.test.ts index a2e75ba4ae9..b493063ecf5 100644 --- a/src/vs/editor/test/common/model/model.line.test.ts +++ b/src/vs/editor/test/common/model/model.line.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; -import { ModelLine, ILineEdit } from 'vs/editor/common/model/modelLine'; +import { ModelLine, ILineEdit, computeIndentLevel } from 'vs/editor/common/model/modelLine'; import { MetadataConsts } from 'vs/editor/common/modes'; import { ViewLineToken, ViewLineTokenFactory } from 'vs/editor/common/core/viewLineToken'; @@ -22,12 +22,9 @@ function assertLineTokens(_actual: LineTokens, _expected: TestToken[]): void { assert.deepEqual(actual.map(decode), expected.map(decode)); } -const NO_TAB_SIZE = 0; - suite('ModelLine - getIndentLevel', () => { function assertIndentLevel(text: string, expected: number, tabSize: number = 4): void { - let modelLine = new ModelLine(text, tabSize); - let actual = modelLine.getIndentLevel(); + let actual = computeIndentLevel(text, tabSize); assert.equal(actual, expected, text); } @@ -52,8 +49,8 @@ suite('ModelLine - getIndentLevel', () => { suite('Editor Model - modelLine.applyEdits text', () => { function testEdits(initial: string, edits: ILineEdit[], expected: string): void { - var line = new ModelLine(initial, NO_TAB_SIZE); - line.applyEdits(edits, NO_TAB_SIZE); + var line = new ModelLine(initial); + line.applyEdits(edits); assert.equal(line.text, expected); } @@ -198,8 +195,8 @@ suite('Editor Model - modelLine.applyEdits text', () => { suite('Editor Model - modelLine.split text', () => { function testLineSplit(initial: string, splitColumn: number, expected1: string, expected2: string): void { - var line = new ModelLine(initial, NO_TAB_SIZE); - var newLine = line.split(splitColumn, NO_TAB_SIZE); + var line = new ModelLine(initial); + var newLine = line.split(splitColumn); assert.equal(line.text, expected1); assert.equal(newLine.text, expected2); } @@ -235,9 +232,9 @@ suite('Editor Model - modelLine.split text', () => { suite('Editor Model - modelLine.append text', () => { function testLineAppend(a: string, b: string, expected: string): void { - var line1 = new ModelLine(a, NO_TAB_SIZE); - var line2 = new ModelLine(b, NO_TAB_SIZE); - line1.append(line2, NO_TAB_SIZE); + var line1 = new ModelLine(a); + var line2 = new ModelLine(b); + line1.append(line2); assert.equal(line1.text, expected); } @@ -296,23 +293,23 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { function testLineEditTokens(initialText: string, initialTokens: TestToken[], edits: ILineEdit[], expectedText: string, expectedTokens: TestToken[]): void { - let line = new ModelLine(initialText, NO_TAB_SIZE); + let line = new ModelLine(initialText); line.setTokens(0, TestToken.toTokens(initialTokens)); - line.applyEdits(edits, NO_TAB_SIZE); + line.applyEdits(edits); assert.equal(line.text, expectedText); assertLineTokens(line.getTokens(0), expectedTokens); } test('insertion on empty line', () => { - let line = new ModelLine('some text', NO_TAB_SIZE); + let line = new ModelLine('some text'); line.setTokens(0, TestToken.toTokens([new TestToken(0, 1)])); - line.applyEdits([{ startColumn: 1, endColumn: 10, text: '' }], NO_TAB_SIZE); + line.applyEdits([{ startColumn: 1, endColumn: 10, text: '' }]); line.setTokens(0, new Uint32Array(0)); - line.applyEdits([{ startColumn: 1, endColumn: 1, text: 'a' }], NO_TAB_SIZE); + line.applyEdits([{ startColumn: 1, endColumn: 1, text: 'a' }]); assertLineTokens(line.getTokens(0), [new TestToken(0, 1)]); }); @@ -843,10 +840,10 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { suite('Editor Model - modelLine.split text & tokens', () => { function testLineSplitTokens(initialText: string, initialTokens: TestToken[], splitColumn: number, expectedText1: string, expectedText2: string, expectedTokens: TestToken[]): void { - let line = new ModelLine(initialText, NO_TAB_SIZE); + let line = new ModelLine(initialText); line.setTokens(0, TestToken.toTokens(initialTokens)); - let other = line.split(splitColumn, NO_TAB_SIZE); + let other = line.split(splitColumn); assert.equal(line.text, expectedText1); assert.equal(other.text, expectedText2); @@ -927,13 +924,13 @@ suite('Editor Model - modelLine.split text & tokens', () => { suite('Editor Model - modelLine.append text & tokens', () => { function testLineAppendTokens(aText: string, aTokens: TestToken[], bText: string, bTokens: TestToken[], expectedText: string, expectedTokens: TestToken[]): void { - let a = new ModelLine(aText, NO_TAB_SIZE); + let a = new ModelLine(aText); a.setTokens(0, TestToken.toTokens(aTokens)); - let b = new ModelLine(bText, NO_TAB_SIZE); + let b = new ModelLine(bText); b.setTokens(0, TestToken.toTokens(bTokens)); - a.append(b, NO_TAB_SIZE); + a.append(b); assert.equal(a.text, expectedText); assertLineTokens(a.getTokens(0), expectedTokens); @@ -1047,9 +1044,9 @@ suite('Editor Model - modelLine.append text & tokens', () => { suite('Editor Model - modelLine.applyEdits', () => { function testLineEdit(initialText: string, edits: ILineEdit[], expectedText: string): void { - let line = new ModelLine(initialText, NO_TAB_SIZE); + let line = new ModelLine(initialText); - line.applyEdits(edits, NO_TAB_SIZE); + line.applyEdits(edits); assert.equal(line.text, expectedText, 'text'); } @@ -1402,9 +1399,9 @@ suite('Editor Model - modelLine.applyEdits', () => { suite('Editor Model - modelLine.split', () => { function testLineSplit(initialText: string, splitColumn: number, forceMoveMarkers: boolean, expectedText1: string, expectedText2: string): void { - let line = new ModelLine(initialText, NO_TAB_SIZE); + let line = new ModelLine(initialText); - let otherLine = line.split(splitColumn, NO_TAB_SIZE); + let otherLine = line.split(splitColumn); assert.equal(line.text, expectedText1, 'text'); assert.equal(otherLine.text, expectedText2, 'text'); @@ -1484,10 +1481,10 @@ suite('Editor Model - modelLine.split', () => { suite('Editor Model - modelLine.append', () => { function testLinePrependMarkers(aText: string, bText: string, expectedText: string): void { - let a = new ModelLine(aText, NO_TAB_SIZE); - let b = new ModelLine(bText, NO_TAB_SIZE); + let a = new ModelLine(aText); + let b = new ModelLine(bText); - a.append(b, NO_TAB_SIZE); + a.append(b); assert.equal(a.text, expectedText, 'text'); } diff --git a/src/vs/editor/test/common/model/textModelWithTokens.test.ts b/src/vs/editor/test/common/model/textModelWithTokens.test.ts index 24c66e08947..1ee24bc97c7 100644 --- a/src/vs/editor/test/common/model/textModelWithTokens.test.ts +++ b/src/vs/editor/test/common/model/textModelWithTokens.test.ts @@ -365,9 +365,11 @@ suite('TextModel.getLineIndentGuide', () => { let text = lines.map(l => l[1]).join('\n'); let model = Model.createFromString(text); + let actualIndents = model.getLinesIndentGuides(1, model.getLineCount()); + let actual: [number, string][] = []; for (let line = 1; line <= model.getLineCount(); line++) { - actual[line - 1] = [model.getLineIndentGuide(line), model.getLineContent(line)]; + actual[line - 1] = [actualIndents[line - 1], model.getLineContent(line)]; } // let expected = lines.map(l => l[0]); @@ -408,8 +410,8 @@ suite('TextModel.getLineIndentGuide', () => { test('getLineIndentGuide decreasing indent', () => { assertIndentGuides([ - [0, ' A'], - [0, ' A'], + [1, ' A'], + [1, ' A'], [0, 'A'], ]); }); @@ -450,7 +452,7 @@ suite('TextModel.getLineIndentGuide', () => { [1, ''], [1, ' void foo() {'], [1, ' '], - [1, ' return 1;'], + [2, ' return 1;'], [1, ' }'], [1, ' '], [0, '}'], diff --git a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts index cca084b0918..9b187cf4a63 100644 --- a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts +++ b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts @@ -136,15 +136,17 @@ suite('Editor ViewModel - SplitLinesCollection', () => { assert.equal(linesCollection.getViewLineCount(), 6); // getOutputIndentGuide - assert.equal(linesCollection.getViewLineIndentGuide(-1), 0); - assert.equal(linesCollection.getViewLineIndentGuide(0), 0); - assert.equal(linesCollection.getViewLineIndentGuide(1), 0); - assert.equal(linesCollection.getViewLineIndentGuide(2), 1); - assert.equal(linesCollection.getViewLineIndentGuide(3), 0); - assert.equal(linesCollection.getViewLineIndentGuide(4), 0); - assert.equal(linesCollection.getViewLineIndentGuide(5), 1); - assert.equal(linesCollection.getViewLineIndentGuide(6), 0); - assert.equal(linesCollection.getViewLineIndentGuide(7), 0); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(-1, -1), [0]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(0, 0), [0]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(1, 1), [0]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(2, 2), [1]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(3, 3), [0]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(4, 4), [0]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(5, 5), [1]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(6, 6), [0]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(7, 7), [0]); + + assert.deepEqual(linesCollection.getViewLinesIndentGuides(0, 7), [0, 1, 0, 0, 1, 0]); // getOutputLineContent assert.equal(linesCollection.getViewLineContent(-1), 'int main() {'); diff --git a/src/vs/platform/actions/electron-browser/menusExtensionPoint.ts b/src/vs/platform/actions/electron-browser/menusExtensionPoint.ts index ca45e187101..48aaa387d34 100644 --- a/src/vs/platform/actions/electron-browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/electron-browser/menusExtensionPoint.ts @@ -34,6 +34,7 @@ namespace schema { case 'editor/title': return MenuId.EditorTitle; case 'editor/context': return MenuId.EditorContext; case 'explorer/context': return MenuId.ExplorerContext; + case 'problems/context': return MenuId.ProblemsPanelContext; case 'editor/title/context': return MenuId.EditorTitleContext; case 'debug/callstack/context': return MenuId.DebugCallStackContext; case 'scm/title': return MenuId.SCMTitle; @@ -127,6 +128,11 @@ namespace schema { type: 'array', items: menuItem }, + 'problems/context': { + description: localize('menus.problemsContext', "The problems panel context menu"), + type: 'array', + items: menuItem + }, 'editor/title/context': { description: localize('menus.editorTabContext', "The editor tabs context menu"), type: 'array', diff --git a/src/vs/platform/backup/test/electron-main/backupMainService.test.ts b/src/vs/platform/backup/test/electron-main/backupMainService.test.ts index 7d5a37d4edb..d200c14c5f7 100644 --- a/src/vs/platform/backup/test/electron-main/backupMainService.test.ts +++ b/src/vs/platform/backup/test/electron-main/backupMainService.test.ts @@ -23,9 +23,10 @@ import { LogMainService } from 'vs/platform/log/common/log'; import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { createHash } from 'crypto'; import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; +import { getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; suite('BackupMainService', () => { - const parentDir = path.join(os.tmpdir(), 'vsctests', 'service'); + const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupservice'); const backupHome = path.join(parentDir, 'Backups'); const backupWorkspacesPath = path.join(backupHome, 'workspaces.json'); diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index 98a195affaa..4385e72b323 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -283,8 +283,7 @@ export class Configuration { protected _workspaceConfiguration: ConfigurationModel = new ConfigurationModel(), protected folders: StrictResourceMap = new StrictResourceMap(), protected _memoryConfiguration: ConfigurationModel = new ConfigurationModel(), - protected _memoryConfigurationByResource: StrictResourceMap = new StrictResourceMap(), - protected _workspace?: Workspace) { + protected _memoryConfigurationByResource: StrictResourceMap = new StrictResourceMap()) { this.merge(); } @@ -317,13 +316,13 @@ export class Configuration { this._foldersConsolidatedConfigurations.set(folder, this._workspaceConsolidatedConfiguration.merge(this.folders.get(folder))); } - getSection(section: string = '', overrides: IConfigurationOverrides = {}): C { - const configModel = this.getConsolidateConfigurationModel(overrides); + getSection(section: string = '', overrides: IConfigurationOverrides, workspace: Workspace): C { + const configModel = this.getConsolidateConfigurationModel(overrides, workspace); return objects.clone(section ? configModel.getSectionContents(section) : configModel.contents); } - getValue(key: string, overrides: IConfigurationOverrides = {}): any { - const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); + getValue(key: string, overrides: IConfigurationOverrides, workspace: Workspace): any { + const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides, workspace); return objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)); } @@ -350,7 +349,7 @@ export class Configuration { } } - lookup(key: string, overrides: IConfigurationOverrides = {}): { + lookup(key: string, overrides: IConfigurationOverrides, workspace: Workspace): { default: C, user: C, workspace: C, @@ -358,26 +357,26 @@ export class Configuration { memory?: C value: C, } { - const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); - const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource); + const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides, workspace); + const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource, workspace); const memoryConfigurationModel = overrides.resource ? this._memoryConfigurationByResource.get(overrides.resource) || this._memoryConfiguration : this._memoryConfiguration; return objects.clone({ default: getConfigurationValue(overrides.overrideIdentifier ? this._defaults.override(overrides.overrideIdentifier).contents : this._defaults.contents, key), user: getConfigurationValue(overrides.overrideIdentifier ? this._user.override(overrides.overrideIdentifier).contents : this._user.contents, key), - workspace: this._workspace ? getConfigurationValue(overrides.overrideIdentifier ? this._workspaceConfiguration.override(overrides.overrideIdentifier).contents : this._workspaceConfiguration.contents, key) : void 0, //Check on workspace exists or not because _workspaceConfiguration is never null + workspace: workspace ? getConfigurationValue(overrides.overrideIdentifier ? this._workspaceConfiguration.override(overrides.overrideIdentifier).contents : this._workspaceConfiguration.contents, key) : void 0, //Check on workspace exists or not because _workspaceConfiguration is never null workspaceFolder: folderConfigurationModel ? getConfigurationValue(overrides.overrideIdentifier ? folderConfigurationModel.override(overrides.overrideIdentifier).contents : folderConfigurationModel.contents, key) : void 0, memory: getConfigurationValue(overrides.overrideIdentifier ? memoryConfigurationModel.override(overrides.overrideIdentifier).contents : memoryConfigurationModel.contents, key), value: getConfigurationValue(consolidateConfigurationModel.contents, key) }); } - keys(): { + keys(workspace: Workspace): { default: string[]; user: string[]; workspace: string[]; workspaceFolder: string[]; } { - const folderConfigurationModel = this.getFolderConfigurationModelForResource(); + const folderConfigurationModel = this.getFolderConfigurationModelForResource(null, workspace); return objects.clone({ default: this._defaults.keys, user: this._user.keys, @@ -386,13 +385,13 @@ export class Configuration { }); } - private getConsolidateConfigurationModel(overrides: IConfigurationOverrides): ConfigurationModel { - let configurationModel = this.getConsolidatedConfigurationModelForResource(overrides); + private getConsolidateConfigurationModel(overrides: IConfigurationOverrides, workspace: Workspace): ConfigurationModel { + let configurationModel = this.getConsolidatedConfigurationModelForResource(overrides, workspace); return overrides.overrideIdentifier ? configurationModel.override(overrides.overrideIdentifier) : configurationModel; } - private getConsolidatedConfigurationModelForResource({ resource }: IConfigurationOverrides): ConfigurationModel { - if (!this._workspace) { + private getConsolidatedConfigurationModelForResource({ resource }: IConfigurationOverrides, workspace: Workspace): ConfigurationModel { + if (!workspace) { return this._globalConfiguration; } @@ -401,7 +400,7 @@ export class Configuration { } let consolidateConfiguration = this._workspaceConsolidatedConfiguration; - const root = this._workspace.getFolder(resource); + const root = workspace.getFolder(resource); if (root) { consolidateConfiguration = this._foldersConsolidatedConfigurations.get(root.uri) || this._workspaceConsolidatedConfiguration; } @@ -414,12 +413,12 @@ export class Configuration { return consolidateConfiguration; } - private getFolderConfigurationModelForResource(resource?: URI): ConfigurationModel { - if (!this._workspace || !resource) { + private getFolderConfigurationModelForResource(resource: URI, workspace: Workspace): ConfigurationModel { + if (!workspace || !resource) { return null; } - const root = this._workspace.getFolder(resource); + const root = workspace.getFolder(resource); return root ? this.folders.get(root.uri) : null; } @@ -448,7 +447,7 @@ export class Configuration { }; } - public static parse(data: IConfigurationData, workspace: Workspace): Configuration { + public static parse(data: IConfigurationData): Configuration { const defaultConfiguration = Configuration.parseConfigurationModel(data.defaults); const userConfiguration = Configuration.parseConfigurationModel(data.user); const workspaceConfiguration = Configuration.parseConfigurationModel(data.workspace); @@ -456,7 +455,7 @@ export class Configuration { result.set(URI.parse(key), Configuration.parseConfigurationModel(data.folders[key])); return result; }, new StrictResourceMap()); - return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration, folders, new ConfigurationModel(), new StrictResourceMap(), workspace); + return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration, folders, new ConfigurationModel(), new StrictResourceMap()); } private static parseConfigurationModel(model: IConfigurationModel): ConfigurationModel { @@ -483,7 +482,7 @@ export class AbstractConfigurationChangeEvent { protected updateKeys(configuration: ConfigurationModel, keys: string[], resource?: URI): void { for (const key of keys) { - configuration.setValue(key, true); + configuration.setValue(key, {}); } } } diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index 9fb8cfc6fa6..43ad33bce80 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -62,12 +62,12 @@ export class ConfigurationService extends Disposable implements IConfigurationSe getConfiguration(section: string, overrides: IConfigurationOverrides): T getConfiguration(arg1?: any, arg2?: any): any { const section = typeof arg1 === 'string' ? arg1 : void 0; - const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0; - return this.configuration.getSection(section, overrides); + const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : {}; + return this.configuration.getSection(section, overrides, null); } - getValue(key: string, overrides: IConfigurationOverrides): any { - return this.configuration.getValue(key, overrides); + getValue(key: string, overrides: IConfigurationOverrides = {}): any { + return this.configuration.getValue(key, overrides, null); } updateValue(key: string, value: any): TPromise @@ -85,7 +85,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe workspaceFolder: T value: T } { - return this.configuration.lookup(key); + return this.configuration.lookup(key, {}, null); } keys(): { @@ -94,7 +94,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe workspace: string[]; workspaceFolder: string[]; } { - return this.configuration.keys(); + return this.configuration.keys(null); } reloadConfiguration(folder?: IWorkspaceFolder): TPromise { @@ -109,7 +109,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe if (changedKeys.length) { const oldConfiguartion = this._configuration; this.reset(); - changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key), this._configuration.getValue(key))); + changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key, {}, null), this._configuration.getValue(key, {}, null))); if (changedKeys.length) { this.trigger(changedKeys, ConfigurationTarget.USER); } diff --git a/src/vs/platform/configuration/test/common/configurationModels.test.ts b/src/vs/platform/configuration/test/common/configurationModels.test.ts index eadf6dd928e..0bf2c7ea154 100644 --- a/src/vs/platform/configuration/test/common/configurationModels.test.ts +++ b/src/vs/platform/configuration/test/common/configurationModels.test.ts @@ -415,6 +415,17 @@ suite('ConfigurationChangeEvent', () => { assert.ok(testObject.affectsConfiguration('[markdown]')); }); + test('changeEvent affecting a root key and its children', () => { + let testObject = new ConfigurationChangeEvent(); + + testObject.change(['launch', 'launch.version', 'tasks']); + + assert.deepEqual(testObject.affectedKeys, ['launch.version', 'tasks']); + assert.ok(testObject.affectsConfiguration('launch')); + assert.ok(testObject.affectsConfiguration('launch.version')); + assert.ok(testObject.affectsConfiguration('tasks')); + }); + test('changeEvent affecting keys for resources', () => { let testObject = new ConfigurationChangeEvent(); diff --git a/src/vs/platform/extensionManagement/common/extensionEnablementService.ts b/src/vs/platform/extensionManagement/common/extensionEnablementService.ts index 65348d5095c..9d5bc924570 100644 --- a/src/vs/platform/extensionManagement/common/extensionEnablementService.ts +++ b/src/vs/platform/extensionManagement/common/extensionEnablementService.ts @@ -5,16 +5,16 @@ import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { distinct } from 'vs/base/common/arrays'; +import { distinct, coalesce } from 'vs/base/common/arrays'; import Event, { Emitter } from 'vs/base/common/event'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { adoptToGalleryExtensionId, getIdAndVersionFromLocalExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { adoptToGalleryExtensionId, getIdAndVersionFromLocalExtensionId, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensions/disabled'; +const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/disabled'; export class ExtensionEnablementService implements IExtensionEnablementService { @@ -22,8 +22,8 @@ export class ExtensionEnablementService implements IExtensionEnablementService { private disposables: IDisposable[] = []; - private _onEnablementChanged = new Emitter(); - public onEnablementChanged: Event = this._onEnablementChanged.event; + private _onEnablementChanged = new Emitter(); + public onEnablementChanged: Event = this._onEnablementChanged.event; constructor( @IStorageService private storageService: IStorageService, @@ -38,28 +38,28 @@ export class ExtensionEnablementService implements IExtensionEnablementService { return this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY; } - public getGloballyDisabledExtensions(): string[] { + getGloballyDisabledExtensions(): IExtensionIdentifier[] { return this.getDisabledExtensions(StorageScope.GLOBAL); } - public getWorkspaceDisabledExtensions(): string[] { + getWorkspaceDisabledExtensions(): IExtensionIdentifier[] { return this.getDisabledExtensions(StorageScope.WORKSPACE); } - public canEnable(identifier: string): boolean { + canEnable(identifier: IExtensionIdentifier): boolean { if (this.environmentService.disableExtensions) { return false; } - if (this.getGloballyDisabledExtensions().indexOf(identifier) !== -1) { + if (this.getGloballyDisabledExtensions().some(d => areSameExtensions(d, identifier))) { return true; } - if (this.getWorkspaceDisabledExtensions().indexOf(identifier) !== -1) { + if (this.getWorkspaceDisabledExtensions().some(d => areSameExtensions(d, identifier))) { return true; } return false; } - public setEnablement(identifier: string, enable: boolean, workspace: boolean = false): TPromise { + setEnablement(identifier: IExtensionIdentifier, enable: boolean, workspace: boolean = false): TPromise { if (workspace && !this.hasWorkspace) { return TPromise.wrapError(new Error(localize('noWorkspace', "No workspace."))); } @@ -83,10 +83,16 @@ export class ExtensionEnablementService implements IExtensionEnablementService { } } - private disableExtension(identifier: string, scope: StorageScope): TPromise { + migrateToIdentifiers(installed: IExtensionIdentifier[]): void { + this.migrateDisabledExtensions(installed, StorageScope.GLOBAL); + if (this.hasWorkspace) { + this.migrateDisabledExtensions(installed, StorageScope.WORKSPACE); + } + } + + private disableExtension(identifier: IExtensionIdentifier, scope: StorageScope): TPromise { let disabledExtensions = this.getDisabledExtensions(scope); - const index = disabledExtensions.indexOf(identifier); - if (index === -1) { + if (disabledExtensions.every(e => !areSameExtensions(e, identifier))) { disabledExtensions.push(identifier); this.setDisabledExtensions(disabledExtensions, scope, identifier); return TPromise.wrap(true); @@ -94,28 +100,30 @@ export class ExtensionEnablementService implements IExtensionEnablementService { return TPromise.wrap(false); } - private enableExtension(identifier: string, scope: StorageScope, fireEvent = true): TPromise { + private enableExtension(identifier: IExtensionIdentifier, scope: StorageScope, fireEvent = true): TPromise { let disabledExtensions = this.getDisabledExtensions(scope); - const index = disabledExtensions.indexOf(identifier); - if (index !== -1) { - disabledExtensions.splice(index, 1); - this.setDisabledExtensions(disabledExtensions, scope, identifier, fireEvent); - return TPromise.wrap(true); + for (let index = 0; index < disabledExtensions.length; index++) { + const disabledExtension = disabledExtensions[index]; + if (areSameExtensions(disabledExtension, identifier)) { + disabledExtensions.splice(index, 1); + this.setDisabledExtensions(disabledExtensions, scope, identifier, fireEvent); + return TPromise.wrap(true); + } } return TPromise.wrap(false); } - private getDisabledExtensions(scope: StorageScope): string[] { + private getDisabledExtensions(scope: StorageScope): IExtensionIdentifier[] { if (scope === StorageScope.WORKSPACE && !this.hasWorkspace) { return []; } const value = this.storageService.get(DISABLED_EXTENSIONS_STORAGE_PATH, scope, ''); - return value ? distinct(value.split(',')).map(id => adoptToGalleryExtensionId(id)) : []; + return value ? JSON.parse(value) : []; } - private setDisabledExtensions(disabledExtensions: string[], scope: StorageScope, extension: string, fireEvent = true): void { + private setDisabledExtensions(disabledExtensions: IExtensionIdentifier[], scope: StorageScope, extension: IExtensionIdentifier, fireEvent = true): void { if (disabledExtensions.length) { - this.storageService.store(DISABLED_EXTENSIONS_STORAGE_PATH, disabledExtensions.join(','), scope); + this.storageService.store(DISABLED_EXTENSIONS_STORAGE_PATH, JSON.stringify(disabledExtensions.map(({ id, uuid }) => ({ id, uuid }))), scope); } else { this.storageService.remove(DISABLED_EXTENSIONS_STORAGE_PATH, scope); } @@ -124,12 +132,28 @@ export class ExtensionEnablementService implements IExtensionEnablementService { } } - private onDidUninstallExtension({ id, error }: DidUninstallExtensionEvent): void { + private migrateDisabledExtensions(installedExtensions: IExtensionIdentifier[], scope: StorageScope): void { + const oldValue = this.storageService.get('extensions/disabled', scope, ''); + if (oldValue) { + const extensionIdentifiers = coalesce(distinct(oldValue.split(',')).map(id => { + id = adoptToGalleryExtensionId(id); + const matched = installedExtensions.filter(installed => areSameExtensions({ id }, { id: installed.id }))[0]; + return matched ? { id: matched.id, uuid: matched.uuid } : null; + })); + if (extensionIdentifiers.length) { + this.storageService.store(DISABLED_EXTENSIONS_STORAGE_PATH, JSON.stringify(extensionIdentifiers), scope); + } + } + this.storageService.remove('extensions/disabled', scope); + } + + private onDidUninstallExtension({ identifier, error }: DidUninstallExtensionEvent): void { if (!error) { - id = getIdAndVersionFromLocalExtensionId(id).id; + const id = getIdAndVersionFromLocalExtensionId(identifier.id).id; if (id) { - this.enableExtension(id, StorageScope.WORKSPACE, false); - this.enableExtension(id, StorageScope.GLOBAL, false); + const extension = { id, uuid: identifier.uuid }; + this.enableExtension(extension, StorageScope.WORKSPACE, false); + this.enableExtension(extension, StorageScope.GLOBAL, false); } } } diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index aa16e8e0f05..ea125d6cda4 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -135,10 +135,14 @@ export interface IGalleryExtensionAssets { license: IGalleryExtensionAsset; } -export interface IGalleryExtension { - uuid: string; +export interface IExtensionIdentifier { id: string; + uuid?: string; +} + +export interface IGalleryExtension { name: string; + identifier: IExtensionIdentifier; version: string; date: string; displayName: string; @@ -167,7 +171,7 @@ export enum LocalExtensionType { export interface ILocalExtension { type: LocalExtensionType; - id: string; + identifier: IExtensionIdentifier; manifest: IExtensionManifest; metadata: IGalleryMetadata; path: string; @@ -217,19 +221,19 @@ export interface IExtensionGalleryService { reportStatistic(publisher: string, name: string, version: string, type: StatisticType): TPromise; getReadme(extension: IGalleryExtension): TPromise; getManifest(extension: IGalleryExtension): TPromise; - getChangelog(extension: IGalleryMetadata): TPromise; + getChangelog(extension: IGalleryExtension): TPromise; loadCompatibleVersion(extension: IGalleryExtension): TPromise; getAllDependencies(extension: IGalleryExtension): TPromise; } export interface InstallExtensionEvent { - id: string; + identifier: IExtensionIdentifier; zipPath?: string; gallery?: IGalleryExtension; } export interface DidInstallExtensionEvent { - id: string; + identifier: IExtensionIdentifier; zipPath?: string; gallery?: IGalleryExtension; local?: ILocalExtension; @@ -237,7 +241,7 @@ export interface DidInstallExtensionEvent { } export interface DidUninstallExtensionEvent { - id: string; + identifier: IExtensionIdentifier; error?: string; } @@ -246,7 +250,7 @@ export interface IExtensionManagementService { onInstallExtension: Event; onDidInstallExtension: Event; - onUninstallExtension: Event; + onUninstallExtension: Event; onDidUninstallExtension: Event; install(zipPath: string): TPromise; @@ -264,24 +268,24 @@ export interface IExtensionEnablementService { /** * Event to listen on for extension enablement changes */ - onEnablementChanged: Event; + onEnablementChanged: Event; /** * Returns all globally disabled extension identifiers. * Returns an empty array if none exist. */ - getGloballyDisabledExtensions(): string[]; + getGloballyDisabledExtensions(): IExtensionIdentifier[]; /** * Returns all workspace disabled extension identifiers. * Returns an empty array if none exist or workspace does not exist. */ - getWorkspaceDisabledExtensions(): string[]; + getWorkspaceDisabledExtensions(): IExtensionIdentifier[]; /** * Returns `true` if given extension can be enabled by calling `setEnablement`, otherwise false`. */ - canEnable(identifier: string): boolean; + canEnable(identifier: IExtensionIdentifier): boolean; /** * Enable or disable the given extension. @@ -292,14 +296,18 @@ export interface IExtensionEnablementService { * * Throws error if enablement is requested for workspace and there is no workspace */ - setEnablement(identifier: string, enable: boolean, workspace?: boolean): TPromise; + setEnablement(identifier: IExtensionIdentifier, enable: boolean, workspace?: boolean): TPromise; + + migrateToIdentifiers(installed: IExtensionIdentifier[]): void; } export const IExtensionTipsService = createDecorator('extensionTipsService'); export interface IExtensionTipsService { _serviceBrand: any; - getRecommendations(installedExtensions: string[], searchText: string): string[]; + getAllRecommendationsWithReason(): { [id: string]: string; }; + getFileBasedRecommendations(): string[]; + getOtherRecommendations(): string[]; getWorkspaceRecommendations(): TPromise; getKeymapRecommendations(): string[]; getKeywordsForExtension(extension: string): string[]; diff --git a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts index d0acbb80340..5f5a8c39e74 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 } from './extensionManagement'; +import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, LocalExtensionType, DidUninstallExtensionEvent, IExtensionIdentifier } from './extensionManagement'; import Event, { buffer } from 'vs/base/common/event'; export interface IExtensionManagementChannel extends IChannel { @@ -26,7 +26,7 @@ export class ExtensionManagementChannel implements IExtensionManagementChannel { onInstallExtension: Event; onDidInstallExtension: Event; - onUninstallExtension: Event; + onUninstallExtension: Event; onDidUninstallExtension: Event; constructor(private service: IExtensionManagementService) { @@ -63,8 +63,8 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer private _onDidInstallExtension = eventFromCall(this.channel, 'event:onDidInstallExtension'); get onDidInstallExtension(): Event { return this._onDidInstallExtension; } - private _onUninstallExtension = eventFromCall(this.channel, 'event:onUninstallExtension'); - get onUninstallExtension(): Event { return this._onUninstallExtension; } + private _onUninstallExtension = eventFromCall(this.channel, 'event:onUninstallExtension'); + get onUninstallExtension(): Event { return this._onUninstallExtension; } private _onDidUninstallExtension = eventFromCall(this.channel, 'event:onDidUninstallExtension'); get onDidUninstallExtension(): Event { return this._onDidUninstallExtension; } diff --git a/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts index f8684f13156..23945ed58fb 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts @@ -5,10 +5,13 @@ 'use strict'; -import { ILocalExtension, IGalleryExtension, IExtensionManifest, EXTENSION_IDENTIFIER_REGEX, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ILocalExtension, IGalleryExtension, EXTENSION_IDENTIFIER_REGEX, IExtensionEnablementService, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -export function areSameExtensions(a: { id: string }, b: { id: string }): boolean { +export function areSameExtensions(a: IExtensionIdentifier, b: IExtensionIdentifier): boolean { + if (a.uuid && b.uuid) { + return a.uuid === b.uuid; + } if (a.id === b.id) { return true; } @@ -19,14 +22,6 @@ export function getGalleryExtensionId(publisher: string, name: string): string { return `${publisher}.${name.toLocaleLowerCase()}`; } -export function getLocalExtensionIdFromGallery(extension: IGalleryExtension, version: string): string { - return getLocalExtensionId(extension.id, version); -} - -export function getLocalExtensionIdFromManifest(manifest: IExtensionManifest): string { - return getLocalExtensionId(getGalleryExtensionId(manifest.publisher, manifest.name), manifest.version); -} - export function getGalleryExtensionIdFromLocal(local: ILocalExtension): string { return getGalleryExtensionId(local.manifest.publisher, local.manifest.name); } @@ -46,10 +41,6 @@ export function adoptToGalleryExtensionId(id: string): string { return id.replace(EXTENSION_IDENTIFIER_REGEX, (match, publisher: string, name: string) => getGalleryExtensionId(publisher, name)); } -function getLocalExtensionId(id: string, version: string): string { - return `${id}-${version}`; -} - export function getLocalExtensionTelemetryData(extension: ILocalExtension): any { return { id: getGalleryExtensionIdFromLocal(extension), @@ -79,9 +70,9 @@ export function getLocalExtensionTelemetryData(extension: ILocalExtension): any */ export function getGalleryExtensionTelemetryData(extension: IGalleryExtension): any { return { - id: extension.id, + id: extension.identifier.id, name: extension.name, - galleryId: extension.uuid, + galleryId: extension.identifier.uuid, publisherId: extension.publisherId, publisherName: extension.publisher, publisherDisplayName: extension.publisherDisplayName, @@ -102,9 +93,9 @@ export function getGloballyDisabledExtensions(extensionEnablementService: IExten const globallyDisabled = extensionEnablementService.getGloballyDisabledExtensions(); if (!storageService.getBoolean(BetterMergeCheckKey, StorageScope.GLOBAL, false)) { storageService.store(BetterMergeCheckKey, true); - if (globallyDisabled.indexOf(BetterMergeId) === -1 && installedExtensions.some(d => d.id === BetterMergeId)) { - globallyDisabled.push(BetterMergeId); - extensionEnablementService.setEnablement(BetterMergeId, false); + if (globallyDisabled.every(disabled => disabled.id !== BetterMergeId) && installedExtensions.some(d => d.id === BetterMergeId)) { + globallyDisabled.push({ id: BetterMergeId }); + extensionEnablementService.setEnablement({ id: BetterMergeId }, false); storageService.store(BetterMergeDisabledNowKey, true); } } diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index 4453efbc64d..f6e62fd8592 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -245,8 +245,10 @@ function toExtension(galleryExtension: IRawGalleryExtension, extensionsGalleryUr }; return { - uuid: galleryExtension.extensionId, - id: getGalleryExtensionId(galleryExtension.publisher.publisherName, galleryExtension.extensionName), + identifier: { + id: getGalleryExtensionId(galleryExtension.publisher.publisherName, galleryExtension.extensionName), + uuid: galleryExtension.extensionId + }, name: galleryExtension.extensionName, version: version.version, date: version.lastUpdated, @@ -488,7 +490,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { .withFilter(FilterType.Target, 'Microsoft.VisualStudio.Code') .withFilter(FilterType.ExcludeWithFlags, flagsToString(Flags.Unpublished)) .withAssetTypes(AssetType.Manifest, AssetType.VSIX) - .withFilter(FilterType.ExtensionId, extension.uuid); + .withFilter(FilterType.ExtensionId, extension.identifier.uuid); return this.queryGallery(query).then(({ galleryExtensions }) => { const [rawExtension] = galleryExtensions; @@ -556,7 +558,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { dep.properties.dependencies.forEach(d => dependenciesSet.add(d)); } } - result = distinct(result.concat(loadedDependencies), d => d.uuid); + result = distinct(result.concat(loadedDependencies), d => d.identifier.uuid); const dependencies: string[] = []; dependenciesSet.forEach(d => !ExtensionGalleryService.hasExtensionByName(result, d) && dependencies.push(d)); return this.getDependenciesReccursively(dependencies, result, root); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 58c2a514205..ff9dd9a0016 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -18,9 +18,10 @@ import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IExtensionManifest, IGalleryMetadata, InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, LocalExtensionType, - StatisticType + StatisticType, + IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getLocalExtensionIdFromGallery, getLocalExtensionIdFromManifest, getGalleryExtensionIdFromLocal, getIdAndVersionFromLocalExtensionId, adoptToGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { getGalleryExtensionIdFromLocal, getIdAndVersionFromLocalExtensionId, adoptToGalleryExtensionId, areSameExtensions, getGalleryExtensionId } 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'; @@ -75,6 +76,7 @@ interface InstallableExtension { zipPath: string; id: string; metadata: IGalleryMetadata; + current?: ILocalExtension; } export class ExtensionManagementService implements IExtensionManagementService { @@ -92,8 +94,8 @@ export class ExtensionManagementService implements IExtensionManagementService { private _onDidInstallExtension = new Emitter(); onDidInstallExtension: Event = this._onDidInstallExtension.event; - private _onUninstallExtension = new Emitter(); - onUninstallExtension: Event = this._onUninstallExtension.event; + private _onUninstallExtension = new Emitter(); + onUninstallExtension: Event = this._onUninstallExtension.event; private _onDidUninstallExtension = new Emitter(); onDidUninstallExtension: Event = this._onDidUninstallExtension.event; @@ -112,19 +114,19 @@ export class ExtensionManagementService implements IExtensionManagementService { zipPath = path.resolve(zipPath); return validate(zipPath).then(manifest => { - const id = getLocalExtensionIdFromManifest(manifest); + const identifier = { id: getLocalExtensionIdFromManifest(manifest) }; - return this.isObsolete(id).then(isObsolete => { + return this.isObsolete(identifier.id).then(isObsolete => { if (isObsolete) { return TPromise.wrapError(new Error(nls.localize('restartCodeLocal', "Please restart Code before reinstalling {0}.", manifest.displayName || manifest.name))); } - this._onInstallExtension.fire({ id, zipPath }); + this._onInstallExtension.fire({ identifier, zipPath }); - return this.installExtension({ zipPath, id, metadata: null }) + return this.installExtension({ zipPath, id: identifier.id, metadata: null }) .then( - local => this._onDidInstallExtension.fire({ id, zipPath, local }), - error => { this._onDidInstallExtension.fire({ id, zipPath, error }); return TPromise.wrapError(error); } + local => this._onDidInstallExtension.fire({ identifier, zipPath, local }), + error => { this._onDidInstallExtension.fire({ identifier, zipPath, error }); return TPromise.wrapError(error); } ); }); }); @@ -155,11 +157,12 @@ export class ExtensionManagementService implements IExtensionManagementService { } private downloadAndInstallExtensions(extensions: IGalleryExtension[]): TPromise { - return TPromise.join(extensions.map(extensionToInstall => this.downloadInstallableExtension(extensionToInstall))) - .then( - installableExtensions => TPromise.join(installableExtensions.map(installableExtension => this.installExtension(installableExtension))) - .then(null, error => this.rollback(extensions).then(() => this.onDidInstallExtensions(extensions, null, INSTALL_ERROR_LOCAL, error))), - error => this.onDidInstallExtensions(extensions, null, INSTALL_ERROR_GALLERY, error)); + return this.getInstalled(LocalExtensionType.User) + .then(installed => TPromise.join(extensions.map(extensionToInstall => this.downloadInstallableExtension(extensionToInstall, installed))) + .then( + installableExtensions => TPromise.join(installableExtensions.map(installableExtension => this.installExtension(installableExtension))) + .then(null, error => this.rollback(extensions).then(() => this.onDidInstallExtensions(extensions, null, INSTALL_ERROR_LOCAL, error))), + error => this.onDidInstallExtensions(extensions, null, INSTALL_ERROR_GALLERY, error))); } private collectExtensionsToInstall(extension: IGalleryExtension): TPromise { @@ -174,37 +177,38 @@ export class ExtensionManagementService implements IExtensionManagementService { .then(obsolete => obsolete.length ? TPromise.wrapError(new Error(nls.localize('restartCodeGallery', "Please restart Code before reinstalling."))) : extensionsToInstall); } - private downloadInstallableExtension(extension: IGalleryExtension): TPromise { + private downloadInstallableExtension(extension: IGalleryExtension, installed: ILocalExtension[]): TPromise { + const current = installed.filter(i => i.identifier.uuid === extension.identifier.uuid)[0]; const id = getLocalExtensionIdFromGallery(extension, extension.version); const metadata = { - id: extension.uuid, + id: extension.identifier.uuid, publisherId: extension.publisherId, publisherDisplayName: extension.publisherDisplayName, }; return this.galleryService.download(extension) - .then(zipPath => validate(zipPath).then(() => ({ zipPath, id, metadata }))); + .then(zipPath => validate(zipPath).then(() => ({ zipPath, id, metadata, current }))); } private rollback(extensions: IGalleryExtension[]): TPromise { return this.filterOutUninstalled(extensions) - .then(installed => TPromise.join(installed.map(local => this.uninstallExtension(local.id)))) + .then(installed => TPromise.join(installed.map(local => this.uninstallExtension(local.identifier)))) .then(() => null, () => null); } private onInstallExtensions(extensions: IGalleryExtension[]): void { for (const extension of extensions) { const id = getLocalExtensionIdFromGallery(extension, extension.version); - this._onInstallExtension.fire({ id, gallery: extension }); + this._onInstallExtension.fire({ identifier: { id, uuid: extension.identifier.uuid }, gallery: extension }); } } private onDidInstallExtensions(extensions: IGalleryExtension[], local: ILocalExtension[], errorCode?: string, error?: any): TPromise { extensions.forEach((gallery, index) => { - const id = getLocalExtensionIdFromGallery(gallery, gallery.version); + const identifier = { id: getLocalExtensionIdFromGallery(gallery, gallery.version), uuid: gallery.identifier.uuid }; if (errorCode) { - this._onDidInstallExtension.fire({ id, gallery, error: errorCode }); + this._onDidInstallExtension.fire({ identifier, gallery, error: errorCode }); } else { - this._onDidInstallExtension.fire({ id, gallery, local: local[index] }); + this._onDidInstallExtension.fire({ identifier, gallery, local: local[index] }); } }); return error ? TPromise.wrapError(Array.isArray(error) ? this.joinErrors(error) : error) : TPromise.as(null); @@ -214,11 +218,11 @@ export class ExtensionManagementService implements IExtensionManagementService { return this.getInstalled() .then(local => { return dependencies.filter(d => { - if (extension.uuid === d.uuid) { + if (extension.identifier.uuid === d.identifier.uuid) { return false; } const extensionId = getLocalExtensionIdFromGallery(d, d.version); - return local.every(local => local.id !== extensionId); + return local.every(({ identifier }) => identifier.id !== extensionId); }); }); } @@ -229,11 +233,11 @@ export class ExtensionManagementService implements IExtensionManagementService { } private getGalleryExtensionForLocalExtension(galleryExtensions: IGalleryExtension[], localExtension: ILocalExtension): IGalleryExtension { - const filtered = galleryExtensions.filter(galleryExtension => getLocalExtensionIdFromGallery(galleryExtension, galleryExtension.version) === localExtension.id); + const filtered = galleryExtensions.filter(galleryExtension => areSameExtensions(localExtension.identifier, { id: getLocalExtensionIdFromGallery(galleryExtension, galleryExtension.version), uuid: galleryExtension.identifier.uuid })); return filtered.length ? filtered[0] : null; } - private installExtension({ zipPath, id, metadata }: InstallableExtension): TPromise { + private installExtension({ zipPath, id, metadata, current }: InstallableExtension): TPromise { const extensionPath = path.join(this.extensionsPath, id); return pfs.rimraf(extensionPath).then(() => { @@ -246,14 +250,16 @@ export class ExtensionManagementService implements IExtensionManagementService { const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; const changelogUrl = changelog ? URI.file(path.join(extensionPath, changelog)).toString() : null; const type = LocalExtensionType.User; + const identifier = { id, uuid: metadata ? metadata.id : null }; - const local: ILocalExtension = { type, id, manifest, metadata, path: extensionPath, readmeUrl, changelogUrl }; + const local: ILocalExtension = { type, identifier, manifest, metadata, path: extensionPath, readmeUrl, changelogUrl }; const manifestPath = path.join(extensionPath, 'package.json'); return pfs.readFile(manifestPath, 'utf8') .then(raw => parseManifest(raw)) .then(({ manifest }) => assign(manifest, { __metadata: metadata })) .then(manifest => pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t'))) + .then(() => this.checkForRename(current, local)) .then(() => local); }); }); @@ -273,6 +279,15 @@ export class ExtensionManagementService implements IExtensionManagementService { .then(() => { /* drop resolved value */ }); } + private checkForRename(currentExtension: ILocalExtension, newExtension: ILocalExtension): TPromise { + // Check if the gallery id for current and new exensions are same, if not, remove the current one. + if (currentExtension && getGalleryExtensionIdFromLocal(currentExtension) !== getGalleryExtensionIdFromLocal(newExtension)) { + // return this.uninstallExtension(currentExtension.identifier); + return this.setObsolete(currentExtension.identifier.id); + } + return TPromise.as(null); + } + private joinErrors(errors: (Error | string)[]): Error { if (errors.length === 1) { return errors[0] instanceof Error ? errors[0] : new Error(errors[0]); @@ -350,7 +365,7 @@ export class ExtensionManagementService implements IExtensionManagementService { if (dependents.length) { return TPromise.wrapError(new Error(this.getDependentsErrorMessage(extension, dependents))); } - return TPromise.join([this.uninstallExtension(extension.id), ...dependenciesToUninstall.map(d => this.doUninstall(d))]).then(() => null); + return TPromise.join([this.uninstallExtension(extension.identifier), ...dependenciesToUninstall.map(d => this.doUninstall(d))]).then(() => null); } private getDependentsErrorMessage(extension: ILocalExtension, dependents: ILocalExtension[]): string { @@ -401,7 +416,7 @@ export class ExtensionManagementService implements IExtensionManagementService { private doUninstall(extension: ILocalExtension): TPromise { return this.preUninstallExtension(extension) - .then(() => this.uninstallExtension(extension.id)) + .then(() => this.uninstallExtension(extension.identifier)) .then(() => this.postUninstallExtension(extension), error => { this.postUninstallExtension(extension, INSTALL_ERROR_LOCAL); @@ -410,13 +425,13 @@ export class ExtensionManagementService implements IExtensionManagementService { } private preUninstallExtension(extension: ILocalExtension): TPromise { - const extensionPath = path.join(this.extensionsPath, extension.id); + const extensionPath = path.join(this.extensionsPath, extension.identifier.id); return pfs.exists(extensionPath) .then(exists => exists ? null : TPromise.wrapError(new Error(nls.localize('notExists', "Could not find extension")))) - .then(() => this._onUninstallExtension.fire(extension.id)); + .then(() => this._onUninstallExtension.fire(extension.identifier)); } - private uninstallExtension(id: string): TPromise { + private uninstallExtension({ id }: IExtensionIdentifier): TPromise { const extensionPath = path.join(this.extensionsPath, id); return this.setObsolete(id) .then(() => pfs.rimraf(extensionPath)) @@ -428,7 +443,7 @@ export class ExtensionManagementService implements IExtensionManagementService { await this.galleryService.reportStatistic(extension.manifest.publisher, extension.manifest.name, extension.manifest.version, StatisticType.Uninstall); } - this._onDidUninstallExtension.fire({ id: extension.id, error }); + this._onDidUninstallExtension.fire({ identifier: extension.identifier, error }); } getInstalled(type: LocalExtensionType = null): TPromise { @@ -474,7 +489,8 @@ export class ExtensionManagementService implements IExtensionManagementService { if (manifest.extensionDependencies) { manifest.extensionDependencies = manifest.extensionDependencies.map(id => adoptToGalleryExtensionId(id)); } - return { type, id, manifest, metadata, path: extensionPath, readmeUrl, changelogUrl }; + const identifier = { id, uuid: metadata ? metadata.id : null }; + return { type, identifier, manifest, metadata, path: extensionPath, readmeUrl, changelogUrl }; }); }).then(null, () => null); @@ -578,3 +594,15 @@ export class ExtensionManagementService implements IExtensionManagementService { this.disposables = dispose(this.disposables); } } + +export function getLocalExtensionIdFromGallery(extension: IGalleryExtension, version: string): string { + return getLocalExtensionId(extension.identifier.id, version); +} + +export function getLocalExtensionIdFromManifest(manifest: IExtensionManifest): string { + return getLocalExtensionId(getGalleryExtensionId(manifest.publisher, manifest.name), manifest.version); +} + +function getLocalExtensionId(id: string, version: string): string { + return `${id}-${version}`; +} \ No newline at end of file diff --git a/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts b/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts index e35a98d864c..bcc48a92232 100644 --- a/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts +++ b/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts @@ -69,7 +69,7 @@ suite('ExtensionEnablementService Test', () => { }); test('test when no extensions are disabled for workspace when there is no workspace', (done) => { - testObject.setEnablement('pub.a', false, true) + testObject.setEnablement({ id: 'pub.a' }, false, true) .then(() => { instantiationService.stub(IWorkspaceContextService, 'getWorkbenchState', WorkbenchState.EMPTY); assert.deepEqual([], testObject.getWorkspaceDisabledExtensions()); @@ -78,13 +78,13 @@ suite('ExtensionEnablementService Test', () => { }); test('test disable an extension globally', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions())) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => assert.deepEqual([{ id: 'pub.a' }], testObject.getGloballyDisabledExtensions())) .then(done, done); }); test('test disable an extension globally should return truthy promise', (done) => { - testObject.setEnablement('pub.a', false) + testObject.setEnablement({ id: 'pub.a' }, false) .then(value => assert.ok(value)) .then(done, done); }); @@ -92,180 +92,180 @@ suite('ExtensionEnablementService Test', () => { test('test disable an extension globally triggers the change event', (done) => { const target = sinon.spy(); testObject.onEnablementChanged(target); - testObject.setEnablement('pub.a', false) - .then(() => assert.ok(target.calledWithExactly('pub.a'))) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.a' }))) .then(done, done); }); test('test disable an extension globally again should return a falsy promise', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', false)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) .then(value => assert.ok(!value)) .then(done, done); }); test('test disable an extension for workspace', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions())) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => assert.deepEqual([{ id: 'pub.a' }], testObject.getWorkspaceDisabledExtensions())) .then(done, done); }); test('test disable an extension for workspace returns a truthy promise', (done) => { - testObject.setEnablement('pub.a', false, true) + testObject.setEnablement({ id: 'pub.a' }, false, true) .then(value => assert.ok(value)) .then(done, done); }); test('test disable an extension for workspace again should return a falsy promise', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false, true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false, true)) .then(value => assert.ok(!value)) .then(done, done); }); test('test disable an extension for workspace and then globally', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) .then(() => { - assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions()); - assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getWorkspaceDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getGloballyDisabledExtensions()); }) .then(done, done); }); test('test disable an extension for workspace and then globally return a truthy promise', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) .then(value => assert.ok(value)) .then(done, done); }); test('test disable an extension for workspace and then globally triggers the change event', (done) => { const target = sinon.spy(); - testObject.setEnablement('pub.a', false, true) + testObject.setEnablement({ id: 'pub.a' }, false, true) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement('pub.a', false)) - .then(() => assert.ok(target.calledWithExactly('pub.a'))) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.a' }))) .then(done, done); }); test('test disable an extension globally and then for workspace', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', false, true)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false, true)) .then(() => { - assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions()); - assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getWorkspaceDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getGloballyDisabledExtensions()); }) .then(done, done); }); test('test disable an extension globally and then for workspace return a truthy promise', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', false, true)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false, true)) .then(value => assert.ok(value)) .then(done, done); }); test('test disable an extension globally and then for workspace triggers the change event', (done) => { const target = sinon.spy(); - testObject.setEnablement('pub.a', false) + testObject.setEnablement({ id: 'pub.a' }, false) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement('pub.a', false, true)) - .then(() => assert.ok(target.calledWithExactly('pub.a'))) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false, true)) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.a' }))) .then(done, done); }); test('test disable an extension for workspace when there is no workspace throws error', (done) => { instantiationService.stub(IWorkspaceContextService, 'getWorkbenchState', WorkbenchState.EMPTY); - testObject.setEnablement('pub.a', false, true) + testObject.setEnablement({ id: 'pub.a' }, false, true) .then(() => assert.fail('should throw an error'), error => assert.ok(error)) .then(done, done); }); test('test enable an extension globally', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', true)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true)) .then(() => assert.deepEqual([], testObject.getGloballyDisabledExtensions())) .then(done, done); }); test('test enable an extension globally return truthy promise', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', true)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true)) .then(value => assert.ok(value)) .then(done, done); }); test('test enable an extension globally triggers change event', (done) => { const target = sinon.spy(); - testObject.setEnablement('pub.a', false) + testObject.setEnablement({ id: 'pub.a' }, false) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement('pub.a', true)) - .then(() => assert.ok(target.calledWithExactly('pub.a'))) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true)) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.a' }))) .then(done, done); }); test('test enable an extension globally when already enabled return falsy promise', (done) => { - testObject.setEnablement('pub.a', true) + testObject.setEnablement({ id: 'pub.a' }, true) .then(value => assert.ok(!value)) .then(done, done); }); test('test enable an extension for workspace', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', true, true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true, true)) .then(() => assert.deepEqual([], testObject.getWorkspaceDisabledExtensions())) .then(done, done); }); test('test enable an extension for workspace return truthy promise', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', true, true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true, true)) .then(value => assert.ok(value)) .then(done, done); }); test('test enable an extension for workspace triggers change event', (done) => { const target = sinon.spy(); - testObject.setEnablement('pub.b', false, true) + testObject.setEnablement({ id: 'pub.b' }, false, true) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement('pub.b', true, true)) - .then(() => assert.ok(target.calledWithExactly('pub.b'))) + .then(() => testObject.setEnablement({ id: 'pub.b' }, true, true)) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.b' }))) .then(done, done); }); test('test enable an extension for workspace when already enabled return falsy promise', (done) => { - testObject.setEnablement('pub.a', true, true) + testObject.setEnablement({ id: 'pub.a' }, true, true) .then(value => assert.ok(!value)) .then(done, done); }); test('test enable an extension for workspace when disabled in workspace and gloablly', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) - .then(() => testObject.setEnablement('pub.a', true, true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true, true)) .then(() => { - assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getGloballyDisabledExtensions()); assert.deepEqual([], testObject.getWorkspaceDisabledExtensions()); }) .then(done, done); }); test('test enable an extension globally when disabled in workspace and gloablly', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) - .then(() => testObject.setEnablement('pub.a', true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true)) .then(() => { - assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getWorkspaceDisabledExtensions()); assert.deepEqual([], testObject.getGloballyDisabledExtensions()); }) .then(done, done); }); test('test remove an extension from disablement list when uninstalled', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) - .then(() => didUninstallEvent.fire({ id: 'pub.a-1.0.0' })) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) + .then(() => didUninstallEvent.fire({ identifier: { id: 'pub.a-1.0.0' } })) .then(() => { assert.deepEqual([], testObject.getWorkspaceDisabledExtensions()); assert.deepEqual([], testObject.getGloballyDisabledExtensions()); diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index d8f1a0c5c82..b125ab5eff1 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -12,6 +12,7 @@ import { IExtensionPoint } from 'vs/platform/extensions/common/extensionsRegistr export interface IExtensionDescription { readonly id: string; readonly name: string; + readonly uuid?: string; readonly displayName?: string; readonly version: string; readonly publisher: string; diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index abd11cd556a..543bc5045f3 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -588,6 +588,9 @@ export const HotExitConfiguration = { export const CONTENT_CHANGE_EVENT_BUFFER_DELAY = 1000; +export const FILES_ASSOCIATIONS_CONFIG = 'files.associations'; +export const FILES_EXCLUDE_CONFIG = 'files.exclude'; + export interface IFilesConfiguration { files: { associations: { [filepattern: string]: string }; diff --git a/src/vs/platform/opener/browser/openerService.ts b/src/vs/platform/opener/browser/openerService.ts index 81ce6669386..940eea38958 100644 --- a/src/vs/platform/opener/browser/openerService.ts +++ b/src/vs/platform/opener/browser/openerService.ts @@ -5,6 +5,7 @@ 'use strict'; import URI from 'vs/base/common/uri'; +import * as dom from 'vs/base/browser/dom'; import { parse } from 'vs/base/common/marshalling'; import { Schemas } from 'vs/base/common/network'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -39,10 +40,10 @@ export class OpenerService implements IOpenerService { const { scheme, path, query, fragment } = resource; let promise: TPromise; - if (scheme === Schemas.http || scheme === Schemas.https) { - // open http - window.open(resource.toString(true)); + if (scheme === Schemas.http || scheme === Schemas.https || scheme === Schemas.mailto) { + // open http or default mail application + dom.windowOpenNoOpener(resource.toString(true)); } else if (scheme === 'command' && CommandsRegistry.getCommand(path)) { // execute as command let args: any = []; diff --git a/src/vs/platform/search/common/search.ts b/src/vs/platform/search/common/search.ts index bdd1918a876..1abcff42a87 100644 --- a/src/vs/platform/search/common/search.ts +++ b/src/vs/platform/search/common/search.ts @@ -55,6 +55,7 @@ export interface ICommonQueryOptions { useRipgrep?: boolean; disregardIgnoreFiles?: boolean; disregardExcludeSettings?: boolean; + ignoreSymlinks?: boolean; } export interface IQueryOptions extends ICommonQueryOptions { @@ -173,6 +174,7 @@ export interface ISearchConfiguration extends IFilesConfiguration { exclude: glob.IExpression; useRipgrep: boolean; useIgnoreFilesByDefault: boolean; + followSymlinks: boolean; }; editor: { wordSeparators: string; diff --git a/src/vs/platform/url/electron-main/urlService.ts b/src/vs/platform/url/electron-main/urlService.ts index 01e4a8895a2..2a7f2904df8 100644 --- a/src/vs/platform/url/electron-main/urlService.ts +++ b/src/vs/platform/url/electron-main/urlService.ts @@ -5,7 +5,7 @@ 'use strict'; -import Event, { mapEvent, chain, echo, Emitter, any } from 'vs/base/common/event'; +import Event, { mapEvent, chain, echo, Emitter, anyEvent } from 'vs/base/common/event'; import { fromEventEmitter } from 'vs/base/node/event'; import { IURLService } from 'vs/platform/url/common/url'; import product from 'vs/platform/node/product'; @@ -39,7 +39,7 @@ export class URLService implements IURLService { // echo all `onOpenUrl` events to each listener const bufferedOnOpenUrl = echo(preventedOnOpenUrl, true, initialBuffer); - this.onOpenURL = chain(any(bufferedOnOpenUrl, this.openUrlEmitter.event)) + this.onOpenURL = chain(anyEvent(bufferedOnOpenUrl, this.openUrlEmitter.event)) .map(url => { try { return URI.parse(url); @@ -54,4 +54,4 @@ export class URLService implements IURLService { open(url: string): void { this.openUrlEmitter.fire(url); } -} \ No newline at end of file +} diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index 5f6c19c1d55..632dccaee33 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -43,11 +43,11 @@ export interface IWindowsService { pickFileFolderAndOpen(options: INativeOpenDialogOptions): TPromise; pickFileAndOpen(options: INativeOpenDialogOptions): TPromise; pickFolderAndOpen(options: INativeOpenDialogOptions): TPromise; + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise; reloadWindow(windowId: number): TPromise; openDevTools(windowId: number): TPromise; toggleDevTools(windowId: number): TPromise; closeWorkspace(windowId: number): TPromise; - openWorkspace(windowId: number): TPromise; createAndEnterWorkspace(windowId: number, folderPaths?: string[], path?: string): TPromise; saveAndEnterWorkspace(windowId: number, path: string): TPromise; toggleFullScreen(windowId: number): TPromise; @@ -115,11 +115,11 @@ export interface IWindowService { pickFileFolderAndOpen(options: INativeOpenDialogOptions): TPromise; pickFileAndOpen(options: INativeOpenDialogOptions): TPromise; pickFolderAndOpen(options: INativeOpenDialogOptions): TPromise; + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise; reloadWindow(): TPromise; openDevTools(): TPromise; toggleDevTools(): TPromise; closeWorkspace(): TPromise; - openWorkspace(): TPromise; updateTouchBar(items: ICommandAction[][]): TPromise; createAndEnterWorkspace(folderPaths?: string[], path?: string): TPromise; saveAndEnterWorkspace(path: string): TPromise; diff --git a/src/vs/platform/windows/common/windowsIpc.ts b/src/vs/platform/windows/common/windowsIpc.ts index 237fadf835f..10a3e7eabbf 100644 --- a/src/vs/platform/windows/common/windowsIpc.ts +++ b/src/vs/platform/windows/common/windowsIpc.ts @@ -20,10 +20,10 @@ export interface IWindowsChannel extends IChannel { call(command: 'pickFileFolderAndOpen', arg: INativeOpenDialogOptions): TPromise; call(command: 'pickFileAndOpen', arg: INativeOpenDialogOptions): TPromise; call(command: 'pickFolderAndOpen', arg: INativeOpenDialogOptions): TPromise; + call(command: 'pickWorkspaceAndOpen', arg: INativeOpenDialogOptions): TPromise; call(command: 'reloadWindow', arg: number): TPromise; call(command: 'toggleDevTools', arg: number): TPromise; call(command: 'closeWorkspace', arg: number): TPromise; - call(command: 'openWorkspace', arg: number): TPromise; call(command: 'createAndEnterWorkspace', arg: [number, string[], string]): TPromise; call(command: 'saveAndEnterWorkspace', arg: [number, string]): TPromise; call(command: 'toggleFullScreen', arg: number): TPromise; @@ -82,11 +82,11 @@ export class WindowsChannel implements IWindowsChannel { case 'pickFileFolderAndOpen': return this.service.pickFileFolderAndOpen(arg); case 'pickFileAndOpen': return this.service.pickFileAndOpen(arg); case 'pickFolderAndOpen': return this.service.pickFolderAndOpen(arg); + case 'pickWorkspaceAndOpen': return this.service.pickWorkspaceAndOpen(arg); case 'reloadWindow': return this.service.reloadWindow(arg); case 'openDevTools': return this.service.openDevTools(arg); case 'toggleDevTools': return this.service.toggleDevTools(arg); case 'closeWorkspace': return this.service.closeWorkspace(arg); - case 'openWorkspace': return this.service.openWorkspace(arg); case 'createAndEnterWorkspace': return this.service.createAndEnterWorkspace(arg[0], arg[1], arg[2]); case 'saveAndEnterWorkspace': return this.service.saveAndEnterWorkspace(arg[0], arg[1]); case 'toggleFullScreen': return this.service.toggleFullScreen(arg); @@ -154,6 +154,10 @@ export class WindowsChannelClient implements IWindowsService { return this.channel.call('pickFolderAndOpen', options); } + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise { + return this.channel.call('pickWorkspaceAndOpen', options); + } + reloadWindow(windowId: number): TPromise { return this.channel.call('reloadWindow', windowId); } @@ -170,10 +174,6 @@ export class WindowsChannelClient implements IWindowsService { return this.channel.call('closeWorkspace', windowId); } - openWorkspace(windowId: number): TPromise { - return this.channel.call('openWorkspace', windowId); - } - createAndEnterWorkspace(windowId: number, folderPaths?: string[], path?: string): TPromise { return this.channel.call('createAndEnterWorkspace', [windowId, folderPaths, path]); } diff --git a/src/vs/platform/windows/electron-browser/windowService.ts b/src/vs/platform/windows/electron-browser/windowService.ts index 0cf353eb6f2..1302176c493 100644 --- a/src/vs/platform/windows/electron-browser/windowService.ts +++ b/src/vs/platform/windows/electron-browser/windowService.ts @@ -5,7 +5,7 @@ 'use strict'; -import Event, { filterEvent, mapEvent, any } from 'vs/base/common/event'; +import Event, { filterEvent, mapEvent, anyEvent } from 'vs/base/common/event'; import { TPromise } from 'vs/base/common/winjs.base'; import { IWindowService, IWindowsService, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult } from 'vs/platform/windows/common/windows'; import { remote } from 'electron'; @@ -26,7 +26,7 @@ export class WindowService implements IWindowService { ) { const onThisWindowFocus = mapEvent(filterEvent(windowsService.onWindowFocus, id => id === windowId), _ => true); const onThisWindowBlur = mapEvent(filterEvent(windowsService.onWindowBlur, id => id === windowId), _ => false); - this.onDidChangeFocus = any(onThisWindowFocus, onThisWindowBlur); + this.onDidChangeFocus = anyEvent(onThisWindowFocus, onThisWindowBlur); } getCurrentWindowId(): number { @@ -51,6 +51,12 @@ export class WindowService implements IWindowService { return this.windowsService.pickFolderAndOpen(options); } + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise { + options.windowId = this.windowId; + + return this.windowsService.pickWorkspaceAndOpen(options); + } + reloadWindow(): TPromise { return this.windowsService.reloadWindow(this.windowId); } @@ -67,10 +73,6 @@ export class WindowService implements IWindowService { return this.windowsService.closeWorkspace(this.windowId); } - openWorkspace(): TPromise { - return this.windowsService.openWorkspace(this.windowId); - } - createAndEnterWorkspace(folderPaths?: string[], path?: string): TPromise { return this.windowsService.createAndEnterWorkspace(this.windowId, folderPaths, path); } @@ -140,31 +142,37 @@ export class WindowService implements IWindowService { } showSaveDialog(options: Electron.SaveDialogOptions, callback?: (fileName: string) => void): string { + + function normalizePath(path: string): string { + if (path && isMacintosh) { + path = normalizeNFC(path); // normalize paths returned from the OS + } + + return path; + } + if (callback) { - return remote.dialog.showSaveDialog(remote.getCurrentWindow(), options, callback); + return remote.dialog.showSaveDialog(remote.getCurrentWindow(), options, path => callback(normalizePath(path))); } - let path = remote.dialog.showSaveDialog(remote.getCurrentWindow(), options); // https://github.com/electron/electron/issues/4936 - - if (path && isMacintosh) { - path = normalizeNFC(path); // normalize paths returned from the OS - } - - return path; + return normalizePath(remote.dialog.showSaveDialog(remote.getCurrentWindow(), options)); // https://github.com/electron/electron/issues/4936 } showOpenDialog(options: Electron.OpenDialogOptions, callback?: (fileNames: string[]) => void): string[] { + + function normalizePaths(paths: string[]): string[] { + if (paths && paths.length > 0 && isMacintosh) { + paths = paths.map(path => normalizeNFC(path)); // normalize paths returned from the OS + } + + return paths; + } + if (callback) { - return remote.dialog.showOpenDialog(remote.getCurrentWindow(), options, callback); + return remote.dialog.showOpenDialog(remote.getCurrentWindow(), options, paths => callback(normalizePaths(paths))); } - let paths = remote.dialog.showOpenDialog(remote.getCurrentWindow(), options); // https://github.com/electron/electron/issues/4936 - - if (paths && paths.length > 0 && isMacintosh) { - paths = paths.map(path => normalizeNFC(path)); // normalize paths returned from the OS - } - - return paths; + return normalizePaths(remote.dialog.showOpenDialog(remote.getCurrentWindow(), options)); // https://github.com/electron/electron/issues/4936 } updateTouchBar(items: ICommandAction[][]): TPromise { diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index ba04b4766e7..6a35060fcd7 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -60,7 +60,6 @@ export interface IWindowsMainService { // methods ready(initialUserEnv: IProcessEnvironment): void; reload(win: ICodeWindow, cli?: ParsedArgs): void; - openWorkspace(win?: ICodeWindow): void; createAndEnterWorkspace(win: ICodeWindow, folderPaths?: string[], path?: string): TPromise; saveAndEnterWorkspace(win: ICodeWindow, path: string): TPromise; closeWorkspace(win: ICodeWindow): void; @@ -69,6 +68,7 @@ export interface IWindowsMainService { pickFileFolderAndOpen(options: INativeOpenDialogOptions): void; pickFolderAndOpen(options: INativeOpenDialogOptions): void; pickFileAndOpen(options: INativeOpenDialogOptions): void; + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): void; focusLastActive(cli: ParsedArgs, context: OpenContext): ICodeWindow; getLastActiveWindow(): ICodeWindow; waitForWindowCloseOrLoad(windowId: number): TPromise; diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index 2c3ac1c8934..119303af739 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -70,6 +70,12 @@ export class WindowsService implements IWindowsService, IDisposable { return TPromise.as(null); } + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise { + this.windowsMainService.pickWorkspaceAndOpen(options); + + return TPromise.as(null); + } + reloadWindow(windowId: number): TPromise { const codeWindow = this.windowsMainService.getWindowById(windowId); @@ -125,16 +131,6 @@ export class WindowsService implements IWindowsService, IDisposable { return TPromise.as(null); } - openWorkspace(windowId: number): TPromise { - const codeWindow = this.windowsMainService.getWindowById(windowId); - - if (codeWindow) { - this.windowsMainService.openWorkspace(codeWindow); - } - - return TPromise.as(null); - } - createAndEnterWorkspace(windowId: number, folderPaths?: string[], path?: string): TPromise { const codeWindow = this.windowsMainService.getWindowById(windowId); diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 78875f25837..af594644bae 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -13,7 +13,6 @@ import Event from 'vs/base/common/event'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, isRawUriWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { coalesce, distinct } from 'vs/base/common/arrays'; import { isLinux } from 'vs/base/common/platform'; -import { TPromise } from 'vs/base/common/winjs.base'; export const IWorkspaceContextService = createDecorator('contextService'); @@ -48,21 +47,10 @@ export interface IWorkspaceContextService { onDidChangeWorkspaceFolders: Event; /** - * Provides access to the workspace object the platform is running with. This may be null if the workbench was opened - * without workspace (empty); + * Provides access to the workspace object the platform is running with. */ getWorkspace(): IWorkspace; - /** - * add folders to the existing workspace - */ - addFolders(folders: URI[]): TPromise; - - /** - * remove folders from the existing workspace - */ - removeFolders(folders: URI[]): TPromise; - /** * Return the state of the workbench. * diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts index 3adce81a073..28c28f189d9 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts @@ -17,9 +17,10 @@ import { WorkspacesMainService, IStoredWorkspace } from 'vs/platform/workspaces/ import { WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier, IRawFileWorkspaceFolder, IRawUriWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { LogMainService } from 'vs/platform/log/common/log'; import URI from 'vs/base/common/uri'; +import { getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; suite('WorkspacesMainService', () => { - const parentDir = path.join(os.tmpdir(), 'vsctests', 'service'); + const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'workspacesservice'); const workspacesHome = path.join(parentDir, 'Workspaces'); class TestEnvironmentService extends EnvironmentService { @@ -359,14 +360,16 @@ suite('WorkspacesMainService', () => { assert.equal(1, untitled.length); assert.equal(untitledOne.id, untitled[0].id); - return service.createWorkspace([process.cwd(), os.tmpdir()]).then(untitledTwo => { + return service.createWorkspace([os.tmpdir(), process.cwd()]).then(untitledTwo => { untitled = service.getUntitledWorkspacesSync(); assert.equal(2, untitled.length); service.deleteUntitledWorkspaceSync(untitledOne); - service.deleteUntitledWorkspaceSync(untitledTwo); + untitled = service.getUntitledWorkspacesSync(); + assert.equal(1, untitled.length); + service.deleteUntitledWorkspaceSync(untitledTwo); untitled = service.getUntitledWorkspacesSync(); assert.equal(0, untitled.length); diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 09c84d07fc1..b1d5160d44e 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -4979,6 +4979,10 @@ declare module 'vscode' { * Args for the custom shell executable, this does not work on Windows (see #8429) */ shellArgs?: string[]; + /** + * Object with environment variables that will be added to the VS Code process. + */ + env?: { [key: string]: string | null }; } /** @@ -5193,6 +5197,14 @@ declare module 'vscode' { */ export let workspaceFolders: WorkspaceFolder[] | undefined; + /** + * The name of the workspace. `undefined` when no folder + * has been opened. + * + * @readonly + */ + export let name: string | undefined; + /** * An event that is emitted when a workspace folder is added or removed. */ @@ -6032,8 +6044,8 @@ declare module 'vscode' { /** * A debug configuration provider allows to add the initial debug configurations to a newly created launch.json - * and allows to resolve a launch configuration before it is used to start a new debug session. - * A debug configuration provider is registered via #workspace.registerDebugConfigurationProvider. + * and to resolve a launch configuration before it is used to start a new debug session. + * A debug configuration provider is registered via #debug.registerDebugConfigurationProvider. */ export interface DebugConfigurationProvider { /** @@ -6050,11 +6062,12 @@ declare module 'vscode' { * Resolves a [debug configuration](#DebugConfiguration) by filling in missing values or by adding/changing/removing attributes. * If more than one debug configuration provider is registered for the same type, the resolveDebugConfiguration calls are chained * in arbitrary order and the initial debug configuration is piped through the chain. + * Returning the value 'undefined' prevents the debug session from starting. * * @param folder The workspace folder from which the configuration originates from or undefined for a folderless setup. * @param debugConfiguration The [debug configuration](#DebugConfiguration) to resolve. * @param token A cancellation token. - * @return The resolved debug configuration. + * @return The resolved debug configuration or undefined. */ resolveDebugConfiguration?(folder: WorkspaceFolder | undefined, debugConfiguration: DebugConfiguration, token?: CancellationToken): ProviderResult; } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 3ff70ed91db..5586bd1c124 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -190,4 +190,31 @@ declare module 'vscode' { } //#endregion + + /** + * Represents the debug console. + */ + export interface DebugConsole { + /** + * Append the given value to the debug console. + * + * @param value A string, falsy values will not be printed. + */ + append(value: string): void; + + /** + * Append the given value and a line feed character + * to the debug console. + * + * @param value A string, falsy values will be printed. + */ + appendLine(value: string): void; + } + + export namespace debug { + /** + * The [debug console](#DebugConsole) singleton. + */ + export let console: DebugConsole; + } } diff --git a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts index af2d72759b5..8686e4f1483 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts @@ -11,6 +11,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +import severity from 'vs/base/common/severity'; @extHostNamedCustomer(MainContext.MainThreadDebugService) export class MainThreadDebugService implements MainThreadDebugServiceShape { @@ -93,4 +94,10 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape { } return TPromise.wrapError(new Error('debug session not found')); } + + public $appendDebugConsole(value: string): TPromise { + // Use warning as severity to get the orange color for messages coming from the debug extension + this.debugService.logToRepl(value, severity.Warning); + return TPromise.as(undefined); + } } diff --git a/src/vs/workbench/api/electron-browser/mainThreadEditors.ts b/src/vs/workbench/api/electron-browser/mainThreadEditors.ts index 6787006461b..eb1b487da37 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadEditors.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadEditors.ts @@ -60,7 +60,7 @@ export class MainThreadEditors implements MainThreadEditorsShape { this._toDispose.push(documentsAndEditors.onTextEditorRemove(editors => editors.forEach(this._onTextEditorRemove, this))); this._toDispose.push(editorGroupService.onEditorsChanged(() => this._updateActiveAndVisibleTextEditors())); - this._toDispose.push(editorGroupService.onEditorsMoved(() => this._updateActiveAndVisibleTextEditors())); + this._toDispose.push(editorGroupService.onEditorGroupMoved(() => this._updateActiveAndVisibleTextEditors())); this._registeredDecorationTypes = Object.create(null); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts index a786896b834..18ada375e58 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -13,7 +13,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { IProgress } from 'vs/platform/progress/common/progress'; import { ISearchResultProvider, ISearchQuery, ISearchComplete, ISearchProgressItem, QueryType, IFileMatch, ISearchService } from 'vs/platform/search/common/search'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; @extHostNamedCustomer(MainContext.MainThreadFileSystem) export class MainThreadFileSystem implements MainThreadFileSystemShape { @@ -26,7 +26,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { extHostContext: IExtHostContext, @IFileService private readonly _fileService: IFileService, @ISearchService private readonly _searchService: ISearchService, - @IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService + @IWorkspaceEditingService private readonly _workspaceEditingService: IWorkspaceEditingService ) { this._proxy = extHostContext.get(ExtHostContext.ExtHostFileSystem); } @@ -45,7 +45,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { } $onDidAddFileSystemRoot(uri: URI): void { - this._workspaceContextService.addFolders([uri]); + this._workspaceEditingService.addFolders([uri]); } $onFileSystemChange(handle: number, changes: IFileChange[]): void { diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index 757bab38cea..9578af3db6e 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -205,9 +205,17 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha // --- navigate type $registerNavigateTypeSupport(handle: number): TPromise { + let lastResultId: number; this._registrations[handle] = WorkspaceSymbolProviderRegistry.register({ provideWorkspaceSymbols: (search: string): TPromise => { - return this._heapService.trackRecursive(this._proxy.$provideWorkspaceSymbols(handle, search)); + + return this._proxy.$provideWorkspaceSymbols(handle, search).then(result => { + if (lastResultId !== undefined) { + this._proxy.$releaseWorkspaceSymbols(handle, lastResultId); + } + lastResultId = result._id; + return result.symbols; + }); }, resolveWorkspaceSymbol: (item: modes.SymbolInformation): TPromise => { return this._proxy.$resolveWorkspaceSymbol(handle, item); diff --git a/src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts b/src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts index a0c4d0db90f..aade4a664e3 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts @@ -33,13 +33,14 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape // when the extension host process goes down ? } - public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], waitOnExit?: boolean): TPromise { + public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], env?: { [key: string]: string }, waitOnExit?: boolean): TPromise { const shellLaunchConfig: IShellLaunchConfig = { name, executable: shellPath, args: shellArgs, waitOnExit, - ignoreConfigurationCwd: true + ignoreConfigurationCwd: true, + env }; return TPromise.as(this.terminalService.createInstance(shellLaunchConfig).id); } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 128eb4a907e..1d9c80b498f 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -397,6 +397,12 @@ export function createApiFactory( get workspaceFolders() { return extHostWorkspace.getWorkspaceFolders(); }, + get name() { + return extHostWorkspace.workspace ? extHostWorkspace.workspace.name : undefined; + }, + set name(value) { + throw errors.readonly(); + }, onDidChangeWorkspaceFolders: function (listener, thisArgs?, disposables?) { return extHostWorkspace.onDidChangeWorkspace(listener, thisArgs, disposables); }, @@ -489,6 +495,9 @@ export function createApiFactory( get activeDebugSession() { return extHostDebugService.activeDebugSession; }, + get console() { + return extHostDebugService.debugConsole; + }, startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration) { return extHostDebugService.startDebugging(folder, nameOrConfig); }, @@ -506,7 +515,7 @@ export function createApiFactory( }, registerDebugConfigurationProvider(debugType: string, provider: vscode.DebugConfigurationProvider) { return extHostDebugService.registerDebugConfigurationProvider(debugType, provider); - }, + } }; // namespace: credentials diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 2619ab29fcb..2346b9d7ebb 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -291,7 +291,7 @@ export interface MainThreadProgressShape extends IDisposable { } export interface MainThreadTerminalServiceShape extends IDisposable { - $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], waitOnExit?: boolean): TPromise; + $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], env?: { [key: string]: string }, waitOnExit?: boolean): TPromise; $dispose(terminalId: number): void; $hide(terminalId: number): void; $sendText(terminalId: number, text: string, addNewLine: boolean): void; @@ -404,6 +404,7 @@ export interface MainThreadDebugServiceShape extends IDisposable { $unregisterDebugConfigurationProvider(handle: number): TPromise; $startDebugging(folder: URI | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise; $customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): TPromise; + $appendDebugConsole(value: string): TPromise; } export interface MainThreadCredentialsShape extends IDisposable { @@ -551,6 +552,21 @@ export interface IExtHostSuggestResult { incomplete?: boolean; } +export interface IdObject { + _id: number; +} + +export namespace IdObject { + let n = 0; + export function mixin(object: T): T & IdObject { + (object)._id = n++; + return object; + } +} + +export type IWorkspaceSymbol = IdObject & modes.SymbolInformation; +export interface IWorkspaceSymbols extends IdObject { symbols: IWorkspaceSymbol[]; }; + export interface ExtHostLanguageFeaturesShape { $provideDocumentSymbols(handle: number, resource: URI): TPromise; $provideCodeLenses(handle: number, resource: URI): TPromise; @@ -565,8 +581,9 @@ export interface ExtHostLanguageFeaturesShape { $provideDocumentFormattingEdits(handle: number, resource: URI, options: modes.FormattingOptions): TPromise; $provideDocumentRangeFormattingEdits(handle: number, resource: URI, range: IRange, options: modes.FormattingOptions): TPromise; $provideOnTypeFormattingEdits(handle: number, resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise; - $provideWorkspaceSymbols(handle: number, search: string): TPromise; - $resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise; + $provideWorkspaceSymbols(handle: number, search: string): TPromise; + $resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise; + $releaseWorkspaceSymbols(handle: number, id: number): void; $provideRenameEdits(handle: number, resource: URI, position: IPosition, newName: string): TPromise; $provideCompletionItems(handle: number, resource: URI, position: IPosition, context: modes.SuggestContext): TPromise; $resolveCompletionItem(handle: number, resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise; diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index fde9013ed78..f7b42446d55 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -45,7 +45,7 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationData) { this._proxy = proxy; this._extHostWorkspace = extHostWorkspace; - this._configuration = Configuration.parse(data, extHostWorkspace.workspace); + this._configuration = Configuration.parse(data); } get onDidChangeConfiguration(): Event { @@ -53,14 +53,14 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { } $acceptConfigurationChanged(data: IConfigurationData, eventData: IWorkspaceConfigurationChangeEventData) { - this._configuration = Configuration.parse(data, this._extHostWorkspace.workspace); + this._configuration = Configuration.parse(data); this._onDidChangeConfiguration.fire(undefined); } getConfiguration(section?: string, resource?: URI): vscode.WorkspaceConfiguration { const config = section - ? lookUp(this._configuration.getSection(null, { resource }), section) - : this._configuration.getSection(null, { resource }); + ? lookUp(this._configuration.getSection(null, { resource }, this._extHostWorkspace.workspace), section) + : this._configuration.getSection(null, { resource }, this._extHostWorkspace.workspace); function parseConfigurationTarget(arg: boolean | ExtHostConfigurationTarget): ConfigurationTarget { if (arg === void 0 || arg === null) { @@ -99,7 +99,7 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { }, inspect: (key: string): ConfigurationInspect => { key = section ? `${section}.${key}` : key; - const config = this._configuration.lookup(key, { resource }); + const config = this._configuration.lookup(key, { resource }, this._extHostWorkspace.workspace); if (config) { return { key, diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 71727e711d5..23c7a043199 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -40,6 +40,9 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { private _onDidReceiveDebugSessionCustomEvent: Emitter; get onDidReceiveDebugSessionCustomEvent(): Event { return this._onDidReceiveDebugSessionCustomEvent.event; } + private _debugConsole: ExtHostDebugConsole; + get debugConsole(): ExtHostDebugConsole { return this._debugConsole; } + constructor(mainContext: IMainContext, workspace: ExtHostWorkspace) { @@ -54,6 +57,8 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { this._onDidReceiveDebugSessionCustomEvent = new Emitter(); this._debugServiceProxy = mainContext.get(MainContext.MainThreadDebugService); + + this._debugConsole = new ExtHostDebugConsole(this._debugServiceProxy); } public registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider): vscode.Disposable { @@ -178,7 +183,7 @@ export class ExtHostDebugSession implements vscode.DebugSession { this._id = id; this._type = type; this._name = name; - }; + } public get id(): string { return this._id; @@ -196,3 +201,20 @@ export class ExtHostDebugSession implements vscode.DebugSession { return this._debugServiceProxy.$customDebugAdapterRequest(this._id, command, args); } } + +export class ExtHostDebugConsole implements vscode.DebugConsole { + + private _debugServiceProxy: MainThreadDebugServiceShape; + + constructor(proxy: MainThreadDebugServiceShape) { + this._debugServiceProxy = proxy; + } + + append(value: string): void { + this._debugServiceProxy.$appendDebugConsole(value); + } + + appendLine(value: string): void { + this.append(value + '\n'); + } +} diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 7718b667dd4..3b5bb8f8b44 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -16,9 +16,8 @@ import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService'; import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments'; import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands'; import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics'; -import { IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search'; import { asWinJsPromise } from 'vs/base/common/async'; -import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IExtHostSuggestResult, IExtHostSuggestion } from './extHost.protocol'; +import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IExtHostSuggestResult, IExtHostSuggestion, IWorkspaceSymbols, IWorkspaceSymbol, IdObject } from './extHost.protocol'; import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings'; import { IPosition } from 'vs/editor/common/core/position'; import { IRange } from 'vs/editor/common/core/range'; @@ -368,45 +367,56 @@ class OnTypeFormattingAdapter { } } +class NavigateTypeAdapter { -class NavigateTypeAdapter implements IWorkspaceSymbolProvider { + private readonly _symbolCache: { [id: number]: vscode.SymbolInformation } = Object.create(null); + private readonly _resultCache: { [id: number]: [number, number] } = Object.create(null); + private readonly _provider: vscode.WorkspaceSymbolProvider; - private _provider: vscode.WorkspaceSymbolProvider; - private _heapService: ExtHostHeapService; - - constructor(provider: vscode.WorkspaceSymbolProvider, heapService: ExtHostHeapService) { + constructor(provider: vscode.WorkspaceSymbolProvider) { this._provider = provider; - this._heapService = heapService; } - provideWorkspaceSymbols(search: string): TPromise { - + provideWorkspaceSymbols(search: string): TPromise { + const result: IWorkspaceSymbols = IdObject.mixin({ symbols: [] }); return asWinJsPromise(token => this._provider.provideWorkspaceSymbols(search, token)).then(value => { - if (Array.isArray(value)) { - return value.map(item => { - const id = this._heapService.keep(item); - const result = TypeConverters.fromSymbolInformation(item); - return ObjectIdentifier.mixin(result, id); - }); + if (!isFalsyOrEmpty(value)) { + for (const item of value) { + const symbol = IdObject.mixin(TypeConverters.fromSymbolInformation(item)); + this._symbolCache[symbol._id] = item; + result.symbols.push(symbol); + } } - return undefined; + }).then(() => { + this._resultCache[result._id] = [result.symbols[0]._id, result.symbols[result.symbols.length - 1]._id]; + return result; }); } - resolveWorkspaceSymbol(item: modes.SymbolInformation): TPromise { + resolveWorkspaceSymbol(symbol: IWorkspaceSymbol): TPromise { if (typeof this._provider.resolveWorkspaceSymbol !== 'function') { - return TPromise.as(item); + return TPromise.as(symbol); } - const symbolInfo = this._heapService.get(ObjectIdentifier.of(item)); - if (symbolInfo) { - return asWinJsPromise(token => this._provider.resolveWorkspaceSymbol(symbolInfo, token)).then(value => { - return value && TypeConverters.fromSymbolInformation(value); + const item = this._symbolCache[symbol._id]; + if (item) { + return asWinJsPromise(token => this._provider.resolveWorkspaceSymbol(item, token)).then(value => { + return value && mixin(symbol, TypeConverters.fromSymbolInformation(value), true); }); } return undefined; } + + releaseWorkspaceSymbols(id: number): any { + const range = this._resultCache[id]; + if (range) { + for (let [from, to] = range; from <= to; from++) { + delete this._symbolCache[from]; + } + delete this._resultCache[id]; + } + } } class RenameAdapter { @@ -946,19 +956,23 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable { const handle = this._nextHandle(); - this._adapter.set(handle, new NavigateTypeAdapter(provider, this._heapService)); + this._adapter.set(handle, new NavigateTypeAdapter(provider)); this._proxy.$registerNavigateTypeSupport(handle); return this._createDisposable(handle); } - $provideWorkspaceSymbols(handle: number, search: string): TPromise { + $provideWorkspaceSymbols(handle: number, search: string): TPromise { return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search)); } - $resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise { + $resolveWorkspaceSymbol(handle: number, symbol: IWorkspaceSymbol): TPromise { return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol)); } + $releaseWorkspaceSymbols(handle: number, id: number) { + this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.releaseWorkspaceSymbols(id)); + } + // --- rename registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable { diff --git a/src/vs/workbench/api/node/extHostQuickOpen.ts b/src/vs/workbench/api/node/extHostQuickOpen.ts index 3f68011720b..03672ebf187 100644 --- a/src/vs/workbench/api/node/extHostQuickOpen.ts +++ b/src/vs/workbench/api/node/extHostQuickOpen.ts @@ -128,12 +128,12 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape { // ---- workspace folder picker showWorkspaceFolderPick(options?: WorkspaceFolderPickOptions, token = CancellationToken.None): Thenable { - return this._commands.executeCommand('_workbench.pickWorkspaceFolder', [options]).then((folder: WorkspaceFolder) => { - if (!folder) { + return this._commands.executeCommand('_workbench.pickWorkspaceFolder', [options]).then((selectedFolder: WorkspaceFolder) => { + if (!selectedFolder) { return undefined; } - return this._workspace.getWorkspaceFolders().filter(folder => folder.uri.toString() === folder.uri.toString())[0]; + return this._workspace.getWorkspaceFolders().filter(folder => folder.uri.toString() === selectedFolder.uri.toString())[0]; }); } } diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index e42fc83d1f6..adcd7ddd9a1 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -24,6 +24,7 @@ export class ExtHostTerminal implements vscode.Terminal { name?: string, shellPath?: string, shellArgs?: string[], + env?: { [key: string]: string }, waitOnExit?: boolean ) { this._name = name; @@ -32,7 +33,7 @@ export class ExtHostTerminal implements vscode.Terminal { this._pidPromise = new TPromise(c => { this._pidPromiseComplete = c; }); - this._proxy.$createTerminal(name, shellPath, shellArgs, waitOnExit).then((id) => { + this._proxy.$createTerminal(name, shellPath, shellArgs, env, waitOnExit).then((id) => { this._id = id; this._queuedRequests.forEach((r) => { r.run(this._proxy, this._id); @@ -113,7 +114,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { } public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal { - let terminal = new ExtHostTerminal(this._proxy, options.name, options.shellPath, options.shellArgs/*, options.waitOnExit*/); + let terminal = new ExtHostTerminal(this._proxy, options.name, options.shellPath, options.shellArgs, options.env/*, options.waitOnExit*/); this._terminals.push(terminal); return terminal; } diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index 50a08486f98..078e0e38201 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -8,7 +8,6 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { Action } from 'vs/base/common/actions'; import nls = require('vs/nls'); -import { distinct } from 'vs/base/common/arrays'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -26,6 +25,27 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { IQuickOpenService, IFilePickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen'; import { CancellationToken } from 'vs/base/common/cancellation'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; +import { IHistoryService } from 'vs/workbench/services/history/common/history'; + +export class OpenFileAction extends Action { + + static ID = 'workbench.action.files.openFile'; + static LABEL = nls.localize('openFile', "Open File..."); + + constructor( + id: string, + label: string, + @IWindowService private windowService: IWindowService, + @IHistoryService private historyService: IHistoryService, + @IWorkspaceContextService private contextService: IWorkspaceContextService + ) { + super(id, label); + } + + run(event?: any, data?: ITelemetryData): TPromise { + return this.windowService.pickFileAndOpen({ telemetryExtraData: data, dialogOptions: { defaultPath: defaultFilePath(this.contextService, this.historyService) } }); + } +} export class OpenFolderAction extends Action { @@ -35,13 +55,15 @@ export class OpenFolderAction extends Action { constructor( id: string, label: string, - @IWindowService private windowService: IWindowService + @IWindowService private windowService: IWindowService, + @IHistoryService private historyService: IHistoryService, + @IWorkspaceContextService private contextService: IWorkspaceContextService ) { super(id, label); } run(event?: any, data?: ITelemetryData): TPromise { - return this.windowService.pickFolderAndOpen({ telemetryExtraData: data }); + return this.windowService.pickFolderAndOpen({ telemetryExtraData: data, dialogOptions: { defaultPath: defaultFolderPath(this.contextService, this.historyService) } }); } } @@ -53,16 +75,57 @@ export class OpenFileFolderAction extends Action { constructor( id: string, label: string, - @IWindowService private windowService: IWindowService + @IWindowService private windowService: IWindowService, + @IHistoryService private historyService: IHistoryService, + @IWorkspaceContextService private contextService: IWorkspaceContextService ) { super(id, label); } run(event?: any, data?: ITelemetryData): TPromise { - return this.windowService.pickFileFolderAndOpen({ telemetryExtraData: data }); + return this.windowService.pickFileFolderAndOpen({ telemetryExtraData: data, dialogOptions: { defaultPath: defaultFilePath(this.contextService, this.historyService) } }); } } +export const openFileFolderInNewWindowCommand = (accessor: ServicesAccessor) => { + const { windowService, historyService, contextService } = services(accessor); + + windowService.pickFileFolderAndOpen({ forceNewWindow: true, dialogOptions: { defaultPath: defaultFilePath(contextService, historyService) } }); +}; + +export const openFolderCommand = (accessor: ServicesAccessor, forceNewWindow: boolean) => { + const { windowService, historyService, contextService } = services(accessor); + + windowService.pickFolderAndOpen({ forceNewWindow, dialogOptions: { defaultPath: defaultFolderPath(contextService, historyService) } }); +}; + +export const openFolderInNewWindowCommand = (accessor: ServicesAccessor) => { + const { windowService, historyService, contextService } = services(accessor); + + windowService.pickFolderAndOpen({ forceNewWindow: true, dialogOptions: { defaultPath: defaultFolderPath(contextService, historyService) } }); +}; + +export const openFileInNewWindowCommand = (accessor: ServicesAccessor) => { + const { windowService, historyService, contextService } = services(accessor); + + windowService.pickFileAndOpen({ forceNewWindow: true, dialogOptions: { defaultPath: defaultFilePath(contextService, historyService) } }); +}; + +export const openWorkspaceInNewWindowCommand = (accessor: ServicesAccessor) => { + const { windowService, historyService, contextService, environmentService } = services(accessor); + + windowService.pickWorkspaceAndOpen({ forceNewWindow: true, dialogOptions: { defaultPath: defaultWorkspacePath(contextService, historyService, environmentService) } }); +}; + +function services(accessor: ServicesAccessor): { windowService: IWindowService, historyService: IHistoryService, contextService: IWorkspaceContextService, environmentService: IEnvironmentService } { + return { + windowService: accessor.get(IWindowService), + historyService: accessor.get(IHistoryService), + contextService: accessor.get(IWorkspaceContextService), + environmentService: accessor.get(IEnvironmentService) + }; +} + export abstract class BaseWorkspacesAction extends Action { constructor( @@ -70,27 +133,65 @@ export abstract class BaseWorkspacesAction extends Action { label: string, protected windowService: IWindowService, protected environmentService: IEnvironmentService, - protected contextService: IWorkspaceContextService + protected contextService: IWorkspaceContextService, + protected historyService: IHistoryService ) { super(id, label); } protected pickFolders(buttonLabel: string, title: string): string[] { - let defaultPath: string; - const workspace = this.contextService.getWorkspace(); - if (workspace.folders.length > 0) { - defaultPath = dirname(workspace.folders[0].uri.fsPath); // pick the parent of the first root by default - } - return this.windowService.showOpenDialog({ buttonLabel, title, properties: ['multiSelections', 'openDirectory', 'createDirectory'], - defaultPath + defaultPath: defaultFolderPath(this.contextService, this.historyService) }); } } +function defaultFilePath(contextService: IWorkspaceContextService, historyService: IHistoryService): string { + let candidate: URI; + + // Check for last active file first... + candidate = historyService.getLastActiveFile(); + + // ...then for last active file root + if (!candidate) { + candidate = historyService.getLastActiveWorkspaceRoot('file'); + } + + return candidate ? dirname(candidate.fsPath) : void 0; +} + +function defaultFolderPath(contextService: IWorkspaceContextService, historyService: IHistoryService): string { + let candidate: URI; + + // Check for last active file root first... + candidate = historyService.getLastActiveWorkspaceRoot('file'); + + // ...then for last active file + if (!candidate) { + candidate = historyService.getLastActiveFile(); + } + + return candidate ? dirname(candidate.fsPath) : void 0; +} + +function defaultWorkspacePath(contextService: IWorkspaceContextService, historyService: IHistoryService, environmentService: IEnvironmentService): string { + + // Check for current workspace config file first... + if (contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && !isUntitledWorkspace(contextService.getWorkspace().configuration.fsPath, environmentService)) { + return dirname(contextService.getWorkspace().configuration.fsPath); + } + + // ...then fallback to default folder path + return defaultFolderPath(contextService, historyService); +} + +function isUntitledWorkspace(path: string, environmentService: IEnvironmentService): boolean { + return isParent(path, environmentService.workspacesHome, !isLinux /* ignore case */); +} + export class AddRootFolderAction extends BaseWorkspacesAction { static ID = 'workbench.action.addRootFolder'; @@ -104,31 +205,20 @@ export class AddRootFolderAction extends BaseWorkspacesAction { @IEnvironmentService environmentService: IEnvironmentService, @IInstantiationService private instantiationService: IInstantiationService, @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, - @IViewletService private viewletService: IViewletService + @IViewletService private viewletService: IViewletService, + @IHistoryService historyService: IHistoryService ) { - super(id, label, windowService, environmentService, contextService); + super(id, label, windowService, environmentService, contextService, historyService); } public run(): TPromise { - let addFoldersPromise: TPromise; - - // Workspace - if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { - const folders = super.pickFolders(mnemonicButtonLabel(nls.localize({ key: 'add', comment: ['&& denotes a mnemonic'] }, "&&Add")), nls.localize('addFolderToWorkspaceTitle', "Add Folder to Workspace")); - if (!folders || !folders.length) { - return TPromise.as(null); - } - - addFoldersPromise = this.contextService.addFolders(folders.map(folder => URI.file(folder))); - } - - // Empty or Folder - else { - addFoldersPromise = this.instantiationService.createInstance(NewWorkspaceAction, NewWorkspaceAction.ID, NewWorkspaceAction.LABEL, this.contextService.getWorkspace().folders.map(folder => folder.uri)).run(); + const folders = super.pickFolders(mnemonicButtonLabel(nls.localize({ key: 'add', comment: ['&& denotes a mnemonic'] }, "&&Add")), nls.localize('addFolderToWorkspaceTitle', "Add Folder to Workspace")); + if (!folders || !folders.length) { + return TPromise.as(null); } // Add and show Files Explorer viewlet - return addFoldersPromise.then(() => this.viewletService.openViewlet(this.viewletService.getDefaultViewletId(), true)); + return this.workspaceEditingService.addFolders(folders.map(folder => URI.file(folder))).then(() => this.viewletService.openViewlet(this.viewletService.getDefaultViewletId(), true)); } } @@ -144,9 +234,10 @@ export class GlobalRemoveRootFolderAction extends BaseWorkspacesAction { @IWorkspaceContextService contextService: IWorkspaceContextService, @IEnvironmentService environmentService: IEnvironmentService, @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, - @ICommandService private commandService: ICommandService + @ICommandService private commandService: ICommandService, + @IHistoryService historyService: IHistoryService ) { - super(id, label, windowService, environmentService, contextService); + super(id, label, windowService, environmentService, contextService, historyService); } public run(): TPromise { @@ -156,14 +247,7 @@ export class GlobalRemoveRootFolderAction extends BaseWorkspacesAction { if (state === WorkbenchState.WORKSPACE || state === WorkbenchState.FOLDER) { return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND).then(folder => { if (folder) { - - // Folder: close workspace - if (state === WorkbenchState.FOLDER) { - return this.windowService.closeWorkspace().then(() => true); - } - - // Workspace: remove folder - return this.contextService.removeFolders([folder.uri]).then(() => true); + return this.workspaceEditingService.removeFolders([folder.uri]).then(() => true); } return true; @@ -174,39 +258,6 @@ export class GlobalRemoveRootFolderAction extends BaseWorkspacesAction { } } -class NewWorkspaceAction extends BaseWorkspacesAction { - - static ID = 'workbench.action.newWorkspace'; - static LABEL = nls.localize('newWorkspace', "New Workspace..."); - - constructor( - id: string, - label: string, - private presetRoots: URI[], - @IWindowService windowService: IWindowService, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @IEnvironmentService environmentService: IEnvironmentService, - @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService - ) { - super(id, label, windowService, environmentService, contextService); - } - - public run(): TPromise { - const folders = super.pickFolders(mnemonicButtonLabel(nls.localize({ key: 'select', comment: ['&& denotes a mnemonic'] }, "&&Select")), nls.localize('selectWorkspace', "Select Folders for Workspace")); - if (folders && folders.length) { - return this.createWorkspace([...this.presetRoots, ...folders.map(folder => URI.file(folder))]); - } - - return TPromise.as(null); - } - - private createWorkspace(folders: URI[]): TPromise { - const workspaceFolders = distinct(folders.map(folder => folder.fsPath), folder => isLinux ? folder : folder.toLowerCase()); - - return this.workspaceEditingService.createAndEnterWorkspace(workspaceFolders); - } -} - export class RemoveRootFolderAction extends Action { static ID = 'workbench.action.removeRootFolder'; @@ -216,13 +267,13 @@ export class RemoveRootFolderAction extends Action { private rootUri: URI, id: string, label: string, - @IWorkspaceContextService private contextService: IWorkspaceContextService + @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService ) { super(id, label); } public run(): TPromise { - return this.contextService.removeFolders([this.rootUri]); + return this.workspaceEditingService.removeFolders([this.rootUri]); } } @@ -243,6 +294,7 @@ export class OpenFolderSettingsAction extends Action { public run(): TPromise { const workspaceFolder = this.contextService.getWorkspaceFolder(this.rootUri); + return this.commandService.executeCommand('_workbench.action.openFolderSettings', workspaceFolder); } } @@ -258,9 +310,10 @@ export class SaveWorkspaceAsAction extends BaseWorkspacesAction { @IWindowService windowService: IWindowService, @IEnvironmentService environmentService: IEnvironmentService, @IWorkspaceContextService contextService: IWorkspaceContextService, - @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService + @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, + @IHistoryService historyService: IHistoryService ) { - super(id, label, windowService, environmentService, contextService); + super(id, label, windowService, environmentService, contextService, historyService); } public run(): TPromise { @@ -281,25 +334,13 @@ export class SaveWorkspaceAsAction extends BaseWorkspacesAction { } private getNewWorkspaceConfigPath(): string { - const workspace = this.contextService.getWorkspace(); - let defaultPath: string; - if (workspace.configuration && !this.isUntitledWorkspace(workspace.configuration.fsPath)) { - defaultPath = workspace.configuration.fsPath; - } else if (workspace.folders.length > 0) { - defaultPath = dirname(workspace.folders[0].uri.fsPath); // pick the parent of the first root by default - } - return this.windowService.showSaveDialog({ buttonLabel: mnemonicButtonLabel(nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save")), title: nls.localize('saveWorkspace', "Save Workspace"), filters: WORKSPACE_FILTER, - defaultPath + defaultPath: defaultWorkspacePath(this.contextService, this.historyService, this.environmentService) }); } - - private isUntitledWorkspace(path: string): boolean { - return isParent(path, this.environmentService.workspacesHome, !isLinux /* ignore case */); - } } export class OpenWorkspaceAction extends Action { @@ -311,12 +352,15 @@ export class OpenWorkspaceAction extends Action { id: string, label: string, @IWindowService private windowService: IWindowService, + @IWorkspaceContextService private contextService: IWorkspaceContextService, + @IHistoryService private historyService: IHistoryService, + @IEnvironmentService private environmentService: IEnvironmentService ) { super(id, label); } - public run(): TPromise { - return this.windowService.openWorkspace(); + public run(event?: any, data?: ITelemetryData): TPromise { + return this.windowService.pickWorkspaceAndOpen({ telemetryExtraData: data, dialogOptions: { defaultPath: defaultWorkspacePath(this.contextService, this.historyService, this.environmentService) } }); } } diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index bf7bf9f97d6..87ecb23e4c6 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -22,7 +22,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IDecorationsService, IResourceDecorationChangeEvent } from 'vs/workbench/services/decorations/browser/decorations'; import { Schemas } from 'vs/base/common/network'; -import { FileKind } from 'vs/platform/files/common/files'; +import { FileKind, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files'; import { IModel } from 'vs/editor/common/editorCommon'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -64,11 +64,25 @@ export class ResourceLabel extends IconLabel { } private registerListeners(): void { - this.extensionService.onReady().then(() => this.render(true /* clear cache */)); // update when extensions are loaded with potentially new languages - this.toDispose.push(this.configurationService.onDidChangeConfiguration(() => this.render(true /* clear cache */))); // update when file.associations change - this.toDispose.push(this.modelService.onModelModeChanged(e => this.onModelModeChanged(e))); // react to model mode changes - this.toDispose.push(this.decorationsService.onDidChangeDecorations(this.onFileDecorationsChanges, this)); // react to file decoration changes + + // update when extensions are loaded with potentially new languages + this.extensionService.onReady().then(() => this.render(true /* clear cache */)); + + // react to model mode changes + this.toDispose.push(this.modelService.onModelModeChanged(e => this.onModelModeChanged(e))); + + // react to file decoration changes + this.toDispose.push(this.decorationsService.onDidChangeDecorations(this.onFileDecorationsChanges, this)); + + // react to theme changes this.toDispose.push(this.themeService.onThemeChange(() => this.render(false))); + + // react to files.associations changes + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(FILES_ASSOCIATIONS_CONFIG)) { + this.render(true /* clear cache */); + } + })); } private onModelModeChanged(e: { model: IModel; oldModeId: string; }): void { @@ -188,15 +202,16 @@ export class ResourceLabel extends IconLabel { this.options.fileKind !== FileKind.FILE ); - if (deco && this.options.fileDecorations.colors) { - iconLabelOptions.extraClasses.push(deco.labelClassName); - } - - if (deco && deco.badgeClassName && this.options.fileDecorations.badges) { - iconLabelOptions.badge = { - title: deco.title, - className: deco.badgeClassName, - }; + if (deco) { + if (deco.title) { + iconLabelOptions.title = `${deco.title}, ${iconLabelOptions.title}`; + } + if (this.options.fileDecorations.colors) { + iconLabelOptions.extraClasses.push(deco.labelClassName); + } + if (this.options.fileDecorations.badges) { + iconLabelOptions.extraClasses.push(deco.badgeClassName); + } } } diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 7b4676fee99..4df6b114780 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -11,7 +11,7 @@ import { Part } from 'vs/workbench/browser/part'; import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController'; import { Sash, ISashEvent, IVerticalSashLayoutProvider, IHorizontalSashLayoutProvider, Orientation } from 'vs/base/browser/ui/sash/sash'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IPartService, Position, ILayoutOptions, Parts } from 'vs/workbench/services/part/common/partService'; +import { IPartService, Position, Parts } from 'vs/workbench/services/part/common/partService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; @@ -24,9 +24,11 @@ const MIN_SIDEBAR_PART_WIDTH = 170; const MIN_EDITOR_PART_HEIGHT = 70; const MIN_EDITOR_PART_WIDTH = 220; const MIN_PANEL_PART_HEIGHT = 77; -const DEFAULT_PANEL_HEIGHT_COEFFICIENT = 0.4; +const MIN_PANEL_PART_WIDTH = 300; +const DEFAULT_PANEL_SIZE_COEFFICIENT = 0.4; const HIDE_SIDEBAR_WIDTH_THRESHOLD = 50; const HIDE_PANEL_HEIGHT_THRESHOLD = 50; +const HIDE_PANEL_WIDTH_THRESHOLD = 100; const TITLE_BAR_HEIGHT = 22; const STATUS_BAR_HEIGHT = 22; const ACTIVITY_BAR_WIDTH = 50; @@ -35,7 +37,7 @@ interface PartLayoutInfo { titlebar: { height: number; }; activitybar: { width: number; }; sidebar: { minWidth: number; }; - panel: { minHeight: number; }; + panel: { minHeight: number; minWidth: number; }; editor: { minWidth: number; minHeight: number; }; statusbar: { height: number; }; } @@ -45,7 +47,8 @@ interface PartLayoutInfo { */ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontalSashLayoutProvider { - private static sashXWidthSettingsKey = 'workbench.sidebar.width'; + private static sashXOneWidthSettingsKey = 'workbench.sidebar.width'; + private static sashXTwoWidthSettingsKey = 'workbench.panel.width'; private static sashYHeightSettingsKey = 'workbench.panel.height'; private parent: Builder; @@ -60,19 +63,15 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal private toUnbind: IDisposable[]; private partLayoutInfo: PartLayoutInfo; private workbenchSize: Dimension; - private sashX: Sash; + private sashXOne: Sash; + private sashXTwo: Sash; private sashY: Sash; - private startSidebarWidth: number; - private sidebarWidth: number; + private _sidebarWidth: number; private sidebarHeight: number; private titlebarHeight: number; - private activitybarWidth: number; private statusbarHeight: number; - private startPanelHeight: number; - private panelHeight: number; - private panelHeightBeforeMaximized: number; - private panelMaximized: boolean; - private panelWidth: number; + private _panelHeight: number; + private _panelWidth: number; private layoutEditorGroupsVertically: boolean; // Take parts as an object bag since instatation service does not have typings for constructors with 9+ arguments @@ -107,10 +106,12 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal this.quickopen = quickopen; this.toUnbind = []; this.partLayoutInfo = this.getPartLayoutInfo(); - this.panelHeightBeforeMaximized = 0; - this.panelMaximized = false; - this.sashX = new Sash(this.workbenchContainer.getHTMLElement(), this, { + this.sashXOne = new Sash(this.workbenchContainer.getHTMLElement(), this, { + baseSize: 5 + }); + + this.sashXTwo = new Sash(this.workbenchContainer.getHTMLElement(), this, { baseSize: 5 }); @@ -119,8 +120,9 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal orientation: Orientation.HORIZONTAL }); - this.sidebarWidth = this.storageService.getInteger(WorkbenchLayout.sashXWidthSettingsKey, StorageScope.GLOBAL, -1); - this.panelHeight = this.storageService.getInteger(WorkbenchLayout.sashYHeightSettingsKey, StorageScope.GLOBAL, 0); + this._sidebarWidth = this.storageService.getInteger(WorkbenchLayout.sashXOneWidthSettingsKey, StorageScope.GLOBAL, -1); + this._panelHeight = this.storageService.getInteger(WorkbenchLayout.sashYHeightSettingsKey, StorageScope.GLOBAL, 0); + this._panelWidth = this.storageService.getInteger(WorkbenchLayout.sashXTwoWidthSettingsKey, StorageScope.GLOBAL, 0); this.layoutEditorGroupsVertically = (this.editorGroupService.getGroupOrientation() !== 'horizontal'); @@ -131,6 +133,59 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal this.registerSashListeners(); } + private get activitybarWidth(): number { + if (this.partService.isVisible(Parts.ACTIVITYBAR_PART)) { + return this.partLayoutInfo.activitybar.width; + } + + return 0; + } + + private get panelHeight(): number { + const panelPosition = this.partService.getPanelPosition(); + if (panelPosition === Position.RIGHT) { + return this.sidebarHeight; + } + + return this._panelHeight; + } + + private set panelHeight(value: number) { + const editorCountForHeight = this.editorGroupService.getGroupOrientation() === 'horizontal' ? this.editorGroupService.getStacksModel().groups.length : 1; + const maxPanelHeight = this.sidebarHeight - editorCountForHeight * MIN_EDITOR_PART_HEIGHT; + this._panelHeight = Math.min(maxPanelHeight, Math.max(this.partLayoutInfo.panel.minHeight, value)); + } + + private get panelWidth(): number { + const panelPosition = this.partService.getPanelPosition(); + if (panelPosition === Position.BOTTOM) { + return this.workbenchSize.width - this.activitybarWidth - this.sidebarWidth; + } + + return this._panelWidth; + } + + private set panelWidth(value: number) { + const editorCountForWidth = this.editorGroupService.getGroupOrientation() === 'vertical' ? this.editorGroupService.getStacksModel().groups.length : 1; + const maxPanelWidth = this.workbenchSize.width - editorCountForWidth * MIN_EDITOR_PART_WIDTH - this.sidebarWidth - this.activitybarWidth; + this._panelWidth = Math.min(maxPanelWidth, Math.max(this.partLayoutInfo.panel.minWidth, value)); + } + + private get sidebarWidth(): number { + if (this.partService.isVisible(Parts.SIDEBAR_PART)) { + return this._sidebarWidth; + } + + return 0; + } + + private set sidebarWidth(value: number) { + const editorCountForWidth = this.editorGroupService.getGroupOrientation() === 'vertical' ? this.editorGroupService.getStacksModel().groups.length : 1; + const panelMinWidth = this.partService.getPanelPosition() === Position.RIGHT && this.partService.isVisible(Parts.PANEL_PART) ? MIN_PANEL_PART_WIDTH : 0; + const maxSidebarWidth = this.workbenchSize.width - this.activitybarWidth - editorCountForWidth * MIN_EDITOR_PART_WIDTH - panelMinWidth; + this._sidebarWidth = Math.min(maxSidebarWidth, Math.max(this.partLayoutInfo.sidebar.minWidth, value)); + } + private getPartLayoutInfo(): PartLayoutInfo { return { titlebar: { @@ -143,7 +198,8 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal minWidth: MIN_SIDEBAR_PART_WIDTH }, panel: { - minHeight: MIN_PANEL_PART_HEIGHT + minHeight: MIN_PANEL_PART_HEIGHT, + minWidth: MIN_PANEL_PART_WIDTH }, editor: { minWidth: MIN_EDITOR_PART_WIDTH, @@ -158,22 +214,31 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal private registerSashListeners(): void { let startX: number = 0; let startY: number = 0; + let startXTwo: number = 0; + let startSidebarWidth: number; + let startPanelHeight: number; + let startPanelWidth: number; - this.sashX.addListener('start', (e: ISashEvent) => { - this.startSidebarWidth = this.sidebarWidth; + this.toUnbind.push(this.sashXOne.addListener('start', (e: ISashEvent) => { + startSidebarWidth = this.sidebarWidth; startX = e.startX; - }); + })); - this.sashY.addListener('start', (e: ISashEvent) => { - this.startPanelHeight = this.panelHeight; + this.toUnbind.push(this.sashY.addListener('start', (e: ISashEvent) => { + startPanelHeight = this.panelHeight; startY = e.startY; - }); + })); - this.sashX.addListener('change', (e: ISashEvent) => { + this.toUnbind.push(this.sashXTwo.addListener('start', (e: ISashEvent) => { + startPanelWidth = this.panelWidth; + startXTwo = e.startX; + })); + + this.toUnbind.push(this.sashXOne.addListener('change', (e: ISashEvent) => { let doLayout = false; let sidebarPosition = this.partService.getSideBarPosition(); let isSidebarVisible = this.partService.isVisible(Parts.SIDEBAR_PART); - let newSashWidth = (sidebarPosition === Position.LEFT) ? this.startSidebarWidth + e.currentX - startX : this.startSidebarWidth - e.currentX + startX; + let newSashWidth = (sidebarPosition === Position.LEFT) ? startSidebarWidth + e.currentX - startX : startSidebarWidth - e.currentX + startX; let promise = TPromise.as(null); // Sidebar visible @@ -184,7 +249,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal let dragCompensation = MIN_SIDEBAR_PART_WIDTH - HIDE_SIDEBAR_WIDTH_THRESHOLD; promise = this.partService.setSideBarHidden(true); startX = (sidebarPosition === Position.LEFT) ? Math.max(this.activitybarWidth, e.currentX - dragCompensation) : Math.min(e.currentX + dragCompensation, this.workbenchSize.width - this.activitybarWidth); - this.sidebarWidth = this.startSidebarWidth; // when restoring sidebar, restore to the sidebar width we started from + this.sidebarWidth = startSidebarWidth; // when restoring sidebar, restore to the sidebar width we started from } // Otherwise size the sidebar accordingly @@ -198,7 +263,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal else { if ((sidebarPosition === Position.LEFT && e.currentX - startX >= this.partLayoutInfo.sidebar.minWidth) || (sidebarPosition === Position.RIGHT && startX - e.currentX >= this.partLayoutInfo.sidebar.minWidth)) { - this.startSidebarWidth = this.partLayoutInfo.sidebar.minWidth - (sidebarPosition === Position.LEFT ? e.currentX - startX : startX - e.currentX); + startSidebarWidth = this.partLayoutInfo.sidebar.minWidth - (sidebarPosition === Position.LEFT ? e.currentX - startX : startX - e.currentX); this.sidebarWidth = this.partLayoutInfo.sidebar.minWidth; promise = this.partService.setSideBarHidden(false); } @@ -207,12 +272,12 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal if (doLayout) { promise.done(() => this.layout(), errors.onUnexpectedError); } - }); + })); - this.sashY.addListener('change', (e: ISashEvent) => { + this.toUnbind.push(this.sashY.addListener('change', (e: ISashEvent) => { let doLayout = false; let isPanelVisible = this.partService.isVisible(Parts.PANEL_PART); - let newSashHeight = this.startPanelHeight - (e.currentY - startY); + let newSashHeight = startPanelHeight - (e.currentY - startY); let promise = TPromise.as(null); // Panel visible @@ -223,7 +288,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal let dragCompensation = MIN_PANEL_PART_HEIGHT - HIDE_PANEL_HEIGHT_THRESHOLD; promise = this.partService.setPanelHidden(true); startY = Math.min(this.sidebarHeight - this.statusbarHeight - this.titlebarHeight, e.currentY + dragCompensation); - this.panelHeight = this.startPanelHeight; // when restoring panel, restore to the panel height we started from + this.panelHeight = startPanelHeight; // when restoring panel, restore to the panel height we started from } // Otherwise size the panel accordingly @@ -236,7 +301,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal // Panel hidden else { if (startY - e.currentY >= this.partLayoutInfo.panel.minHeight) { - this.startPanelHeight = 0; + startPanelHeight = 0; this.panelHeight = this.partLayoutInfo.panel.minHeight; promise = this.partService.setPanelHidden(false); } @@ -245,29 +310,77 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal if (doLayout) { promise.done(() => this.layout(), errors.onUnexpectedError); } - }); + })); - this.sashX.addListener('end', () => { - this.storageService.store(WorkbenchLayout.sashXWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL); - }); + this.toUnbind.push(this.sashXTwo.addListener('change', (e: ISashEvent) => { + let doLayout = false; + let isPanelVisible = this.partService.isVisible(Parts.PANEL_PART); + let newSashWidth = startPanelWidth - (e.currentX - startXTwo); + let promise = TPromise.as(null); - this.sashY.addListener('end', () => { + // Panel visible + if (isPanelVisible) { + + // Automatically hide panel when a certain threshold is met + if (newSashWidth + HIDE_PANEL_WIDTH_THRESHOLD < this.partLayoutInfo.panel.minWidth) { + let dragCompensation = MIN_PANEL_PART_WIDTH - HIDE_PANEL_WIDTH_THRESHOLD; + promise = this.partService.setPanelHidden(true); + startXTwo = Math.min(this.workbenchSize.width - this.activitybarWidth, e.currentX + dragCompensation); + this.panelWidth = startPanelWidth; // when restoring panel, restore to the panel height we started from + } + + // Otherwise size the panel accordingly + else { + this.panelWidth = newSashWidth; + doLayout = newSashWidth >= this.partLayoutInfo.panel.minWidth; + } + } + + // Panel hidden + else { + if (startXTwo - e.currentX >= this.partLayoutInfo.panel.minWidth) { + startPanelWidth = 0; + this.panelWidth = this.partLayoutInfo.panel.minWidth; + promise = this.partService.setPanelHidden(false); + } + } + + if (doLayout) { + promise.done(() => this.layout(), errors.onUnexpectedError); + } + })); + + this.toUnbind.push(this.sashXOne.addListener('end', () => { + this.storageService.store(WorkbenchLayout.sashXOneWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL); + })); + + this.toUnbind.push(this.sashY.addListener('end', () => { this.storageService.store(WorkbenchLayout.sashYHeightSettingsKey, this.panelHeight, StorageScope.GLOBAL); - }); + })); - this.sashY.addListener('reset', () => { - this.panelHeight = this.sidebarHeight * DEFAULT_PANEL_HEIGHT_COEFFICIENT; + this.toUnbind.push(this.sashXTwo.addListener('end', () => { + this.storageService.store(WorkbenchLayout.sashXTwoWidthSettingsKey, this.panelWidth, StorageScope.GLOBAL); + })); + + this.toUnbind.push(this.sashY.addListener('reset', () => { + this.panelHeight = this.sidebarHeight * DEFAULT_PANEL_SIZE_COEFFICIENT; this.storageService.store(WorkbenchLayout.sashYHeightSettingsKey, this.panelHeight, StorageScope.GLOBAL); - this.partService.setPanelHidden(false).done(() => this.layout(), errors.onUnexpectedError); - }); + this.layout(); + })); - this.sashX.addListener('reset', () => { + this.toUnbind.push(this.sashXOne.addListener('reset', () => { let activeViewlet = this.viewletService.getActiveViewlet(); let optimalWidth = activeViewlet && activeViewlet.getOptimalWidth(); - this.sidebarWidth = Math.max(MIN_SIDEBAR_PART_WIDTH, optimalWidth || 0); - this.storageService.store(WorkbenchLayout.sashXWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL); + this.sidebarWidth = optimalWidth || 0; + this.storageService.store(WorkbenchLayout.sashXOneWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL); this.partService.setSideBarHidden(false).done(() => this.layout(), errors.onUnexpectedError); - }); + })); + + this.toUnbind.push(this.sashXTwo.addListener('reset', () => { + this.panelWidth = (this.workbenchSize.width - this.sidebarWidth - this.activitybarWidth) * DEFAULT_PANEL_SIZE_COEFFICIENT; + this.storageService.store(WorkbenchLayout.sashXTwoWidthSettingsKey, this.panelWidth, StorageScope.GLOBAL); + this.layout(); + })); } private onEditorsChanged(): void { @@ -299,7 +412,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal } } - public layout(options?: ILayoutOptions): void { + public layout(): void { this.workbenchSize = this.parent.getClientArea(); const isActivityBarHidden = !this.partService.isVisible(Parts.ACTIVITYBAR_PART); @@ -308,16 +421,11 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal const isStatusbarHidden = !this.partService.isVisible(Parts.STATUSBAR_PART); const isSidebarHidden = !this.partService.isVisible(Parts.SIDEBAR_PART); const sidebarPosition = this.partService.getSideBarPosition(); + const panelPosition = this.partService.getPanelPosition(); // Sidebar - let sidebarWidth: number; - if (isSidebarHidden) { - sidebarWidth = 0; - } else if (this.sidebarWidth !== -1) { - sidebarWidth = Math.max(this.partLayoutInfo.sidebar.minWidth, this.sidebarWidth); - } else { - sidebarWidth = this.workbenchSize.width / 5; - this.sidebarWidth = sidebarWidth; + if (this.sidebarWidth === -1) { + this.sidebarWidth = this.workbenchSize.width / 5; } this.statusbarHeight = isStatusbarHidden ? 0 : this.partLayoutInfo.statusbar.height; @@ -325,60 +433,49 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal const previousMaxPanelHeight = this.sidebarHeight - MIN_EDITOR_PART_HEIGHT; this.sidebarHeight = this.workbenchSize.height - this.statusbarHeight - this.titlebarHeight; - let sidebarSize = new Dimension(sidebarWidth, this.sidebarHeight); + let sidebarSize = new Dimension(this.sidebarWidth, this.sidebarHeight); // Activity Bar - this.activitybarWidth = isActivityBarHidden ? 0 : this.partLayoutInfo.activitybar.width; let activityBarSize = new Dimension(this.activitybarWidth, sidebarSize.height); // Panel part let panelHeight: number; + let panelWidth: number; const editorCountForHeight = this.editorGroupService.getGroupOrientation() === 'horizontal' ? this.editorGroupService.getStacksModel().groups.length : 1; const maxPanelHeight = sidebarSize.height - editorCountForHeight * MIN_EDITOR_PART_HEIGHT; + const maxPanelWidth = this.workbenchSize.width - activityBarSize.width - sidebarSize.width - editorCountForHeight * MIN_EDITOR_PART_WIDTH; + if (isPanelHidden) { panelHeight = 0; - } else if (this.panelHeight === previousMaxPanelHeight) { - panelHeight = maxPanelHeight; - } else if (this.panelHeight > 0) { - panelHeight = Math.min(maxPanelHeight, Math.max(this.partLayoutInfo.panel.minHeight, this.panelHeight)); + panelWidth = 0; + } else if (panelPosition === Position.BOTTOM) { + if (this.panelHeight === previousMaxPanelHeight) { + panelHeight = maxPanelHeight; + } else if (this.panelHeight > 0) { + panelHeight = Math.min(maxPanelHeight, Math.max(this.partLayoutInfo.panel.minHeight, this.panelHeight)); + } else { + panelHeight = sidebarSize.height * DEFAULT_PANEL_SIZE_COEFFICIENT; + } + + panelWidth = this.workbenchSize.width - sidebarSize.width - activityBarSize.width; } else { - panelHeight = sidebarSize.height * DEFAULT_PANEL_HEIGHT_COEFFICIENT; + panelHeight = sidebarSize.height; + if (this.panelWidth > 0) { + panelWidth = Math.min(maxPanelWidth, Math.max(this.partLayoutInfo.panel.minWidth, this.panelWidth)); + } else { + panelWidth = (this.workbenchSize.width - activityBarSize.width - sidebarSize.width) * DEFAULT_PANEL_SIZE_COEFFICIENT; + } } - if (options && options.toggleMaximizedPanel) { - panelHeight = this.panelMaximized ? Math.max(this.partLayoutInfo.panel.minHeight, Math.min(this.panelHeightBeforeMaximized, maxPanelHeight)) : maxPanelHeight; - } - this.panelMaximized = panelHeight === maxPanelHeight; - if (panelHeight / maxPanelHeight < 0.7) { - // Remember the previous height only if the panel size is not too large. - // To get a nice minimize effect even if a user dragged the panel sash to maximum. - this.panelHeightBeforeMaximized = panelHeight; - } - const panelDimension = new Dimension(this.workbenchSize.width - sidebarSize.width - activityBarSize.width, panelHeight); - this.panelWidth = panelDimension.width; + const panelDimension = new Dimension(panelWidth, panelHeight); // Editor let editorSize = { width: 0, - height: 0, - remainderLeft: 0, - remainderRight: 0 + height: 0 }; - editorSize.width = panelDimension.width; - editorSize.height = sidebarSize.height - panelDimension.height; - - // Sidebar hidden - if (isSidebarHidden) { - editorSize.width = this.workbenchSize.width - activityBarSize.width; - - if (sidebarPosition === Position.LEFT) { - editorSize.remainderLeft = Math.round((this.workbenchSize.width - editorSize.width + activityBarSize.width) / 2); - editorSize.remainderRight = this.workbenchSize.width - editorSize.width - editorSize.remainderLeft; - } else { - editorSize.remainderRight = Math.round((this.workbenchSize.width - editorSize.width + activityBarSize.width) / 2); - editorSize.remainderLeft = this.workbenchSize.width - editorSize.width - editorSize.remainderRight; - } - } + editorSize.width = this.workbenchSize.width - sidebarSize.width - activityBarSize.width - (panelPosition === Position.RIGHT ? panelDimension.width : 0); + editorSize.height = sidebarSize.height - (panelPosition === Position.BOTTOM ? panelDimension.height : 0); // Assert Sidebar and Editor Size to not overflow let editorMinWidth = this.partLayoutInfo.editor.minWidth; @@ -395,26 +492,35 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal if (editorSize.width < editorMinWidth) { let diff = editorMinWidth - editorSize.width; editorSize.width = editorMinWidth; - panelDimension.width = editorMinWidth; + if (panelPosition === Position.BOTTOM) { + panelDimension.width = editorMinWidth; + } + sidebarSize.width -= diff; sidebarSize.width = Math.max(MIN_SIDEBAR_PART_WIDTH, sidebarSize.width); } - if (editorSize.height < editorMinHeight) { + if (editorSize.height < editorMinHeight && panelPosition === Position.BOTTOM) { let diff = editorMinHeight - editorSize.height; editorSize.height = editorMinHeight; + panelDimension.height -= diff; panelDimension.height = Math.max(MIN_PANEL_PART_HEIGHT, panelDimension.height); } if (!isSidebarHidden) { this.sidebarWidth = sidebarSize.width; - this.storageService.store(WorkbenchLayout.sashXWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL); + this.storageService.store(WorkbenchLayout.sashXOneWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL); } if (!isPanelHidden) { - this.panelHeight = panelDimension.height; - this.storageService.store(WorkbenchLayout.sashYHeightSettingsKey, this.panelHeight, StorageScope.GLOBAL); + if (panelPosition === Position.BOTTOM) { + this.panelHeight = panelDimension.height; + this.storageService.store(WorkbenchLayout.sashYHeightSettingsKey, this.panelHeight, StorageScope.GLOBAL); + } else { + this.panelWidth = panelDimension.width; + this.storageService.store(WorkbenchLayout.sashXTwoWidthSettingsKey, this.panelWidth, StorageScope.GLOBAL); + } } // Workbench @@ -442,16 +548,22 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal this.editor.getContainer().size(editorSize.width, editorSize.height); this.panel.getContainer().size(panelDimension.width, panelDimension.height); - const editorBottom = this.statusbarHeight + panelDimension.height; - if (isSidebarHidden) { - this.editor.getContainer().position(this.titlebarHeight, editorSize.remainderRight, editorBottom, editorSize.remainderLeft); - this.panel.getContainer().position(editorSize.height + this.titlebarHeight, editorSize.remainderRight, this.statusbarHeight, editorSize.remainderLeft); - } else if (sidebarPosition === Position.LEFT) { - this.editor.getContainer().position(this.titlebarHeight, 0, editorBottom, sidebarSize.width + activityBarSize.width); - this.panel.getContainer().position(editorSize.height + this.titlebarHeight, 0, this.statusbarHeight, sidebarSize.width + activityBarSize.width); + if (panelPosition === Position.BOTTOM) { + if (sidebarPosition === Position.LEFT) { + this.editor.getContainer().position(this.titlebarHeight, 0, this.statusbarHeight + panelDimension.height, sidebarSize.width + activityBarSize.width); + this.panel.getContainer().position(editorSize.height + this.titlebarHeight, 0, this.statusbarHeight, sidebarSize.width + activityBarSize.width); + } else { + this.editor.getContainer().position(this.titlebarHeight, sidebarSize.width, this.statusbarHeight + panelDimension.height, 0); + this.panel.getContainer().position(editorSize.height + this.titlebarHeight, sidebarSize.width, this.statusbarHeight, 0); + } } else { - this.editor.getContainer().position(this.titlebarHeight, sidebarSize.width, editorBottom, 0); - this.panel.getContainer().position(editorSize.height + this.titlebarHeight, sidebarSize.width, this.statusbarHeight, 0); + if (sidebarPosition === Position.LEFT) { + this.editor.getContainer().position(this.titlebarHeight, panelDimension.width, this.statusbarHeight, sidebarSize.width + activityBarSize.width); + this.panel.getContainer().position(this.titlebarHeight, 0, this.statusbarHeight, sidebarSize.width + activityBarSize.width + editorSize.width); + } else { + this.editor.getContainer().position(this.titlebarHeight, sidebarSize.width + activityBarSize.width + panelWidth, this.statusbarHeight, 0); + this.panel.getContainer().position(this.titlebarHeight, sidebarSize.width + activityBarSize.width, this.statusbarHeight, editorSize.width); + } } // Activity Bar Part @@ -471,11 +583,11 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal // Sidebar Part this.sidebar.getContainer().size(sidebarSize.width, sidebarSize.height); - + const editorAndPanelWidth = editorSize.width + (panelPosition === Position.RIGHT ? panelWidth : 0); if (sidebarPosition === Position.LEFT) { - this.sidebar.getContainer().position(this.titlebarHeight, editorSize.width, 0, activityBarSize.width); + this.sidebar.getContainer().position(this.titlebarHeight, editorAndPanelWidth, this.statusbarHeight, activityBarSize.width); } else { - this.sidebar.getContainer().position(this.titlebarHeight, null, 0, editorSize.width); + this.sidebar.getContainer().position(this.titlebarHeight, activityBarSize.width, this.statusbarHeight, editorAndPanelWidth); } // Statusbar Part @@ -490,8 +602,16 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal this.quickopen.layout(this.workbenchSize); // Sashes - this.sashX.layout(); - this.sashY.layout(); + this.sashXOne.layout(); + if (panelPosition === Position.BOTTOM) { + this.sashXTwo.hide(); + this.sashY.layout(); + this.sashY.show(); + } else { + this.sashY.hide(); + this.sashXTwo.layout(); + this.sashXTwo.show(); + } // Propagate to Part Layouts this.titlebar.layout(new Dimension(this.workbenchSize.width, this.titlebarHeight)); @@ -509,14 +629,17 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal } public getVerticalSashLeft(sash: Sash): number { - let isSidebarVisible = this.partService.isVisible(Parts.SIDEBAR_PART); let sidebarPosition = this.partService.getSideBarPosition(); + if (sash === this.sashXOne) { - if (sidebarPosition === Position.LEFT) { - return isSidebarVisible ? this.sidebarWidth + this.activitybarWidth : this.activitybarWidth; + if (sidebarPosition === Position.LEFT) { + return this.sidebarWidth + this.activitybarWidth; + } + + return this.workbenchSize.width - this.sidebarWidth - this.activitybarWidth; } - return isSidebarVisible ? this.workbenchSize.width - this.sidebarWidth - this.activitybarWidth : this.workbenchSize.width - this.activitybarWidth; + return this.workbenchSize.width - this.panelWidth - (sidebarPosition === Position.RIGHT ? this.sidebarWidth + this.activitybarWidth : 0); } public getVerticalSashHeight(sash: Sash): number { @@ -529,17 +652,17 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal } public getHorizontalSashLeft(sash: Sash): number { - return this.partService.getSideBarPosition() === Position.LEFT ? this.getVerticalSashLeft(sash) : 0; + if (this.partService.getSideBarPosition() === Position.RIGHT) { + return 0; + } + + return this.sidebarWidth + this.activitybarWidth; } public getHorizontalSashWidth(sash: Sash): number { return this.panelWidth; } - public isPanelMaximized(): boolean { - return this.panelMaximized; - } - // change part size along the main axis public resizePart(part: Parts, sizeChange: number): void { const visibleEditors = this.editorService.getVisibleEditors().length; @@ -547,12 +670,10 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal const sizeChangePxHeight = this.workbenchSize.height * (sizeChange / 100); let doLayout = false; - let newSashSize: number = 0; switch (part) { case Parts.SIDEBAR_PART: - newSashSize = this.sidebarWidth + sizeChangePxWidth; - this.sidebarWidth = Math.max(this.partLayoutInfo.sidebar.minWidth, newSashSize); // Sidebar can not become smaller than MIN_PART_WIDTH + this.sidebarWidth = this.sidebarWidth + sizeChangePxWidth; // Sidebar can not become smaller than MIN_PART_WIDTH if (this.layoutEditorGroupsVertically && (this.workbenchSize.width - this.sidebarWidth < visibleEditors * MIN_EDITOR_PART_WIDTH)) { this.sidebarWidth = (this.workbenchSize.width - visibleEditors * MIN_EDITOR_PART_WIDTH); @@ -561,8 +682,8 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal doLayout = true; break; case Parts.PANEL_PART: - newSashSize = this.panelHeight + sizeChangePxHeight; - this.panelHeight = Math.max(this.partLayoutInfo.panel.minHeight, newSashSize); + this.panelHeight = this.panelHeight + sizeChangePxHeight; + this.panelWidth = this.panelWidth + sizeChangePxWidth; doLayout = true; break; case Parts.EDITOR_PART: diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index a2b0e9c3711..dcb5207ab72 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -7,7 +7,7 @@ import 'vs/css!./media/activityaction'; import DOM = require('vs/base/browser/dom'); -import { EventType as TouchEventType } from 'vs/base/browser/touch'; +import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch'; import { TPromise } from 'vs/base/common/winjs.base'; import { Action } from 'vs/base/common/actions'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -123,7 +123,7 @@ export class GlobalActivityActionItem extends ActivityActionItem { } }); - this.$container.on(TouchEventType.Tap, (e: MouseEvent) => { + this.$container.on(TouchEventType.Tap, (e: GestureEvent) => { DOM.EventHelper.stop(e, true); const event = new StandardMouseEvent(e); diff --git a/src/vs/workbench/browser/parts/compositebar/compositeBar.ts b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts index df4ae59ddff..2a1a311acfe 100644 --- a/src/vs/workbench/browser/parts/compositebar/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts @@ -248,9 +248,9 @@ export class CompositeBar implements ICompositeBar { this.compositeOverflowActionItem = null; } - // Pull out composites that overflow or got hidden - visibleComposites.forEach(compositeId => { - if (compositesToShow.indexOf(compositeId) === -1) { + // Pull out composites that overflow, got hidden or changed position + visibleComposites.forEach((compositeId, index) => { + if (compositesToShow.indexOf(compositeId) !== index) { this.pullComposite(compositeId); } }); @@ -281,7 +281,7 @@ export class CompositeBar implements ICompositeBar { } // Add overflow action as needed - if (visibleCompositesChange && overflows) { + if ((visibleCompositesChange && overflows) || this.compositeSwitcherBar.length() === 0) { this.compositeOverflowAction = this.instantiationService.createInstance(CompositeOverflowActivityAction, () => this.compositeOverflowActionItem.showMenu()); this.compositeOverflowActionItem = this.instantiationService.createInstance( CompositeOverflowActivityActionItem, @@ -403,6 +403,10 @@ export class CompositeBar implements ICompositeBar { } public move(compositeId: string, toCompositeId: string): void { + // Make sure both composites are known to this composite bar + if (this.options.composites.filter(c => c.id === compositeId || c.id === toCompositeId).length !== 2) { + return; + } // Make sure a moved composite gets pinned if (!this.isPinned(compositeId)) { this.pin(compositeId, false /* defer update, we take care of it */); diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index fead4e1c3b3..4dc87d3e133 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -100,7 +100,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService private _onEditorsChanged: Emitter; private _onEditorOpening: Emitter; - private _onEditorsMoved: Emitter; + private _onEditorGroupMoved: Emitter; private _onEditorOpenFail: Emitter; private _onGroupOrientationChanged: Emitter; private _onTabOptionsChanged: Emitter; @@ -134,7 +134,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService this._onEditorsChanged = new Emitter(); this._onEditorOpening = new Emitter(); - this._onEditorsMoved = new Emitter(); + this._onEditorGroupMoved = new Emitter(); this._onEditorOpenFail = new Emitter(); this._onGroupOrientationChanged = new Emitter(); this._onTabOptionsChanged = new Emitter(); @@ -218,7 +218,6 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService if (configuration && configuration.workbench && configuration.workbench.editor) { const editorConfig = configuration.workbench.editor; - // Pin all preview editors of the user chose to disable preview const newPreviewEditors = editorConfig.enablePreview; if (this.tabOptions.previewEditors !== newPreviewEditors && !newPreviewEditors) { @@ -299,8 +298,8 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService return this._onEditorOpening.event; } - public get onEditorsMoved(): Event { - return this._onEditorsMoved.event; + public get onEditorGroupMoved(): Event { + return this._onEditorGroupMoved.event; } public get onEditorOpenFail(): Event { @@ -688,7 +687,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // Emit Editor move event if (rochade !== Rochade.NONE) { - this._onEditorsMoved.fire(); + this._onEditorGroupMoved.fire(); } } @@ -902,7 +901,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService this.focusGroup(fromGroup); // Events - this._onEditorsMoved.fire(); + this._onEditorGroupMoved.fire(); } public moveEditor(input: EditorInput, from: EditorGroup, to: EditorGroup, moveOptions?: IMoveOptions): void; @@ -1377,7 +1376,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // Emitters this._onEditorsChanged.dispose(); this._onEditorOpening.dispose(); - this._onEditorsMoved.dispose(); + this._onEditorGroupMoved.dispose(); this._onEditorOpenFail.dispose(); // Reset Tokens diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index ee23ffe9df8..2ffc03718df 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -33,7 +33,7 @@ import { IEditor as IBaseEditor, IEditorInput } from 'vs/platform/editor/common/ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IQuickOpenService, IPickOpenEntry, IFilePickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; -import { SUPPORTED_ENCODINGS, IFileService, IFilesConfiguration } from 'vs/platform/files/common/files'; +import { SUPPORTED_ENCODINGS, IFileService, IFilesConfiguration, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -785,8 +785,6 @@ export class ChangeModeAction extends Action { public static ID = 'workbench.action.editor.changeLanguageMode'; public static LABEL = nls.localize('changeMode', "Change Language Mode"); - private static FILE_ASSOCIATION_KEY = 'files.associations'; - constructor( actionId: string, actionLabel: string, @@ -964,7 +962,7 @@ export class ChangeModeAction extends Action { TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */).done(() => { this.quickOpenService.pick(picks, { placeHolder: nls.localize('pickLanguageToConfigure', "Select Language Mode to Associate with '{0}'", extension || basename) }).done(language => { if (language) { - const fileAssociationsConfig = this.configurationService.inspect(ChangeModeAction.FILE_ASSOCIATION_KEY); + const fileAssociationsConfig = this.configurationService.inspect(FILES_ASSOCIATIONS_CONFIG); let associationKey: string; if (extension && basename[0] !== '.') { @@ -987,7 +985,7 @@ export class ChangeModeAction extends Action { currentAssociations[associationKey] = language.id; - this.configurationService.updateValue(ChangeModeAction.FILE_ASSOCIATION_KEY, currentAssociations, target); + this.configurationService.updateValue(FILES_ASSOCIATIONS_CONFIG, currentAssociations, target); } }); }); diff --git a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts index 2c08851ca89..0db19a83116 100644 --- a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts @@ -13,10 +13,12 @@ import { TitleControl } from 'vs/workbench/browser/parts/editor/titleControl'; import { ResourceLabel } from 'vs/workbench/browser/labels'; import { Verbosity } from 'vs/platform/editor/common/editor'; import { TAB_ACTIVE_FOREGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND } from 'vs/workbench/common/theme'; +import { EventType as TouchEventType, GestureEvent, Gesture } from 'vs/base/browser/touch'; export class NoTabsTitleControl extends TitleControl { private titleContainer: HTMLElement; private editorLabel: ResourceLabel; + private titleTouchSupport: Gesture; public setContext(group: IEditorGroup): void { super.setContext(group); @@ -29,12 +31,18 @@ export class NoTabsTitleControl extends TitleControl { this.titleContainer = parent; + // Gesture Support + this.titleTouchSupport = new Gesture(this.titleContainer); + // Pin on double click this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, DOM.EventType.DBLCLICK, (e: MouseEvent) => this.onTitleDoubleClick(e))); // Detect mouse click this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, DOM.EventType.CLICK, (e: MouseEvent) => this.onTitleClick(e))); + // Detect touch + this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, TouchEventType.Tap, (e: GestureEvent) => this.onTitleClick(e))); + // Editor Label this.editorLabel = this.instantiationService.createInstance(ResourceLabel, this.titleContainer, void 0); this.toUnbind.push(this.editorLabel); @@ -50,6 +58,7 @@ export class NoTabsTitleControl extends TitleControl { // Context Menu this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, DOM.EventType.CONTEXT_MENU, (e: Event) => this.onContextMenu({ group: this.context, editor: this.context.activeEditor }, e, this.titleContainer))); + this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, TouchEventType.Contextmenu, (e: Event) => this.onContextMenu({ group: this.context, editor: this.context.activeEditor }, e, this.titleContainer))); } private onTitleLabelClick(e: MouseEvent): void { @@ -70,7 +79,7 @@ export class NoTabsTitleControl extends TitleControl { this.editorGroupService.pinEditor(group, group.activeEditor); } - private onTitleClick(e: MouseEvent): void { + private onTitleClick(e: MouseEvent | GestureEvent): void { if (!this.context) { return; } @@ -78,7 +87,7 @@ export class NoTabsTitleControl extends TitleControl { const group = this.context; // Close editor on middle mouse click - if (e.button === 1 /* Middle Button */) { + if (e instanceof MouseEvent && e.button === 1 /* Middle Button */) { this.closeEditorAction.run({ group, editor: group.activeEditor }).done(null, errors.onUnexpectedError); } @@ -150,4 +159,10 @@ export class NoTabsTitleControl extends TitleControl { default: return Verbosity.MEDIUM; } } + + public dispose(): void { + super.dispose(); + + this.titleTouchSupport.dispose(); + } } \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index e598d3383e3..518bf98604d 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -17,6 +17,7 @@ import { ActionRunner, IAction } from 'vs/base/common/actions'; import { Position, IEditorInput, Verbosity, IUntitledResourceInput } from 'vs/platform/editor/common/editor'; import { IEditorGroup, toResource } from 'vs/workbench/common/editor'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { EventType as TouchEventType, GestureEvent, Gesture } from 'vs/base/browser/touch'; import { KeyCode } from 'vs/base/common/keyCodes'; import { ResourceLabel } from 'vs/workbench/browser/labels'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; @@ -503,6 +504,9 @@ export class TabsTitleControl extends TitleControl { tabContainer.setAttribute('role', 'presentation'); // cannot use role "tab" here due to https://github.com/Microsoft/vscode/issues/8659 DOM.addClass(tabContainer, 'tab'); + // Gesture Support + const gestureSupport = new Gesture(tabContainer); + // Tab Editor Label const editorLabel = this.instantiationService.createInstance(ResourceLabel, tabContainer, void 0); this.editorLabels.push(editorLabel); @@ -518,7 +522,7 @@ export class TabsTitleControl extends TitleControl { // Eventing const disposable = this.hookTabListeners(tabContainer, index); - this.tabDisposeables.push(combinedDisposable([disposable, bar, editorLabel])); + this.tabDisposeables.push(combinedDisposable([disposable, bar, editorLabel, gestureSupport])); return tabContainer; } @@ -568,14 +572,36 @@ export class TabsTitleControl extends TitleControl { private hookTabListeners(tab: HTMLElement, index: number): IDisposable { const disposables: IDisposable[] = []; - // Open on Click - disposables.push(DOM.addDisposableListener(tab, DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => { + const handleClickOrTouch = (e: MouseEvent | GestureEvent) => { tab.blur(); + if (e instanceof MouseEvent && e.button !== 0) { + return; // only for left mouse click + } + const { editor, position } = this.toTabContext(index); - if (e.button === 0 /* Left Button */ && !this.isTabActionBar((e.target || e.srcElement) as HTMLElement)) { + if (!this.isTabActionBar((e.target || e.srcElement) as HTMLElement)) { setTimeout(() => this.editorService.openEditor(editor, null, position).done(null, errors.onUnexpectedError)); // timeout to keep focus in editor after mouse up } + }; + + const showContextMenu = (e: Event) => { + DOM.EventHelper.stop(e); + + const { group, editor } = this.toTabContext(index); + + this.onContextMenu({ group, editor }, e, tab); + }; + + // Open on Click + disposables.push(DOM.addDisposableListener(tab, DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => handleClickOrTouch(e))); + + // Open on Touch + disposables.push(DOM.addDisposableListener(tab, TouchEventType.Tap, (e: GestureEvent) => handleClickOrTouch(e))); + + // Touch Scroll Support + disposables.push(DOM.addDisposableListener(tab, TouchEventType.Change, (e: GestureEvent) => { + this.tabsContainer.scrollLeft -= e.translationX; })); // Close on mouse middle click @@ -592,14 +618,15 @@ export class TabsTitleControl extends TitleControl { disposables.push(DOM.addDisposableListener(tab, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { const event = new StandardKeyboardEvent(e); if (event.shiftKey && event.keyCode === KeyCode.F10) { - DOM.EventHelper.stop(e); - - const { group, editor } = this.toTabContext(index); - - this.onContextMenu({ group, editor }, e, tab); + showContextMenu(e); } })); + // Context menu on touch context menu gesture + disposables.push(DOM.addDisposableListener(tab, TouchEventType.Contextmenu, (e: GestureEvent) => { + showContextMenu(e); + })); + // Keyboard accessibility disposables.push(DOM.addDisposableListener(tab, DOM.EventType.KEY_UP, (e: KeyboardEvent) => { const event = new StandardKeyboardEvent(e); diff --git a/src/vs/workbench/browser/parts/panel/media/down-inverse.svg b/src/vs/workbench/browser/parts/panel/media/down-inverse.svg deleted file mode 100755 index d436c7e2735..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/down-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/media/down.svg b/src/vs/workbench/browser/parts/panel/media/down.svg deleted file mode 100755 index 279f3570dc8..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/down.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/media/panel-bottom-inverse.svg b/src/vs/workbench/browser/parts/panel/media/panel-bottom-inverse.svg new file mode 100755 index 00000000000..f9aa418241a --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/panel-bottom-inverse.svg @@ -0,0 +1 @@ +BottomRowOfTwoRows_16x \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/media/panel-bottom.svg b/src/vs/workbench/browser/parts/panel/media/panel-bottom.svg new file mode 100755 index 00000000000..780681f19e5 --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/panel-bottom.svg @@ -0,0 +1 @@ +BottomRowOfTwoRows_16x \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/media/panel-right-inverse.svg b/src/vs/workbench/browser/parts/panel/media/panel-right-inverse.svg new file mode 100755 index 00000000000..428206fb117 --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/panel-right-inverse.svg @@ -0,0 +1 @@ +RightColumnOfTwoColumns_16x \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/media/panel-right.svg b/src/vs/workbench/browser/parts/panel/media/panel-right.svg new file mode 100755 index 00000000000..3b7b808f9ab --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/panel-right.svg @@ -0,0 +1 @@ +RightColumnOfTwoColumns_16x \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css index 042d150e84f..f78ffc0149f 100644 --- a/src/vs/workbench/browser/parts/panel/media/panelpart.css +++ b/src/vs/workbench/browser/parts/panel/media/panelpart.css @@ -13,8 +13,6 @@ } .monaco-workbench > .part.panel .title { - border-top-width: 1px; - border-top-style: solid; padding-right: 0px; height: 35px; display: flex; @@ -22,6 +20,16 @@ justify-content: space-between; } +.monaco-workbench > .part.panel.bottom .title { + border-top-width: 1px; + border-top-style: solid; +} + +.monaco-workbench > .part.panel.right { + border-left-width: 1px; + border-left-style: solid; +} + .monaco-workbench > .part.panel > .composite.title > .title-actions { flex: 0; } @@ -35,7 +43,7 @@ .monaco-workbench > .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more { background: url('ellipsis.svg') center center no-repeat; display: block; - height: 35px; + height: 33px; min-width: 28px; margin-left: 0px; margin-right: 0px; @@ -88,22 +96,22 @@ background: url('close.svg') center center no-repeat; } -.monaco-workbench .maximize-panel-action { - background: url('up.svg') center center no-repeat; +.monaco-workbench .move-panel-to-right { + background: url('panel-right.svg') center center no-repeat; } -.vs-dark .monaco-workbench .maximize-panel-action, -.hc-black .monaco-workbench .maximize-panel-action { - background: url('up-inverse.svg') center center no-repeat; +.vs-dark .monaco-workbench .move-panel-to-right, +.hc-black .monaco-workbench .move-panel-to-right { + background: url('panel-right-inverse.svg') center center no-repeat; } -.monaco-workbench .minimize-panel-action { - background: url('down.svg') center center no-repeat; +.monaco-workbench .move-panel-to-bottom { + background: url('panel-bottom.svg') center center no-repeat; } -.vs-dark .monaco-workbench .minimize-panel-action, -.hc-black .monaco-workbench .minimize-panel-action { - background: url('down-inverse.svg') center center no-repeat; +.vs-dark .monaco-workbench .move-panel-to-bottom, +.hc-black .monaco-workbench .move-panel-to-bottom { + background: url('panel-bottom-inverse.svg') center center no-repeat; } .vs-dark .monaco-workbench .hide-panel-action, diff --git a/src/vs/workbench/browser/parts/panel/media/up-inverse.svg b/src/vs/workbench/browser/parts/panel/media/up-inverse.svg deleted file mode 100755 index 33b7f7c65f6..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/up-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/media/up.svg b/src/vs/workbench/browser/parts/panel/media/up.svg deleted file mode 100755 index 0033a327163..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/up.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index 759cb22cbf6..785d5b550a3 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -12,46 +12,11 @@ import { Action } from 'vs/base/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/actions'; -import { IPanelService, IPanelIdentifier } from 'vs/workbench/services/panel/common/panelService'; -import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { IPartService, Parts, Position } from 'vs/workbench/services/part/common/partService'; import { ActivityAction } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; import { IActivity } from 'vs/workbench/common/activity'; - -export class OpenPanelAction extends Action { - - constructor( - private panel: IPanelIdentifier, - @IKeybindingService private keybindingService: IKeybindingService, - @IPanelService private panelService: IPanelService - ) { - super(panel.id, panel.name); - - this.tooltip = nls.localize('panelActionTooltip', "{0} ({1})", panel.name, this.getKeybindingLabel(panel.commandId)); - } - - public run(event: any): TPromise { - return this.panelService.openPanel(this.panel.id, true).then(() => this.activate()); - } - - public activate(): void { - if (!this.checked) { - this._setChecked(true); - } - } - - public deactivate(): void { - if (this.checked) { - this._setChecked(false); - } - } - - private getKeybindingLabel(id: string): string { - const keys = this.keybindingService.lookupKeybinding(id); - - return keys ? keys.getLabel() : ''; - } -} +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export class ClosePanelAction extends Action { static ID = 'workbench.action.closePanel'; @@ -117,32 +82,36 @@ class FocusPanelAction extends Action { } } -export class ToggleMaximizedPanelAction extends Action { +export class TogglePanelPositionAction extends Action { - public static ID = 'workbench.action.toggleMaximizedPanel'; - public static LABEL = nls.localize('toggleMaximizedPanel', "Toggle Maximized Panel"); - private static MAXIMIZE_LABEL = nls.localize('maximizePanel', "Maximize Panel Size"); - private static RESTORE_LABEL = nls.localize('minimizePanel', "Restore Panel Size"); + public static ID = 'workbench.action.togglePanelPosition'; + public static LABEL = nls.localize('toggledPanelPosition', "Toggle Panel Position"); + private static MOVE_TO_RIGHT_LABEL = nls.localize('moveToRight', "Move to Right"); + private static MOVE_TO_BOTTOM_LABEL = nls.localize('moveToBottom', "Move to Bottom"); + private static panelPositionConfigurationKey = 'workbench.panel.location'; private toDispose: IDisposable[]; constructor( id: string, label: string, - @IPartService private partService: IPartService + @IPartService private partService: IPartService, + @IConfigurationService private configurationService: IConfigurationService + ) { - super(id, label, partService.isPanelMaximized() ? 'minimize-panel-action' : 'maximize-panel-action'); + super(id, label, partService.getPanelPosition() === Position.RIGHT ? 'move-panel-to-bottom' : 'move-panel-to-right'); this.toDispose = []; this.toDispose.push(partService.onEditorLayout(() => { - const maximized = this.partService.isPanelMaximized(); - this.class = maximized ? 'minimize-panel-action' : 'maximize-panel-action'; - this.label = maximized ? ToggleMaximizedPanelAction.RESTORE_LABEL : ToggleMaximizedPanelAction.MAXIMIZE_LABEL; + const positionRight = this.partService.getPanelPosition() === Position.RIGHT; + this.class = positionRight ? 'move-panel-to-bottom' : 'move-panel-to-right'; + this.label = positionRight ? TogglePanelPositionAction.MOVE_TO_BOTTOM_LABEL : TogglePanelPositionAction.MOVE_TO_RIGHT_LABEL; })); } public run(): TPromise { - // Show panel - return this.partService.setPanelHidden(false) - .then(() => this.partService.toggleMaximizedPanel()); + const position = this.partService.getPanelPosition(); + const newPositionValue = (position === Position.BOTTOM) ? 'right' : 'bottom'; + + return this.configurationService.updateValue(TogglePanelPositionAction.panelPositionConfigurationKey, newPositionValue, ConfigurationTarget.USER); } public dispose(): void { @@ -151,6 +120,10 @@ export class ToggleMaximizedPanelAction extends Action { } } +class ToggleMaximizedPanelAction extends TogglePanelPositionAction { + public static ID = 'workbench.action.toggleMaximizedPanel'; +} + export class PanelActivityAction extends ActivityAction { constructor( @@ -161,12 +134,13 @@ export class PanelActivityAction extends ActivityAction { } public run(event: any): TPromise { - return this.panelService.openPanel(this.activity.id, true).then(() => this.activate()); + return this.panelService.openPanel(this.activity.id, true).then(() => this.activate());; } } const actionRegistry = Registry.as(WorkbenchExtensions.WorkbenchActions); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TogglePanelAction, TogglePanelAction.ID, TogglePanelAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_J }), 'View: Toggle Panel', nls.localize('view', "View")); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPanelAction, FocusPanelAction.ID, FocusPanelAction.LABEL), 'View: Focus into Panel', nls.localize('view', "View")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, ToggleMaximizedPanelAction.LABEL), 'View: Toggle Maximized Panel', nls.localize('view', "View")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL), 'View: Close Panel', nls.localize('view', "View")); \ No newline at end of file +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL), 'View: Close Panel', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TogglePanelPositionAction, TogglePanelPositionAction.ID, TogglePanelPositionAction.LABEL), 'View: Toggle Panel Position', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, undefined), 'View: Toggle Panel Position', nls.localize('view', "View")); diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index 66485230cdf..b5d4331937a 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -22,7 +22,7 @@ import { IMessageService } from 'vs/platform/message/common/message'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ClosePanelAction, ToggleMaximizedPanelAction, PanelActivityAction, OpenPanelAction } from 'vs/workbench/browser/parts/panel/panelActions'; +import { ClosePanelAction, TogglePanelPositionAction, PanelActivityAction } from 'vs/workbench/browser/parts/panel/panelActions'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme'; import { activeContrastBorder, focusBorder, contrastBorder, editorBackground, badgeBackground, badgeForeground } from 'vs/platform/theme/common/colorRegistry'; @@ -36,6 +36,7 @@ export class PanelPart extends CompositePart implements IPanelService { public static activePanelSettingsKey = 'workbench.panelpart.activepanelid'; private static readonly PINNED_PANELS = 'workbench.panel.pinnedPanels'; + private static readonly MIN_COMPOSITE_BAR_WIDTH = 50; public _serviceBrand: any; @@ -82,7 +83,7 @@ export class PanelPart extends CompositePart implements IPanelService { openComposite: (compositeId: string) => this.openPanel(compositeId, true), getActivityAction: (compositeId: string) => this.instantiationService.createInstance(PanelActivityAction, this.getPanel(compositeId)), getCompositePinnedAction: (compositeId: string) => new ToggleCompositePinnedAction(this.getPanel(compositeId), this.compositeBar), - getOnCompositeClickAction: (compositeId: string) => this.instantiationService.createInstance(OpenPanelAction, this.getPanel(compositeId)), + getOnCompositeClickAction: (compositeId: string) => this.instantiationService.createInstance(PanelActivityAction, this.getPanel(compositeId)), getDefaultCompositeId: () => Registry.as(PanelExtensions.Panels).getDefaultPanelId(), hidePart: () => this.partService.setPanelHidden(true), overflowActionSize: 28, @@ -120,11 +121,12 @@ export class PanelPart extends CompositePart implements IPanelService { return this._onDidCompositeClose.event; } - protected updateStyles(): void { + public updateStyles(): void { super.updateStyles(); const container = this.getContainer(); container.style('background-color', this.getColor(PANEL_BACKGROUND)); + container.style('border-left-color', this.getColor(PANEL_BORDER) || this.getColor(contrastBorder)); const title = this.getTitleArea(); title.style('border-top-color', this.getColor(PANEL_BORDER) || this.getColor(contrastBorder)); @@ -175,7 +177,7 @@ export class PanelPart extends CompositePart implements IPanelService { protected getActions(): IAction[] { return [ - this.instantiationService.createInstance(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, ToggleMaximizedPanelAction.LABEL), + this.instantiationService.createInstance(TogglePanelPositionAction, TogglePanelPositionAction.ID, TogglePanelPositionAction.LABEL), this.instantiationService.createInstance(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL) ]; } @@ -224,7 +226,7 @@ export class PanelPart extends CompositePart implements IPanelService { let availableWidth = this.dimension.width - 8; // take padding into account if (this.toolBar) { // adjust height for global actions showing - availableWidth -= this.toolBar.getContainer().getHTMLElement().offsetWidth; + availableWidth = Math.max(PanelPart.MIN_COMPOSITE_BAR_WIDTH, availableWidth - this.toolBar.getContainer().getHTMLElement().offsetWidth); } this.compositeBar.layout(new Dimension(availableWidth, this.dimension.height)); } diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 3a666cfbc1c..b9efab5784e 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -36,7 +36,7 @@ import { Component } from 'vs/workbench/common/component'; import Event, { Emitter } from 'vs/base/common/event'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { KeyMod } from 'vs/base/common/keyCodes'; -import { QuickOpenHandler, QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions, EditorQuickOpenEntry, IWorkbenchQuickOpenConfiguration } from 'vs/workbench/browser/quickopen'; +import { QuickOpenHandler, QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions, EditorQuickOpenEntry, CLOSE_ON_FOCUS_LOST_CONFIG } from 'vs/workbench/browser/quickopen'; import errors = require('vs/base/common/errors'); import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPickOpenEntry, IFilePickOpenEntry, IInputOptions, IQuickOpenService, IPickOptions, IShowOptions, IPickOpenItem } from 'vs/platform/quickOpen/common/quickOpen'; @@ -131,22 +131,22 @@ export class QuickOpenController extends Component implements IQuickOpenService this._onShow = new Emitter(); this._onHide = new Emitter(); - this.updateConfiguration(this.configurationService.getConfiguration()); + this.updateConfiguration(); this.registerListeners(); } private registerListeners(): void { - this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.updateConfiguration(this.configurationService.getConfiguration()))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.updateConfiguration())); this.toUnbind.push(this.partService.onTitleBarVisibilityChange(() => this.positionQuickOpenWidget())); this.toUnbind.push(browser.onDidChangeZoomLevel(() => this.positionQuickOpenWidget())); } - private updateConfiguration(settings: IWorkbenchQuickOpenConfiguration): void { + private updateConfiguration(): void { if (this.environmentService.args['sticky-quickopen']) { this.closeOnFocusLost = false; } else { - this.closeOnFocusLost = settings.workbench && settings.workbench.quickOpen && settings.workbench.quickOpen.closeOnFocusLost; + this.closeOnFocusLost = this.configurationService.getValue(CLOSE_ON_FOCUS_LOST_CONFIG); } } diff --git a/src/vs/workbench/browser/parts/views/panelViewlet.ts b/src/vs/workbench/browser/parts/views/panelViewlet.ts index 4d973f2a29d..e7d8a379b9b 100644 --- a/src/vs/workbench/browser/parts/views/panelViewlet.ts +++ b/src/vs/workbench/browser/parts/views/panelViewlet.ts @@ -138,6 +138,10 @@ export class PanelViewlet extends Viewlet { private panelItems: IViewletPanelItem[] = []; private panelview: PanelView; + get onDidSashChange(): Event { + return this.panelview.onDidSashChange; + } + protected get length(): number { return this.panelItems.length; } diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index 96ef5e0c9de..1ab6bf3856a 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -234,8 +234,9 @@ export class ViewsViewlet extends PanelViewlet { } async create(parent: Builder): TPromise { - super.create(parent); + await super.create(parent); + this._register(this.onDidSashChange(() => this.updateAllViewsSizes())); this._register(ViewsRegistry.onViewsRegistered(this.onViewsRegistered, this)); this._register(ViewsRegistry.onViewsDeregistered(this.onViewsDeregistered, this)); this._register(this.contextKeyService.onDidChangeContext(keys => this.onContextChanged(keys))); @@ -276,10 +277,7 @@ export class ViewsViewlet extends PanelViewlet { this._resizePanels(); } - for (const view of this.viewsViewletPanels) { - let viewState = this.updateViewStateSize(view); - this.viewsStates.set(view.id, viewState); - } + this.updateAllViewsSizes(); } getOptimalWidth(): number { @@ -419,6 +417,13 @@ export class ViewsViewlet extends PanelViewlet { return TPromise.as([]); } + private updateAllViewsSizes(): void { + for (const view of this.viewsViewletPanels) { + let viewState = this.updateViewStateSize(view); + this.viewsStates.set(view.id, viewState); + } + } + private _resizePanels(): void { if (!this.didLayout) { return; diff --git a/src/vs/workbench/browser/quickopen.ts b/src/vs/workbench/browser/quickopen.ts index 07d0289da9e..8c7cf7bea1e 100644 --- a/src/vs/workbench/browser/quickopen.ts +++ b/src/vs/workbench/browser/quickopen.ts @@ -22,11 +22,10 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IConstructorSignature0, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +export const CLOSE_ON_FOCUS_LOST_CONFIG = 'workbench.quickOpen.closeOnFocusLost'; + export interface IWorkbenchQuickOpenConfiguration { workbench: { - quickOpen: { - closeOnFocusLost: boolean; - }, commandPalette: { history: number; preserveInput: boolean; diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 2df8fc14a2d..6ec676c9306 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -804,6 +804,8 @@ export const EditorOpenPositioning = { LAST: 'last' }; +export const OPEN_POSITIONING_CONFIG = 'workbench.editor.openPositioning'; + export interface IWorkbenchEditorConfiguration { /* __GDPR__FRAGMENT__ "IWorkbenchEditorConfiguration" : { diff --git a/src/vs/workbench/common/editor/editorStacksModel.ts b/src/vs/workbench/common/editor/editorStacksModel.ts index 148a01d2c41..20f09e32702 100644 --- a/src/vs/workbench/common/editor/editorStacksModel.ts +++ b/src/vs/workbench/common/editor/editorStacksModel.ts @@ -6,11 +6,11 @@ 'use strict'; import Event, { Emitter, once } from 'vs/base/common/event'; -import { Extensions, IEditorInputFactoryRegistry, EditorInput, toResource, IEditorStacksModel, IEditorGroup, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, IStacksModelChangeEvent, IWorkbenchEditorConfiguration, EditorOpenPositioning, SideBySideEditorInput } from 'vs/workbench/common/editor'; +import { Extensions, IEditorInputFactoryRegistry, EditorInput, toResource, IEditorStacksModel, IEditorGroup, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, IStacksModelChangeEvent, EditorOpenPositioning, SideBySideEditorInput, OPEN_POSITIONING_CONFIG } from 'vs/workbench/common/editor'; import URI from 'vs/base/common/uri'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -84,7 +84,7 @@ export class EditorGroup implements IEditorGroup { this.mru = []; this.toDispose = []; this.mapResourceToEditorCount = new ResourceMap(); - this.onConfigurationUpdated(configurationService.getConfiguration()); + this.onConfigurationUpdated(); this._onEditorActivated = new Emitter(); this._onEditorOpened = new Emitter(); @@ -110,13 +110,11 @@ export class EditorGroup implements IEditorGroup { } private registerListeners(): void { - this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e))); } - private onConfigurationUpdated(config: IWorkbenchEditorConfiguration): void { - if (config && config.workbench && config.workbench.editor) { - this.editorOpenPositioning = config.workbench.editor.openPositioning; - } + private onConfigurationUpdated(event?: IConfigurationChangeEvent): void { + this.editorOpenPositioning = this.configurationService.getValue(OPEN_POSITIONING_CONFIG); } public get id(): GroupIdentifier { diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts index 9ffaef6c14f..3a4d1381e61 100644 --- a/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts @@ -11,8 +11,8 @@ import paths = require('vs/base/common/paths'); import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ParsedExpression, IExpression } from 'vs/base/common/glob'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; +import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob'; import { basename } from 'vs/base/common/paths'; import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -73,7 +73,7 @@ export class ResourceGlobMatcher { constructor( private globFn: (root?: URI) => IExpression, - private parseFn: (expression: IExpression) => ParsedExpression, + private shouldUpdate: (event: IConfigurationChangeEvent) => boolean, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IConfigurationService private configurationService: IConfigurationService ) { @@ -95,7 +95,11 @@ export class ResourceGlobMatcher { } private registerListeners(): void { - this.toUnbind.push(this.configurationService.onDidChangeConfiguration(() => this.updateExcludes(true))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => { + if (this.shouldUpdate(e)) { + this.updateExcludes(true); + } + })); this.toUnbind.push(this.contextService.onDidChangeWorkspaceFolders(() => this.updateExcludes(true))); } @@ -108,7 +112,7 @@ export class ResourceGlobMatcher { if (!this.mapRootToExpressionConfig.has(folder.uri.toString()) || !objects.equals(this.mapRootToExpressionConfig.get(folder.uri.toString()), rootExcludes)) { changed = true; - this.mapRootToParsedExpression.set(folder.uri.toString(), this.parseFn(rootExcludes)); + this.mapRootToParsedExpression.set(folder.uri.toString(), parse(rootExcludes)); this.mapRootToExpressionConfig.set(folder.uri.toString(), objects.clone(rootExcludes)); } }); @@ -132,7 +136,7 @@ export class ResourceGlobMatcher { if (!this.mapRootToExpressionConfig.has(ResourceGlobMatcher.NO_ROOT) || !objects.equals(this.mapRootToExpressionConfig.get(ResourceGlobMatcher.NO_ROOT), globalExcludes)) { changed = true; - this.mapRootToParsedExpression.set(ResourceGlobMatcher.NO_ROOT, this.parseFn(globalExcludes)); + this.mapRootToParsedExpression.set(ResourceGlobMatcher.NO_ROOT, parse(globalExcludes)); this.mapRootToExpressionConfig.set(ResourceGlobMatcher.NO_ROOT, objects.clone(globalExcludes)); } diff --git a/src/vs/workbench/electron-browser/commands.ts b/src/vs/workbench/electron-browser/commands.ts index fa35f6a9600..94b80b9c37c 100644 --- a/src/vs/workbench/electron-browser/commands.ts +++ b/src/vs/workbench/electron-browser/commands.ts @@ -20,6 +20,7 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import URI from 'vs/base/common/uri'; import { IEditorOptions, Position as EditorPosition } from 'vs/platform/editor/common/editor'; +import { openFolderCommand, openFileInNewWindowCommand, openFileFolderInNewWindowCommand, openFolderInNewWindowCommand, openWorkspaceInNewWindowCommand } from 'vs/workbench/browser/actions/workspaceActions'; // --- List Commands @@ -420,4 +421,11 @@ export function registerCommands(): void { return void 0; }); }); + + CommandsRegistry.registerCommand('_files.pickFolderAndOpen', openFolderCommand); + + CommandsRegistry.registerCommand('workbench.action.files.openFileInNewWindow', openFileInNewWindowCommand); + CommandsRegistry.registerCommand('workbench.action.files.openFolderInNewWindow', openFolderInNewWindowCommand); + CommandsRegistry.registerCommand('workbench.action.files.openFileFolderInNewWindow', openFileFolderInNewWindowCommand); + CommandsRegistry.registerCommand('workbench.action.openWorkspaceInNewWindow', openWorkspaceInNewWindowCommand); } diff --git a/src/vs/workbench/electron-browser/main.contribution.ts b/src/vs/workbench/electron-browser/main.contribution.ts index f56ae229cbe..fd40c95e056 100644 --- a/src/vs/workbench/electron-browser/main.contribution.ts +++ b/src/vs/workbench/electron-browser/main.contribution.ts @@ -18,7 +18,7 @@ import { CloseEditorAction, KeybindingsReferenceAction, OpenDocumentationUrlActi import { MessagesVisibleContext } from 'vs/workbench/electron-browser/workbench'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { registerCommands } from 'vs/workbench/electron-browser/commands'; -import { AddRootFolderAction, GlobalRemoveRootFolderAction, OpenWorkspaceAction, SaveWorkspaceAsAction, OpenWorkspaceConfigFileAction, OpenFolderAsWorkspaceInNewWindowAction } from 'vs/workbench/browser/actions/workspaceActions'; +import { AddRootFolderAction, GlobalRemoveRootFolderAction, OpenWorkspaceAction, SaveWorkspaceAsAction, OpenWorkspaceConfigFileAction, OpenFolderAsWorkspaceInNewWindowAction, OpenFileFolderAction, OpenFileAction, OpenFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { inQuickOpenContext, getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -35,7 +35,16 @@ workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NewWin workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseCurrentWindowAction, CloseCurrentWindowAction.ID, CloseCurrentWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W }), 'Close Window'); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SwitchWindow, SwitchWindow.ID, SwitchWindow.LABEL, { primary: null, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_W } }), 'Switch Window...'); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickSwitchWindow, QuickSwitchWindow.ID, QuickSwitchWindow.LABEL), 'Quick Switch Window...'); + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory); + +if (isMacintosh) { + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', fileCategory); +} else { + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory); + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', fileCategory); +} + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'File: Close Workspace', fileCategory); if (!!product.reportIssueUrl) { workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportIssueAction, ReportIssueAction.ID, ReportIssueAction.LABEL), 'Help: Report Issues', helpCategory); @@ -132,9 +141,9 @@ let workbenchProperties: { [path: string]: IJSONSchema; } = { 'type': 'string', 'enum': ['default', 'short', 'medium', 'long'], 'enumDescriptions': [ - nls.localize('workbench.editor.labelFormat.default', "Show the name of the file. When tabs are enabled and two files have the same name in one group the distinguinshing sections of each file's path are added. When tabs are disabled, the path relative to workspace root is shown if the editor is active."), + nls.localize('workbench.editor.labelFormat.default', "Show the name of the file. When tabs are enabled and two files have the same name in one group the distinguinshing sections of each file's path are added. When tabs are disabled, the path relative to the workspace folder is shown if the editor is active."), nls.localize('workbench.editor.labelFormat.short', "Show the name of the file followed by it's directory name."), - nls.localize('workbench.editor.labelFormat.medium', "Show the name of the file followed by it's path relative to the workspace root."), + nls.localize('workbench.editor.labelFormat.medium', "Show the name of the file followed by it's path relative to the workspace folder."), nls.localize('workbench.editor.labelFormat.long', "Show the name of the file followed by it's absolute path.") ], 'default': 'default', @@ -170,7 +179,7 @@ let workbenchProperties: { [path: string]: IJSONSchema; } = { 'type': 'string', 'enum': ['left', 'right', 'first', 'last'], 'default': 'right', - 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorOpenPositioning' }, "Controls where editors open. Select 'left' or 'right' to open editors to the left or right of the current active one. Select 'first' or 'last' to open editors independently from the currently active one.") + 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorOpenPositioning' }, "Controls where editors open. Select 'left' or 'right' to open editors to the left or right of the currently active one. Select 'first' or 'last' to open editors independently from the currently active one.") }, 'workbench.editor.revealIfOpen': { 'type': 'boolean', @@ -197,12 +206,33 @@ let workbenchProperties: { [path: string]: IJSONSchema; } = { 'description': nls.localize('openDefaultSettings', "Controls if opening settings also opens an editor showing all default settings."), 'default': true }, + 'workbench.settings.experimentalFuzzySearchEndpoint': { + 'type': 'string', + 'description': nls.localize('experimentalFuzzySearchEndpoint', "Indicates the endpoint to use for the experimental settings search."), + 'default': '' + }, + 'workbench.settings.experimentalFuzzySearchKey': { + 'type': 'string', + 'description': nls.localize('experimentalFuzzySearchKey', "Indicates the key to use for the experimental settings search."), + 'default': '' + }, + 'workbench.settings.experimentalFuzzySearchBoost': { + 'type': 'number', + 'description': 'Indicates the amount to boost the "literal" component of the query. Temporary.', + 'default': 10 + }, 'workbench.sideBar.location': { 'type': 'string', 'enum': ['left', 'right'], 'default': 'left', 'description': nls.localize('sideBarLocation', "Controls the location of the sidebar. It can either show on the left or right of the workbench.") }, + 'workbench.panel.location': { + 'type': 'string', + 'enum': ['bottom', 'right'], + 'default': 'bottom', + 'description': nls.localize('panelLocation', "Controls the location of the panel. It can either show on the bottom or right of the workbench.") + }, 'workbench.statusBar.visible': { 'type': 'boolean', 'default': true, diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index aeefa814e9f..b39bda8dcb1 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -39,14 +39,14 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; import { Themable } from 'vs/workbench/common/theme'; import { ipcRenderer as ipc, webFrame } from 'electron'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { ConfigurationTarget, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; const TextInputActions: IAction[] = [ new Action('undo', nls.localize('undo', "Undo"), null, true, () => document.execCommand('undo') && TPromise.as(true)), @@ -261,7 +261,11 @@ export class ElectronWindow extends Themable { } } - private onDidUpdateConfiguration(e): void { + private onDidUpdateConfiguration(event: IConfigurationChangeEvent): void { + if (!event.affectsConfiguration('window.zoomLevel')) { + return; + } + const windowConfig: IWindowsConfiguration = this.configurationService.getConfiguration(); let newZoomLevel = 0; @@ -398,21 +402,7 @@ export class ElectronWindow extends Themable { private onAddFolders(request: IAddFoldersRequest): void { const foldersToAdd = request.foldersToAdd.map(folderToAdd => URI.file(folderToAdd.filePath)); - // Workspace: just add to workspace config - if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { - this.contextService.addFolders(foldersToAdd).done(null, errors.onUnexpectedError); - } - - // Single folder or no workspace: create workspace and open - else { - const workspaceFolders: URI[] = [...this.contextService.getWorkspace().folders.map(folder => folder.uri)]; - - // Fill in remaining ones from request - workspaceFolders.push(...request.foldersToAdd.map(folderToAdd => URI.file(folderToAdd.filePath))); - - // Create workspace and open (ensure no duplicates) - this.workspaceEditingService.createAndEnterWorkspace(arrays.distinct(workspaceFolders.map(folder => folder.fsPath), folder => platform.isLinux ? folder : folder.toLowerCase())); - } + this.workspaceEditingService.addFolders(foldersToAdd).done(null, errors.onUnexpectedError); } private onOpenFiles(request: IOpenFileRequest): void { diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 5b34ea90179..c3a5b7828d6 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -15,7 +15,6 @@ import DOM = require('vs/base/browser/dom'); import { Builder, $ } from 'vs/base/browser/builder'; import { Delayer, RunOnceScheduler } from 'vs/base/common/async'; import * as browser from 'vs/base/browser/browser'; -import assert = require('vs/base/common/assert'); import { StopWatch } from 'vs/base/common/stopwatch'; import { startTimer } from 'vs/base/node/startupTimers'; import errors = require('vs/base/common/errors'); @@ -39,7 +38,7 @@ import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbe import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel'; import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController'; import { getServices } from 'vs/platform/instantiation/common/extensions'; -import { Position, Parts, IPartService, ILayoutOptions } from 'vs/workbench/services/part/common/partService'; +import { Position, Parts, IPartService } from 'vs/workbench/services/part/common/partService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ContextMenuService } from 'vs/workbench/services/contextview/electron-browser/contextmenuService'; @@ -102,6 +101,7 @@ import URI from 'vs/base/common/uri'; export const MessagesVisibleContext = new RawContextKey('globalMessageVisible', false); export const EditorsVisibleContext = new RawContextKey('editorIsOpen', false); export const InZenModeContext = new RawContextKey('inZenMode', false); +export const SidebarVisibleContext = new RawContextKey('sidebarVisible', false); export const NoEditorsVisibleContext: ContextKeyExpr = EditorsVisibleContext.toNegated(); interface WorkbenchParams { @@ -152,6 +152,7 @@ export class Workbench implements IPartService { private static zenModeActiveSettingKey = 'workbench.zenmode.active'; private static sidebarPositionConfigurationKey = 'workbench.sideBar.location'; + private static panelPositionConfigurationKey = 'workbench.panel.location'; private static statusbarVisibleConfigurationKey = 'workbench.statusBar.visible'; private static activityBarVisibleConfigurationKey = 'workbench.activityBar.visible'; @@ -194,12 +195,14 @@ export class Workbench implements IPartService { private statusBarHidden: boolean; private activityBarHidden: boolean; private sideBarPosition: Position; + private panelPosition: Position; private panelHidden: boolean; private editorBackgroundDelayer: Delayer; private closeEmptyWindowScheduler: RunOnceScheduler; private messagesVisibleContext: IContextKey; private editorsVisibleContext: IContextKey; private inZenMode: IContextKey; + private sideBarVisibleContext: IContextKey; private hasFilesToCreateOpenOrDiff: boolean; private fontAliasing: string; private zenMode: { @@ -265,9 +268,6 @@ export class Workbench implements IPartService { * once. Use the shutdown function to free up resources created by the workbench on startup. */ public startup(callbacks?: IWorkbenchCallbacks): void { - assert.ok(!this.workbenchStarted, 'Can not start a workbench that was already started'); - assert.ok(!this.workbenchShutdown, 'Can not start a workbench that was shutdown'); - try { this.workbenchStarted = true; this.callbacks = callbacks; @@ -288,6 +288,7 @@ export class Workbench implements IPartService { this.messagesVisibleContext = MessagesVisibleContext.bindTo(this.contextKeyService); this.editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService); this.inZenMode = InZenModeContext.bindTo(this.contextKeyService); + this.sideBarVisibleContext = SidebarVisibleContext.bindTo(this.contextKeyService); // Register Listeners this.registerListeners(); @@ -308,6 +309,7 @@ export class Workbench implements IPartService { let viewletRestoreStopWatch: StopWatch; let viewletIdToRestore: string; if (!this.sideBarHidden) { + this.sideBarVisibleContext.set(true); if (this.shouldRestoreLastOpenedViewlet()) { viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE); @@ -643,6 +645,10 @@ export class Workbench implements IPartService { const sideBarPosition = this.configurationService.getValue(Workbench.sidebarPositionConfigurationKey); this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT; + // Panel position + const panelPosition = this.configurationService.getValue(Workbench.panelPositionConfigurationKey); + this.panelPosition = (panelPosition === 'right') ? Position.RIGHT : Position.BOTTOM; + // Statusbar visibility const statusBarVisible = this.configurationService.getValue(Workbench.statusbarVisibleConfigurationKey); this.statusBarHidden = !statusBarVisible; @@ -790,6 +796,7 @@ export class Workbench implements IPartService { public setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise { this.sideBarHidden = hidden; + this.sideBarVisibleContext.set(!hidden); // Adjust CSS if (hidden) { @@ -885,14 +892,6 @@ export class Workbench implements IPartService { }); } - public toggleMaximizedPanel(): void { - this.workbenchLayout.layout({ toggleMaximizedPanel: true }); - } - - public isPanelMaximized(): boolean { - return this.workbenchLayout.isPanelMaximized(); - } - public getSideBarPosition(): Position { return this.sideBarPosition; } @@ -920,6 +919,30 @@ export class Workbench implements IPartService { this.workbenchLayout.layout(); } + public getPanelPosition(): Position { + return this.panelPosition; + } + + private setPanelPosition(position: Position): void { + if (this.panelHidden) { + this.setPanelHidden(false, true /* Skip Layout */).done(undefined, errors.onUnexpectedError); + } + + const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right'; + const oldPositionValue = (this.panelPosition === Position.BOTTOM) ? 'bottom' : 'right'; + this.panelPosition = position; + + // Adjust CSS + this.panelPart.getContainer().removeClass(oldPositionValue); + this.panelPart.getContainer().addClass(newPositionValue); + + // Update Styles + this.panelPart.updateStyles(); + + // Layout + this.workbenchLayout.layout(); + } + private setFontAliasing(aliasing: string) { this.fontAliasing = aliasing; @@ -939,9 +962,9 @@ export class Workbench implements IPartService { * Asks the workbench and all its UI components inside to lay out according to * the containers dimension the workbench is living in. */ - public layout(options?: ILayoutOptions): void { + public layout(): void { if (this.isStarted()) { - this.workbenchLayout.layout(options); + this.workbenchLayout.layout(); } } @@ -1075,6 +1098,12 @@ export class Workbench implements IPartService { this.setSideBarPosition(newSidebarPosition); } + const newPanelPositionValue = this.configurationService.getValue(Workbench.panelPositionConfigurationKey); + const newPanelPosition = (newPanelPositionValue === 'right') ? Position.RIGHT : Position.BOTTOM; + if (newPanelPosition !== this.getPanelPosition()) { + this.setPanelPosition(newPanelPosition); + } + const fontAliasing = this.configurationService.getValue(Workbench.fontAliasingConfigurationKey); if (fontAliasing !== this.fontAliasing) { this.setFontAliasing(fontAliasing); @@ -1189,7 +1218,7 @@ export class Workbench implements IPartService { private createPanelPart(): void { const panelPartContainer = $(this.workbench) .div({ - 'class': ['part', 'panel'], + 'class': ['part', 'panel', this.panelPosition === Position.BOTTOM ? 'bottom' : 'right'], id: Identifiers.PANEL_PART, role: 'complementary' }); @@ -1219,26 +1248,18 @@ export class Workbench implements IPartService { } public getEditorPart(): EditorPart { - assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.'); - return this.editorPart; } public getSidebarPart(): SidebarPart { - assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.'); - return this.sidebarPart; } public getPanelPart(): PanelPart { - assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.'); - return this.panelPart; } public getInstantiationService(): IInstantiationService { - assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.'); - return this.instantiationService; } @@ -1260,6 +1281,7 @@ export class Workbench implements IPartService { public toggleZenMode(skipLayout?: boolean): void { this.zenMode.active = !this.zenMode.active; + // Check if zen mode transitioned to full screen and if now we are out of zen mode -> we need to go out of full screen let toggleFullScreen = false; if (this.zenMode.active) { @@ -1274,9 +1296,11 @@ export class Workbench implements IPartService { if (config.hideActivityBar) { this.setActivityBarHidden(true, true); } + if (config.hideStatusBar) { this.setStatusBarHidden(true, true); } + if (config.hideTabs) { this.editorPart.hideTabs(true); } @@ -1284,9 +1308,11 @@ export class Workbench implements IPartService { if (this.zenMode.wasPanelVisible) { this.setPanelHidden(false, true).done(undefined, errors.onUnexpectedError); } + if (this.zenMode.wasSideBarVisible) { this.setSideBarHidden(false, true).done(undefined, errors.onUnexpectedError); } + // Status bar and activity bar visibility come from settings -> update their visibility. this.onDidUpdateConfiguration(true); this.editorPart.hideTabs(false); @@ -1294,13 +1320,16 @@ export class Workbench implements IPartService { if (activeEditor) { activeEditor.focus(); } + toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen(); } + this.inZenMode.set(this.zenMode.active); if (!skipLayout) { this.layout(); } + if (toggleFullScreen) { this.windowService.toggleFullScreen().done(undefined, errors.onUnexpectedError); } diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts b/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts index 7da69d61142..4b7695b68b9 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts @@ -5,6 +5,7 @@ 'use strict'; import * as nls from 'vs/nls'; +import * as types from 'vs/base/common/types'; import { parse, ParseError } from 'vs/base/common/json'; import { readFile } from 'vs/base/node/pfs'; import { CharacterPair, LanguageConfiguration, IAutoClosingPair, IAutoClosingPairConditional, IndentationRule, CommentRule, FoldingRules } from 'vs/editor/common/modes/languageConfiguration'; @@ -38,6 +39,26 @@ interface ILanguageConfiguration { folding?: FoldingRules; } +function isStringArr(something: string[]): boolean { + if (!Array.isArray(something)) { + return false; + } + for (let i = 0, len = something.length; i < len; i++) { + if (typeof something[i] !== 'string') { + return false; + } + } + return true; + +} + +function isCharacterPair(something: CharacterPair): boolean { + return ( + isStringArr(something) + && something.length === 2 + ); +} + export class LanguageConfigurationFileHandler { private _modeService: IModeService; @@ -80,24 +101,177 @@ export class LanguageConfigurationFileHandler { }); } + private _extractValidCommentRule(languageIdentifier: LanguageIdentifier, configuration: ILanguageConfiguration): CommentRule { + const source = configuration.comments; + if (typeof source === 'undefined') { + return null; + } + if (!types.isObject(source)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`comments\` to be an object.`); + return null; + } + + let result: CommentRule = null; + if (typeof source.lineComment !== 'undefined') { + if (typeof source.lineComment !== 'string') { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`comments.lineComment\` to be a string.`); + } else { + result = result || {}; + result.lineComment = source.lineComment; + } + } + if (typeof source.blockComment !== 'undefined') { + if (!isCharacterPair(source.blockComment)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`comments.blockComment\` to be an array of two strings.`); + } else { + result = result || {}; + result.blockComment = source.blockComment; + } + } + return result; + } + + private _extractValidBrackets(languageIdentifier: LanguageIdentifier, configuration: ILanguageConfiguration): CharacterPair[] { + const source = configuration.brackets; + if (typeof source === 'undefined') { + return null; + } + if (!Array.isArray(source)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`brackets\` to be an array.`); + return null; + } + + let result: CharacterPair[] = null; + for (let i = 0, len = source.length; i < len; i++) { + const pair = source[i]; + if (!isCharacterPair(pair)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`brackets[${i}]\` to be an array of two strings.`); + continue; + } + + result = result || []; + result.push(pair); + } + return result; + } + + private _extractValidAutoClosingPairs(languageIdentifier: LanguageIdentifier, configuration: ILanguageConfiguration): IAutoClosingPairConditional[] { + const source = configuration.autoClosingPairs; + if (typeof source === 'undefined') { + return null; + } + if (!Array.isArray(source)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`autoClosingPairs\` to be an array.`); + return null; + } + + let result: IAutoClosingPairConditional[] = null; + for (let i = 0, len = source.length; i < len; i++) { + const pair = source[i]; + if (Array.isArray(pair)) { + if (!isCharacterPair(pair)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`autoClosingPairs[${i}]\` to be an array of two strings or an object.`); + continue; + } + result = result || []; + result.push({ open: pair[0], close: pair[1] }); + } else { + if (!types.isObject(pair)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`autoClosingPairs[${i}]\` to be an array of two strings or an object.`); + continue; + } + if (typeof pair.open !== 'string') { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`autoClosingPairs[${i}].open\` to be a string.`); + continue; + } + if (typeof pair.close !== 'string') { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`autoClosingPairs[${i}].close\` to be a string.`); + continue; + } + if (typeof pair.notIn !== 'undefined') { + if (!isStringArr(pair.notIn)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`autoClosingPairs[${i}].notIn\` to be a string array.`); + continue; + } + } + result = result || []; + result.push({ open: pair.open, close: pair.close, notIn: pair.notIn }); + } + } + return result; + } + + private _extractValidSurroundingPairs(languageIdentifier: LanguageIdentifier, configuration: ILanguageConfiguration): IAutoClosingPair[] { + const source = configuration.surroundingPairs; + if (typeof source === 'undefined') { + return null; + } + if (!Array.isArray(source)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`surroundingPairs\` to be an array.`); + return null; + } + + let result: IAutoClosingPair[] = null; + for (let i = 0, len = source.length; i < len; i++) { + const pair = source[i]; + if (Array.isArray(pair)) { + if (!isCharacterPair(pair)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`surroundingPairs[${i}]\` to be an array of two strings or an object.`); + continue; + } + result = result || []; + result.push({ open: pair[0], close: pair[1] }); + } else { + if (!types.isObject(pair)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`surroundingPairs[${i}]\` to be an array of two strings or an object.`); + continue; + } + if (typeof pair.open !== 'string') { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`surroundingPairs[${i}].open\` to be a string.`); + continue; + } + if (typeof pair.close !== 'string') { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`surroundingPairs[${i}].close\` to be a string.`); + continue; + } + result = result || []; + result.push({ open: pair.open, close: pair.close }); + } + } + return result; + } + + // private _mapCharacterPairs(pairs: (CharacterPair | IAutoClosingPairConditional)[]): IAutoClosingPairConditional[] { + // return pairs.map(pair => { + // if (Array.isArray(pair)) { + // return { open: pair[0], close: pair[1] }; + // } + // return pair; + // }); + // } + private _handleConfig(languageIdentifier: LanguageIdentifier, configuration: ILanguageConfiguration): void { let richEditConfig: LanguageConfiguration = {}; - if (configuration.comments) { - richEditConfig.comments = configuration.comments; + const comments = this._extractValidCommentRule(languageIdentifier, configuration); + if (comments) { + richEditConfig.comments = comments; } - if (configuration.brackets) { - richEditConfig.brackets = configuration.brackets; + const brackets = this._extractValidBrackets(languageIdentifier, configuration); + if (brackets) { + richEditConfig.brackets = brackets; } - if (configuration.autoClosingPairs) { - richEditConfig.autoClosingPairs = this._mapCharacterPairs(configuration.autoClosingPairs); + const autoClosingPairs = this._extractValidAutoClosingPairs(languageIdentifier, configuration); + if (autoClosingPairs) { + richEditConfig.autoClosingPairs = autoClosingPairs; } - if (configuration.surroundingPairs) { - richEditConfig.surroundingPairs = this._mapCharacterPairs(configuration.surroundingPairs); + const surroundingPairs = this._extractValidSurroundingPairs(languageIdentifier, configuration); + if (surroundingPairs) { + richEditConfig.surroundingPairs = surroundingPairs; } if (configuration.wordPattern) { @@ -166,15 +340,6 @@ export class LanguageConfigurationFileHandler { return null; } - - private _mapCharacterPairs(pairs: (CharacterPair | IAutoClosingPairConditional)[]): IAutoClosingPairConditional[] { - return pairs.map(pair => { - if (Array.isArray(pair)) { - return { open: pair[0], close: pair[1] }; - } - return pair; - }); - } } const schemaId = 'vscode://schemas/language-configuration'; diff --git a/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts b/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts index e9c35de887b..27e900d3443 100644 --- a/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts +++ b/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts @@ -13,8 +13,38 @@ import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IDebugService, ILaunch } from 'vs/workbench/parts/debug/common/debug'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import * as errors from 'vs/base/common/errors'; +import { QuickOpenEntry, QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel'; +import { ICommandService } from 'vs/platform/commands/common/commands'; -class DebugEntry extends Model.QuickOpenEntry { +class AddConfigEntry extends Model.QuickOpenEntry { + + constructor(private label: string, private launch: ILaunch, private commandService: ICommandService, private contextService: IWorkspaceContextService, highlights: Model.IHighlight[] = []) { + super(highlights); + } + + public getLabel(): string { + return this.label; + } + + public getDescription(): string { + return this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? this.launch.workspace.name : ''; + } + + public getAriaLabel(): string { + return nls.localize('entryAriaLabel', "{0}, debug", this.getLabel()); + } + + public run(mode: QuickOpen.Mode, context: Model.IContext): boolean { + if (mode === QuickOpen.Mode.PREVIEW) { + return false; + } + this.commandService.executeCommand('debug.addConfiguration', this.launch.workspace.uri.toString()).done(undefined, errors.onUnexpectedError); + + return true; + } +} + +class StartDebugEntry extends Model.QuickOpenEntry { constructor(private debugService: IDebugService, private contextService: IWorkspaceContextService, private launch: ILaunch, private configurationName: string, highlights: Model.IHighlight[] = []) { super(highlights); @@ -51,7 +81,8 @@ export class DebugQuickOpenHandler extends Quickopen.QuickOpenHandler { constructor( @IQuickOpenService private quickOpenService: IQuickOpenService, @IDebugService private debugService: IDebugService, - @IWorkspaceContextService private contextService: IWorkspaceContextService + @IWorkspaceContextService private contextService: IWorkspaceContextService, + @ICommandService private commandService: ICommandService ) { super(); } @@ -61,13 +92,24 @@ export class DebugQuickOpenHandler extends Quickopen.QuickOpenHandler { } public getResults(input: string): TPromise { - const configurations: DebugEntry[] = []; + const configurations: QuickOpenEntry[] = []; - for (let launch of this.debugService.getConfigurationManager().getLaunches()) { + const launches = this.debugService.getConfigurationManager().getLaunches(); + for (let launch of launches) { launch.getConfigurationNames().map(config => ({ config: config, highlights: Filters.matchesContiguousSubString(input, config) })) .filter(({ highlights }) => !!highlights) - .forEach(({ config, highlights }) => configurations.push(new DebugEntry(this.debugService, this.contextService, launch, config, highlights))); + .forEach(({ config, highlights }) => configurations.push(new StartDebugEntry(this.debugService, this.contextService, launch, config, highlights))); } + launches.forEach((l, index) => { + const label = launches.length > 1 ? nls.localize("addConfigTo", "Add Config ({0})...", l.workspace.name) : nls.localize('addConfiguration', "Add Configuration..."); + const entry = new AddConfigEntry(label, l, this.commandService, this.contextService, Filters.matchesContiguousSubString(input, label)); + if (index === 0) { + configurations.push(new QuickOpenEntryGroup(entry, undefined, true)); + } else { + configurations.push(entry); + } + + }); return TPromise.as(new Model.QuickOpenModel(configurations)); } diff --git a/src/vs/workbench/parts/debug/browser/debugStatus.ts b/src/vs/workbench/parts/debug/browser/debugStatus.ts index 58ad52104db..26b0934285f 100644 --- a/src/vs/workbench/parts/debug/browser/debugStatus.ts +++ b/src/vs/workbench/parts/debug/browser/debugStatus.ts @@ -14,7 +14,6 @@ import { IDebugService } from 'vs/workbench/parts/debug/common/debug'; import { Themable, STATUS_BAR_FOREGROUND } from 'vs/workbench/common/theme'; const $ = dom.$; -const MAX_LABEL_LENGTH = 17; export class DebugStatus extends Themable implements IStatusbarItem { private toDispose: IDisposable[]; @@ -68,11 +67,9 @@ export class DebugStatus extends Themable implements IStatusbarItem { private setLabel(): void { if (this.label && !this.hidden) { - let name = this.debugService.getConfigurationManager().selectedName || ''; - if (name.length > MAX_LABEL_LENGTH) { - name = name.substring(0, MAX_LABEL_LENGTH) + '...'; - } - this.label.textContent = name; + const manager = this.debugService.getConfigurationManager(); + const name = manager.selectedName || ''; + this.label.textContent = manager.getLaunches().length > 1 ? `${name} (${manager.selectedLaunch.workspace.name})` : name; } } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts index bc97bf770ba..53aab6d7a27 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts @@ -1297,6 +1297,10 @@ export class BreakpointsController extends BaseDebugController { } public openBreakpointSource(breakpoint: Breakpoint, event: IKeyboardEvent | IMouseEvent, preserveFocus: boolean): void { + if (breakpoint.uri.scheme === debug.DEBUG_SCHEME && this.debugService.state === debug.State.Inactive) { + return; + } + const sideBySide = (event && (event.ctrlKey || event.metaKey)); const selection = breakpoint.endLineNumber ? { startLineNumber: breakpoint.lineNumber, diff --git a/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts b/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts index 36a53527512..913c3e87ccf 100644 --- a/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts +++ b/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts @@ -103,7 +103,7 @@ export abstract class AbstractOpenInTerminalAction extends Action { let pathToOpen: string; // Try workspace path first - const root = this.historyService.getLastActiveWorkspaceRoot(); + const root = this.historyService.getLastActiveWorkspaceRoot('file'); pathToOpen = this.resource ? this.resource.fsPath : (root && root.fsPath); // Otherwise check if we have an active file open diff --git a/src/vs/workbench/parts/extensions/browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/browser/extensionEditor.ts index e49587e3c0c..9794f7ba135 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionEditor.ts @@ -25,7 +25,7 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IExtensionGalleryService, IExtensionManifest, IKeyBinding, IView } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionManifest, IKeyBinding, IView, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ResolvedKeybinding, KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension, IExtensionDependencies } from 'vs/workbench/parts/extensions/common/extensions'; @@ -163,7 +163,8 @@ export class ExtensionEditor extends BaseEditor { private extensionActionBar: ActionBar; private navbar: NavBar; private content: HTMLElement; - + private recommendation: HTMLElement; + private header: HTMLElement; private _highlight: ITemplateData; private highlightDisposable: IDisposable; @@ -195,6 +196,7 @@ export class ExtensionEditor extends BaseEditor { @IPartService private partService: IPartService, @IContextViewService private contextViewService: IContextViewService, @IContextKeyService private contextKeyService: IContextKeyService, + @IExtensionTipsService private extensionTipsService: IExtensionTipsService ) { super(ExtensionEditor.ID, telemetryService, themeService); this._highlight = null; @@ -212,11 +214,11 @@ export class ExtensionEditor extends BaseEditor { const container = parent.getHTMLElement(); const root = append(container, $('.extension-editor')); - const header = append(root, $('.header')); + this.header = append(root, $('.header')); - this.icon = append(header, $('img.icon', { draggable: false })); + this.icon = append(this.header, $('img.icon', { draggable: false })); - const details = append(header, $('.details')); + const details = append(this.header, $('.details')); const title = append(details, $('.title')); this.name = append(title, $('span.name.clickable', { title: localize('name', "Extension name") })); this.identifier = append(title, $('span.identifier', { title: localize('extension id', "Extension identifier") })); @@ -249,6 +251,8 @@ export class ExtensionEditor extends BaseEditor { }); this.disposables.push(this.extensionActionBar); + this.recommendation = append(details, $('.recommendation')); + chain(fromEventEmitter<{ error?: any; }>(this.extensionActionBar, 'run')) .map(({ error }) => error) .filter(error => !!error) @@ -289,6 +293,14 @@ export class ExtensionEditor extends BaseEditor { this.publisher.textContent = extension.publisherDisplayName; this.description.textContent = extension.description; + const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason(); + this.recommendation.textContent = extRecommendations[extension.id.toLowerCase()]; + if (extRecommendations[extension.id.toLowerCase()]) { + addClass(this.header, 'recommended'); + } else { + removeClass(this.header, 'recommended'); + } + if (extension.url) { this.name.onclick = finalHandler(() => window.open(extension.url)); this.rating.onclick = finalHandler(() => window.open(`${extension.url}#review-details`)); diff --git a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts index 9fe32c36539..a4e4b7e51b9 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts @@ -17,7 +17,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, AutoUpdateConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions'; import { ExtensionsConfigurationInitialContent } from 'vs/workbench/parts/extensions/common/extensionsFileTemplate'; -import { LocalExtensionType, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { LocalExtensionType, IExtensionEnablementService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService } from 'vs/platform/message/common/message'; @@ -39,6 +39,7 @@ import { IJSONEditingService } from 'vs/workbench/services/configuration/common/ import { ITextEditorSelection } from 'vs/platform/editor/common/editor'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { PICK_WORKSPACE_FOLDER_COMMAND } from 'vs/workbench/browser/actions/workspaceActions'; +import Severity from 'vs/base/common/severity'; export class InstallAction extends Action { @@ -84,6 +85,7 @@ export class InstallAction extends Action { } run(): TPromise { + this.extensionsWorkbenchService.open(this.extension); return this.extensionsWorkbenchService.install(this.extension); } @@ -436,7 +438,7 @@ export class EnableForWorkspaceAction extends Action implements IExtensionAction private update(): void { this.enabled = false; if (this.extension) { - this.enabled = !this.extension.disabledGlobally && this.extension.disabledForWorkspace && this.extensionEnablementService.canEnable(this.extension.id); + this.enabled = !this.extension.disabledGlobally && this.extension.disabledForWorkspace && this.extensionEnablementService.canEnable(this.extension); } } @@ -475,7 +477,7 @@ export class EnableGloballyAction extends Action implements IExtensionAction { private update(): void { this.enabled = false; if (this.extension) { - this.enabled = this.extension.disabledGlobally && this.extensionEnablementService.canEnable(this.extension.id); + this.enabled = this.extension.disabledGlobally && this.extensionEnablementService.canEnable(this.extension); } } @@ -531,7 +533,7 @@ export class EnableAction extends Action { return; } - this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.disabledGlobally || this.extension.disabledForWorkspace) && this.extensionEnablementService.canEnable(this.extension.id); + this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.disabledGlobally || this.extension.disabledForWorkspace) && this.extensionEnablementService.canEnable(this.extension); this.class = this.enabled ? EnableAction.EnabledClass : EnableAction.DisabledClass; } @@ -1133,6 +1135,120 @@ export class ShowWorkspaceRecommendedExtensionsAction extends Action { } } +export class InstallWorkspaceRecommendedExtensionsAction extends Action { + + static ID = 'workbench.extensions.action.installWorkspaceRecommendedExtensions'; + static LABEL = localize('installWorkspaceRecommendedExtensions', "Install All Workspace Recommended Extensions"); + + private disposables: IDisposable[] = []; + private recommendations: string[] = []; + private toInstall: string[] = []; + private updatePromise: TPromise = TPromise.as(null); + + constructor( + id: string = InstallWorkspaceRecommendedExtensionsAction.ID, + label: string = InstallWorkspaceRecommendedExtensionsAction.LABEL, + @IWorkspaceContextService private contextService: IWorkspaceContextService, + @IViewletService private viewletService: IViewletService, + @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, + @IExtensionTipsService private extensionTipsService: IExtensionTipsService, + @IMessageService private messageService: IMessageService + ) { + super(id, label, 'extension-action'); + this.extensionsWorkbenchService.onChange(() => this.updateToInstall(), this, this.disposables); + this.contextService.onDidChangeWorkbenchState(() => this.updateRecommendations(), this, this.disposables); + this.updatePromise = this.updateRecommendations(); + } + + private updateRecommendations(): TPromise { + this.enabled = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY; + if (this.enabled) { + return this.extensionTipsService.getWorkspaceRecommendations().then(names => { + this.recommendations = names; + this.updateToInstall(); + }); + } + return TPromise.as(null); + } + + private updateToInstall(): void { + const installed = this.extensionsWorkbenchService.local.map(x => x.id.toLowerCase()); + this.toInstall = this.recommendations.filter(x => installed.indexOf(x.toLowerCase()) === -1); + this.enabled = this.toInstall.length > 0; + } + + run(): TPromise { + this.viewletService.openViewlet(VIEWLET_ID, true) + .then(viewlet => viewlet as IExtensionsViewlet) + .then(viewlet => { + viewlet.search('@recommended:workspace '); + viewlet.focus(); + }); + + return this.updatePromise.then(() => { + if (!this.toInstall.length) { + this.messageService.show(Severity.Info, localize('allExtensionsInstalled', "All extensions recommended for this workspace have already been installed")); + return TPromise.as(null); + } + return this.extensionsWorkbenchService.queryGallery({ names: this.toInstall, source: 'install-all-workspace-recommendations' }).then(pager => { + return TPromise.join(pager.firstPage.map(e => this.extensionsWorkbenchService.install(e))); + }); + }); + } + + protected isEnabled(): boolean { + return this.enabled; + } + + dispose(): void { + this.disposables = dispose(this.disposables); + super.dispose(); + } +} + +export class InstallRecommendedExtensionAction extends Action { + + static ID = 'workbench.extensions.action.installRecommendedExtension'; + static LABEL = localize('installRecommendedExtension', "Install Recommended Extension"); + + private extensionId: string; + + constructor( + extensionId: string, + @IWorkspaceContextService private contextService: IWorkspaceContextService, + @IViewletService private viewletService: IViewletService, + @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, + @IExtensionTipsService private extensionTipsService: IExtensionTipsService + ) { + super(InstallRecommendedExtensionAction.ID, InstallRecommendedExtensionAction.LABEL, null); + this.extensionId = extensionId; + } + + run(): TPromise { + this.viewletService.openViewlet(VIEWLET_ID, true) + .then(viewlet => viewlet as IExtensionsViewlet) + .then(viewlet => { + viewlet.search('@recommended'); + viewlet.focus(); + }); + + + return this.extensionsWorkbenchService.queryGallery({ names: [this.extensionId], source: 'install-recommendation' }).then(pager => { + return TPromise.join(pager.firstPage.map(e => this.extensionsWorkbenchService.install(e))); + }); + + } + + protected isEnabled(): boolean { + return true; + } + + dispose(): void { + super.dispose(); + } +} + + export class ShowRecommendedKeymapExtensionsAction extends Action { static ID = 'workbench.extensions.action.showRecommendedKeymapExtensions'; @@ -1536,7 +1652,7 @@ export class EnableAllAction extends Action { } private update(): void { - this.enabled = this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e.id) && e.disabledGlobally); + this.enabled = this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e) && e.disabledGlobally); } run(): TPromise { @@ -1569,7 +1685,7 @@ export class EnableAllWorkpsaceAction extends Action { } private update(): void { - this.enabled = this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e.id) && !e.disabledGlobally && e.disabledForWorkspace); + this.enabled = this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e) && !e.disabledGlobally && e.disabledForWorkspace); } run(): TPromise { diff --git a/src/vs/workbench/parts/extensions/browser/extensionsList.ts b/src/vs/workbench/parts/extensions/browser/extensionsList.ts index 8a9c326d6a6..e531ac183a6 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsList.ts @@ -18,10 +18,12 @@ import { domEvent } from 'vs/base/browser/event'; import { IExtension, IExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/common/extensions'; import { InstallAction, UpdateAction, BuiltinStatusLabelAction, ManageExtensionAction, ReloadAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { Label, RatingsWidget, InstallWidget } from 'vs/workbench/parts/extensions/browser/extensionsWidgets'; +import { RatingsWidget, InstallWidget } from 'vs/workbench/parts/extensions/browser/extensionsWidgets'; import { EventType } from 'vs/base/common/events'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { localize } from 'vs/nls'; export interface ITemplateData { root: HTMLElement; @@ -32,6 +34,7 @@ export interface ITemplateData { ratings: HTMLElement; author: HTMLElement; description: HTMLElement; + subText: HTMLElement; extension: IExtension; disposables: IDisposable[]; extensionDisposables: IDisposable[]; @@ -46,13 +49,18 @@ const actionOptions = { icon: true, label: true }; export class Renderer implements IPagedRenderer { + private showRecommendedLabel: boolean; constructor( + showRecommendedLabel: boolean, @IInstantiationService private instantiationService: IInstantiationService, @IContextMenuService private contextMenuService: IContextMenuService, @IMessageService private messageService: IMessageService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, - @IExtensionService private extensionService: IExtensionService - ) { } + @IExtensionService private extensionService: IExtensionService, + @IExtensionTipsService private extensionTipsService: IExtensionTipsService + ) { + this.showRecommendedLabel = showRecommendedLabel; + } get templateId() { return 'extension'; } @@ -63,7 +71,8 @@ export class Renderer implements IPagedRenderer { const headerContainer = append(details, $('.header-container')); const header = append(headerContainer, $('.header')); const name = append(header, $('span.name')); - const version = append(header, $('span.version')); + const subTextContainer = append(header, $('span.subtext-container')); + const subText = append(subTextContainer, $('span.subtext')); const installCount = append(header, $('span.install-count')); const ratings = append(header, $('span.ratings')); const description = append(details, $('.description.ellipsis')); @@ -80,7 +89,6 @@ export class Renderer implements IPagedRenderer { }); actionbar.addListener(EventType.RUN, ({ error }) => error && this.messageService.show(Severity.Error, error)); - const versionWidget = this.instantiationService.createInstance(Label, version, (e: IExtension) => e.version); const installCountWidget = this.instantiationService.createInstance(InstallWidget, installCount, { small: true }); const ratingsWidget = this.instantiationService.createInstance(RatingsWidget, ratings, { small: true }); @@ -91,13 +99,12 @@ export class Renderer implements IPagedRenderer { const manageAction = this.instantiationService.createInstance(ManageExtensionAction); actionbar.push([reloadAction, updateAction, installAction, builtinStatusAction, manageAction], actionOptions); - const disposables = [versionWidget, installCountWidget, ratingsWidget, builtinStatusAction, updateAction, reloadAction, manageAction, actionbar]; + const disposables = [installCountWidget, ratingsWidget, builtinStatusAction, updateAction, reloadAction, manageAction, actionbar]; return { - root, element, icon, name, installCount, ratings, author, description, disposables, + root, element, icon, name, installCount, ratings, author, description, subText, disposables, extensionDisposables: [], set extension(extension: IExtension) { - versionWidget.extension = extension; installCountWidget.extension = extension; ratingsWidget.extension = extension; builtinStatusAction.extension = extension; @@ -127,10 +134,11 @@ export class Renderer implements IPagedRenderer { removeClass(data.element, 'loading'); data.extensionDisposables = dispose(data.extensionDisposables); + const isInstalled = this.extensionsWorkbenchService.local.some(e => e.id === extension.id); this.extensionService.getExtensions().then(enabledExtensions => { const isExtensionRunning = enabledExtensions.some(e => areSameExtensions(e, extension)); - const isInstalled = this.extensionsWorkbenchService.local.some(e => e.id === extension.id); + toggleClass(data.element, 'disabled', isInstalled && !isExtensionRunning); }); @@ -145,7 +153,20 @@ export class Renderer implements IPagedRenderer { data.icon.style.visibility = 'inherit'; } + data.subText.textContent = isInstalled ? extension.version : ''; data.root.setAttribute('aria-label', extension.displayName); + removeClass(data.subText, 'recommended'); + + const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason(); + if (extRecommendations[extension.id.toLowerCase()] && !isInstalled) { + data.root.setAttribute('aria-label', extension.displayName + '. ' + extRecommendations[extension.id]); + if (this.showRecommendedLabel) { + data.subText.textContent = localize('recommended', "Recommended"); + addClass(data.subText, 'recommended'); + data.subText.title = extRecommendations[extension.id.toLowerCase()]; + } + } + data.name.textContent = extension.displayName; data.author.textContent = extension.publisherDisplayName; data.description.textContent = extension.description; diff --git a/src/vs/workbench/parts/extensions/browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/browser/media/extensionEditor.css index b5aeae7795d..424f575504b 100644 --- a/src/vs/workbench/parts/extensions/browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/browser/media/extensionEditor.css @@ -21,6 +21,10 @@ font-size: 14px; } +.extension-editor > .header.recommended { + height: 140px; +} + .extension-editor > .header > .icon { height: 128px; width: 128px; @@ -59,7 +63,7 @@ } .extension-editor > .header > .details > .subtitle { - padding-top: 10px; + padding-top: 6px; white-space: nowrap; height: 20px; line-height: 20px; @@ -81,14 +85,14 @@ } .extension-editor > .header > .details > .description { - margin-top: 14px; + margin-top: 10px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } .extension-editor > .header > .details > .actions { - margin-top: 14px; + margin-top: 10px; } .extension-editor > .header > .details > .actions > .monaco-action-bar { @@ -104,6 +108,16 @@ padding: 1px 6px; } +.extension-editor > .header.recommended > .details > .recommendation { + display: none; +} + +.extension-editor > .header.recommended > .details > .recommendation { + display: block; + margin-top: 10px; + font-size: 13px; +} + .extension-editor > .body { height: calc(100% - 168px); overflow: hidden; diff --git a/src/vs/workbench/parts/extensions/common/extensions.ts b/src/vs/workbench/parts/extensions/common/extensions.ts index c19f4aba5be..3327da7f2c9 100644 --- a/src/vs/workbench/parts/extensions/common/extensions.ts +++ b/src/vs/workbench/parts/extensions/common/extensions.ts @@ -29,6 +29,7 @@ export interface IExtension { name: string; displayName: string; id: string; + uuid: string; publisher: string; publisherDisplayName: string; version: string; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index c6f10cffca4..87897d50807 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import * as paths from 'vs/base/common/paths'; import { TPromise } from 'vs/base/common/winjs.base'; import { forEach } from 'vs/base/common/collections'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { match } from 'vs/base/common/glob'; import * as json from 'vs/base/common/json'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, LocalExtensionType, EXTENSION_IDENTIFIER_PATTERN } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -17,9 +17,9 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import product from 'vs/platform/node/product'; import { IChoiceService, IMessageService } from 'vs/platform/message/common/message'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; +import { ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction, InstallRecommendedExtensionAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; import Severity from 'vs/base/common/severity'; -import { IWorkspaceContextService, IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, IWorkspaceFolder, IWorkspace, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; import { Schemas } from 'vs/base/common/network'; import { IFileService } from 'vs/platform/files/common/files'; import { IExtensionsConfiguration, ConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions'; @@ -36,7 +36,7 @@ interface IExtensionsContent { const empty: { [key: string]: any; } = Object.create(null); const milliSecondsInADay = 1000 * 60 * 60 * 24; -export class ExtensionTipsService implements IExtensionTipsService { +export class ExtensionTipsService extends Disposable implements IExtensionTipsService { _serviceBrand: any; @@ -45,9 +45,11 @@ export class ExtensionTipsService implements IExtensionTipsService { private _availableRecommendations: { [pattern: string]: string[] } = Object.create(null); private importantRecommendations: { [id: string]: { name: string; pattern: string; } } = Object.create(null); private importantRecommendationsIgnoreList: string[]; - private _allRecommendations: string[]; + private _allRecommendations: string[] = []; private _disposables: IDisposable[] = []; + private _allWorkspaceRecommendedExtensions: string[] = []; + constructor( @IExtensionGalleryService private _galleryService: IExtensionGalleryService, @IModelService private _modelService: IModelService, @@ -61,22 +63,36 @@ export class ExtensionTipsService implements IExtensionTipsService { @IMessageService private messageService: IMessageService, @ITelemetryService private telemetryService: ITelemetryService ) { + super(); + if (!this._galleryService.isEnabled()) { return; } + this._suggestTips(); this._suggestWorkspaceRecommendations(); // Executable based recommendations carry out a lot of file stats, so run them after 10 secs // So that the startup is not affected setTimeout(() => this._suggestBasedOnExecutables(this._exeBasedRecommendations), 10000); + this._register(this.contextService.onDidChangeWorkspaceFolders(e => this.onWorkspaceFoldersChanged(e))); + } + + getAllRecommendationsWithReason(): { [id: string]: string; } { + let output: { [id: string]: string; } = Object.create(null); + this.getFileBasedRecommendations().forEach(x => output[x.toLowerCase()] = localize('fileBasedRecommendation', "Based on your recent file history, we recommend this extension.")); + this._allWorkspaceRecommendedExtensions.forEach(x => output[x.toLowerCase()] = localize('workspaceRecommendation', "Your team recommends this extension.")); + return output; } getWorkspaceRecommendations(): TPromise { const workspace = this.contextService.getWorkspace(); return TPromise.join([this.resolveWorkspaceRecommendations(workspace), ...workspace.folders.map(workspaceFolder => this.resolveWorkspaceFolderRecommendations(workspaceFolder))]) - .then(recommendations => distinct(flatten(recommendations))); + .then(recommendations => { + this._allWorkspaceRecommendedExtensions = distinct(flatten(recommendations)); + return this._allWorkspaceRecommendedExtensions; + }); } private resolveWorkspaceRecommendations(workspace: IWorkspace): TPromise { @@ -102,58 +118,38 @@ export class ExtensionTipsService implements IExtensionTipsService { return []; } - getRecommendations(installedExtensions: string[], searchText: string): string[] { - const allRecomendations = this._getAllRecommendationsInProduct(); + private onWorkspaceFoldersChanged(event: IWorkspaceFoldersChangeEvent): void { + if (event.added.length) { + TPromise.join(event.added.map(workspaceFolder => this.resolveWorkspaceFolderRecommendations(workspaceFolder))) + .then(result => { + const newRecommendations = flatten(result); + // Suggest only if atleast one of the newly added recommendtations was not suggested before + if (newRecommendations.some(e => this._allWorkspaceRecommendedExtensions.indexOf(e) === -1)) { + this._suggestWorkspaceRecommendations(); + } + }); + } + } + + getFileBasedRecommendations(): string[] { const fileBased = Object.keys(this._fileBasedRecommendations) - .filter(recommendation => { - return allRecomendations.indexOf(recommendation) > -1 - && installedExtensions.indexOf(recommendation) === -1 - && recommendation.toLowerCase().indexOf(searchText) > -1; - }).sort((a, b) => { + .sort((a, b) => { return this._fileBasedRecommendations[a] > this._fileBasedRecommendations[b] ? -1 : 1; }); - - const exeBased = this._exeBasedRecommendations - .filter((recommendation, index) => { - return this._exeBasedRecommendations.indexOf(recommendation) === index - && installedExtensions.indexOf(recommendation) === -1 - && fileBased.indexOf(recommendation) === -1 - && recommendation.toLowerCase().indexOf(searchText) > -1; - }); - - // Sort recommendations such that few of the exeBased ones show up earliar - const x = Math.min(6, fileBased.length); - const y = Math.min(4, exeBased.length); - const sortedRecommendations = fileBased.slice(0, x); - sortedRecommendations.push(...exeBased.slice(0, y)); - sortedRecommendations.push(...fileBased.slice(x)); - sortedRecommendations.push(...exeBased.slice(y)); - - /* __GDPR__ - "extensionRecommendations:unfiltered" : { - "fileBased" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "exeBased": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('extensionRecommendations:unfiltered', { fileBased, exeBased }); - - return sortedRecommendations; + return fileBased; } + getOtherRecommendations(): string[] { + + return distinct(this._exeBasedRecommendations); + } + + + getKeymapRecommendations(): string[] { return product.keymapExtensionTips || []; } - private _getAllRecommendationsInProduct(): string[] { - if (!this._allRecommendations) { - this._allRecommendations = [...Object.keys(this.importantRecommendations)]; - forEach(this._availableRecommendations, ({ value: ids }) => { - this._allRecommendations.push(...ids); - }); - } - return this._allRecommendations; - } - private _suggestTips() { const extensionTips = product.extensionTips; if (!extensionTips) { @@ -162,26 +158,6 @@ export class ExtensionTipsService implements IExtensionTipsService { this.importantRecommendations = product.extensionImportantTips || Object.create(null); this.importantRecommendationsIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]')); - // retrieve ids of previous recommendations - const storedRecommendationsJson = JSON.parse(this.storageService.get('extensionsAssistant/recommendations', StorageScope.GLOBAL, '[]')); - if (Array.isArray(storedRecommendationsJson)) { - for (let id of storedRecommendationsJson) { - this._fileBasedRecommendations[id] = Date.now(); - } - } else { - const now = Date.now(); - forEach(storedRecommendationsJson, entry => { - if (typeof entry.value === 'number') { - const diff = (now - entry.value) / milliSecondsInADay; - if (diff > 7) { - delete this._fileBasedRecommendations[entry.value]; - } else { - this._fileBasedRecommendations[entry.key] = entry.value; - } - } - }); - } - // group ids by pattern, like {**/*.md} -> [ext.foo1, ext.bar2] this._availableRecommendations = Object.create(null); forEach(extensionTips, entry => { @@ -205,6 +181,31 @@ export class ExtensionTipsService implements IExtensionTipsService { } }); + forEach(this._availableRecommendations, ({ value: ids }) => { + this._allRecommendations.push(...ids); + }); + + // retrieve ids of previous recommendations + const storedRecommendationsJson = JSON.parse(this.storageService.get('extensionsAssistant/recommendations', StorageScope.GLOBAL, '[]')); + + if (Array.isArray(storedRecommendationsJson)) { + for (let id of storedRecommendationsJson) { + if (this._allRecommendations.indexOf(id) > -1) { + this._fileBasedRecommendations[id] = Date.now(); + } + } + } else { + const now = Date.now(); + forEach(storedRecommendationsJson, entry => { + if (typeof entry.value === 'number') { + const diff = (now - entry.value) / milliSecondsInADay; + if (diff <= 7 && this._allRecommendations.indexOf(entry.key) > -1) { + this._fileBasedRecommendations[entry.key] = entry.value; + } + } + }); + } + this._modelService.onModelAdded(this._suggest, this, this._disposables); this._modelService.getModels().forEach(model => this._suggest(model)); } @@ -264,15 +265,26 @@ export class ExtensionTipsService implements IExtensionTipsService { } const recommendationsAction = this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations")); + const installAction = this.instantiationService.createInstance(InstallRecommendedExtensionAction, id); const options = [ + localize('install', 'Install'), recommendationsAction.label, localize('neverShowAgain', "Don't show again"), localize('close', "Close") ]; - this.choiceService.choose(Severity.Info, message, options, 2).done(choice => { + this.choiceService.choose(Severity.Info, message, options, 3).done(choice => { switch (choice) { case 0: + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'install', extensionId: name }); + return installAction.run(); + case 1: /* __GDPR__ "extensionRecommendations:popup" : { "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, @@ -344,15 +356,17 @@ export class ExtensionTipsService implements IExtensionTipsService { } const message = localize('workspaceRecommended', "This workspace has extension recommendations."); - const action = this.instantiationService.createInstance(ShowWorkspaceRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations")); + const showAction = this.instantiationService.createInstance(ShowWorkspaceRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations")); + const installAllAction = this.instantiationService.createInstance(InstallWorkspaceRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction.ID, localize('installAll', "Install All")); const options = [ - action.label, + installAllAction.label, + showAction.label, localize('neverShowAgain', "Don't show again"), localize('close', "Close") ]; - this.choiceService.choose(Severity.Info, message, options, 2).done(choice => { + this.choiceService.choose(Severity.Info, message, options, 3).done(choice => { switch (choice) { case 0: /* __GDPR__ @@ -360,9 +374,17 @@ export class ExtensionTipsService implements IExtensionTipsService { "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ - this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'show' }); - return action.run(); + this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'install' }); + return installAllAction.run(); case 1: + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'show' }); + return showAction.run(); + case 2: /* __GDPR__ "extensionRecommendations:popup" : { "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } @@ -370,7 +392,7 @@ export class ExtensionTipsService implements IExtensionTipsService { */ this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'neverShowAgain' }); return this.storageService.store(storageKey, true, StorageScope.WORKSPACE); - case 2: + case 3: /* __GDPR__ "extensionRecommendations:popup" : { "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsUtils.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsUtils.ts index 2b8ed719ea3..562531b1993 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsUtils.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsUtils.ts @@ -7,12 +7,12 @@ import * as arrays from 'vs/base/common/arrays'; import { localize } from 'vs/nls'; -import Event, { chain, any, debounceEvent } from 'vs/base/common/event'; +import Event, { chain, anyEvent, debounceEvent } from 'vs/base/common/event'; import { onUnexpectedError, canceled } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService, IExtensionTipsService, LocalExtensionType } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService, IExtensionTipsService, LocalExtensionType, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; @@ -20,10 +20,10 @@ import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiati import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IMessageService, Severity, IChoiceService } from 'vs/platform/message/common/message'; import { Action } from 'vs/base/common/actions'; -import { BetterMergeDisabledNowKey, BetterMergeId, getIdAndVersionFromLocalExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { BetterMergeDisabledNowKey, BetterMergeId, getIdAndVersionFromLocalExtensionId, areSameExtensions, adoptToGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; export interface IExtensionStatus { - identifier: string; + identifier: IExtensionIdentifier; local: ILocalExtension; globallyEnabled: boolean; } @@ -42,8 +42,8 @@ export class KeymapExtensions implements IWorkbenchContribution { ) { this.disposables.push( lifecycleService.onShutdown(() => this.dispose()), - instantiationService.invokeFunction(onExtensionChanged)((ids => { - TPromise.join(ids.map(id => this.checkForOtherKeymaps(id))) + instantiationService.invokeFunction(onExtensionChanged)((identifiers => { + TPromise.join(identifiers.map(identifier => this.checkForOtherKeymaps(identifier))) .then(null, onUnexpectedError); })) ); @@ -53,12 +53,12 @@ export class KeymapExtensions implements IWorkbenchContribution { return 'vs.extensions.keymapExtensions'; } - private checkForOtherKeymaps(extensionId: string): TPromise { + private checkForOtherKeymaps(extensionIdentifier: IExtensionIdentifier): TPromise { return this.instantiationService.invokeFunction(getInstalledExtensions).then(extensions => { const keymaps = extensions.filter(extension => isKeymapExtension(this.tipsService, extension)); - const extension = arrays.first(keymaps, extension => extension.identifier === extensionId); + const extension = arrays.first(keymaps, extension => extension.identifier.id === extensionIdentifier.id); if (extension && extension.globallyEnabled) { - const otherKeymaps = keymaps.filter(extension => extension.identifier !== extensionId && extension.globallyEnabled); + const otherKeymaps = keymaps.filter(extension => extension.identifier.id !== extensionIdentifier.id && extension.globallyEnabled); if (otherKeymaps.length) { return this.promptForDisablingOtherKeymaps(extension, otherKeymaps); } @@ -107,7 +107,7 @@ export class KeymapExtensions implements IWorkbenchContribution { this.telemetryService.publicLog('disableOtherKeymaps', telemetryData); if (confirmed) { return TPromise.join(oldKeymaps.map(keymap => { - return this.extensionEnablementService.setEnablement(keymap.identifier, false); + return this.extensionEnablementService.setEnablement(keymap.local.identifier, false); })); } return undefined; @@ -120,18 +120,18 @@ export class KeymapExtensions implements IWorkbenchContribution { } } -export function onExtensionChanged(accessor: ServicesAccessor): Event { +export function onExtensionChanged(accessor: ServicesAccessor): Event { const extensionService = accessor.get(IExtensionManagementService); const extensionEnablementService = accessor.get(IExtensionEnablementService); - return debounceEvent(any( - chain(any(extensionService.onDidInstallExtension, extensionService.onDidUninstallExtension)) - .map(e => stripVersion(e.id)) + return debounceEvent(anyEvent( + chain(anyEvent(extensionService.onDidInstallExtension, extensionService.onDidUninstallExtension)) + .map(e => ({ id: stripVersion(e.identifier.id), uuid: e.identifier.uuid })) .event, extensionEnablementService.onEnablementChanged ), (list, id) => { if (!list) { return [id]; - } else if (list.indexOf(id) === -1) { + } else if (list.some(l => !areSameExtensions(l, id))) { list.push(id); } return list; @@ -144,11 +144,10 @@ export function getInstalledExtensions(accessor: ServicesAccessor): TPromise { const globallyDisabled = extensionEnablementService.getGloballyDisabledExtensions(); return extensions.map(extension => { - const identifier = stripVersion(extension.id); return { - identifier, + identifier: { id: adoptToGalleryExtensionId(extension.identifier.id), uuid: extension.identifier.uuid }, local: extension, - globallyEnabled: globallyDisabled.indexOf(identifier) === -1 + globallyEnabled: globallyDisabled.every(disabled => !areSameExtensions(disabled, extension.identifier)) }; }); }); @@ -156,7 +155,7 @@ export function getInstalledExtensions(accessor: ServicesAccessor): TPromise { - return Promise.all(extensions.filter(e => stripVersion(e.id) === BetterMergeId) + return Promise.all(extensions.filter(e => stripVersion(e.identifier.id) === BetterMergeId) .map(e => extensionManagementService.uninstall(e, true))); }); }), diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 26f160e6164..2b75d30dd62 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -122,6 +122,7 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens viewDescriptors.push(this.createInstalledExtensionsListViewDescriptor()); viewDescriptors.push(this.createSearchInstalledExtensionsListViewDescriptor()); viewDescriptors.push(this.createRecommendedExtensionsListViewDescriptor()); + viewDescriptors.push(this.createSearchRecommendedExtensionsListViewDescriptor()); ViewsRegistry.registerViews(viewDescriptors); } @@ -131,7 +132,7 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens name: localize('marketPlace', "Marketplace"), location: ViewLocation.Extensions, ctor: ExtensionsListView, - when: ContextKeyExpr.and(ContextKeyExpr.has('searchExtensions'), ContextKeyExpr.not('searchInstalledExtensions')), + when: ContextKeyExpr.and(ContextKeyExpr.has('searchExtensions'), ContextKeyExpr.not('searchInstalledExtensions'), ContextKeyExpr.not('searchRecommendedExtensions')), size: 100 }; } @@ -170,6 +171,18 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens }; } + private createSearchRecommendedExtensionsListViewDescriptor(): IViewDescriptor { + return { + id: 'extensions.searchrecommendedList', + name: localize('recommendedExtensions', "Recommended"), + location: ViewLocation.Extensions, + ctor: RecommendedExtensionsView, + when: ContextKeyExpr.and(ContextKeyExpr.has('searchExtensions'), ContextKeyExpr.has('searchRecommendedExtensions')), + size: 50, + canToggleVisibility: true + }; + } + async create(parent: Builder): TPromise { parent.addClass('extensions-viewlet'); this.root = parent.getHTMLElement(); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts index eaa33074295..1451881e85c 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts @@ -38,13 +38,16 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; +import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { EventType } from 'vs/base/common/events'; +import { InstallWorkspaceRecommendedExtensionsAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; export class ExtensionsListView extends ViewsViewletPanel { private messageBox: HTMLElement; private extensionsList: HTMLElement; private badge: CountBadge; - + private listActionBar: HTMLElement; private list: PagedList; constructor( @@ -76,11 +79,15 @@ export class ExtensionsListView extends ViewsViewletPanel { this.disposables.push(attachBadgeStyler(this.badge, this.themeService)); } + showRecommendedLabel() { + return true; + } + renderBody(container: HTMLElement): void { this.extensionsList = append(container, $('.extensions-list')); this.messageBox = append(container, $('.message')); const delegate = new Delegate(); - const renderer = this.instantiationService.createInstance(Renderer); + const renderer = this.instantiationService.createInstance(Renderer, this.showRecommendedLabel()); this.list = new PagedList(this.extensionsList, delegate, [renderer], { ariaLabel: localize('extensions', "Extensions"), keyboardSupport: false @@ -98,6 +105,16 @@ export class ExtensionsListView extends ViewsViewletPanel { .map(e => e.elements[0]) .filter(e => !!e) .on(this.pin, this, this.disposables); + + this.listActionBar = append(this.extensionsList, $('.list-actionbar-container')); + const actionbar = new ActionBar(this.listActionBar, { + animated: false + }); + actionbar.addListener(EventType.RUN, ({ error }) => error && this.messageService.show(Severity.Error, error)); + const installAllAction = this.instantiationService.createInstance(InstallWorkspaceRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction.ID, localize('installAll', "Install All")); + actionbar.push([installAllAction], { icon: true, label: true }); + + this.disposables.push(actionbar); } layoutBody(size: number): void { @@ -106,6 +123,7 @@ export class ExtensionsListView extends ViewsViewletPanel { } async show(query: string): TPromise> { + toggleClass(this.listActionBar, 'hidden', !ExtensionsListView.isWorkspaceRecommendedExtensionsQuery(query)); const model = await this.query(query); this.setModel(model); return model; @@ -279,23 +297,12 @@ export class ExtensionsListView extends ViewsViewletPanel { .then(result => result.filter(e => e.type === LocalExtensionType.User)) .then(local => { const installedExtensions = local.map(x => `${x.publisher}.${x.name}`); - return TPromise.join([TPromise.as(this.tipsService.getRecommendations(installedExtensions, value)), this.tipsService.getWorkspaceRecommendations()]) - .then(([recommendations, workspaceRecommendations]) => { + let fileBasedRecommendations = this.tipsService.getFileBasedRecommendations(); + let others = this.tipsService.getOtherRecommendations(); - workspaceRecommendations = workspaceRecommendations - .filter(name => { - return recommendations.indexOf(name) === -1 - && installedExtensions.indexOf(name) === -1 - && name.toLowerCase().indexOf(value) > -1; - }); - - // Sort recommendations such that few of the workspace ones show up earliar - const x = Math.min(4, recommendations.length); - const y = Math.min(4, workspaceRecommendations.length); - const names = recommendations.slice(0, x); - names.push(...workspaceRecommendations.slice(0, y)); - names.push(...recommendations.slice(x)); - names.push(...workspaceRecommendations.slice(y)); + return this.tipsService.getWorkspaceRecommendations() + .then(workspaceRecommendations => { + const names = this.getTrimmedRecommendations(installedExtensions, value, fileBasedRecommendations, others, workspaceRecommendations); this.telemetryService.publicLog('extensionAllRecommendations:open', { count: names.length }); if (!names.length) { @@ -317,7 +324,12 @@ export class ExtensionsListView extends ViewsViewletPanel { return this.extensionsWorkbenchService.queryLocal() .then(result => result.filter(e => e.type === LocalExtensionType.User)) .then(local => { - const names = this.tipsService.getRecommendations(local.map(x => `${x.publisher}.${x.name}`), value); + let fileBasedRecommendations = this.tipsService.getFileBasedRecommendations(); + let others = this.tipsService.getOtherRecommendations(); + + const installedExtensions = local.map(x => `${x.publisher}.${x.name}`); + + const names = this.getTrimmedRecommendations(installedExtensions, value, fileBasedRecommendations, others, []); /* __GDPR__ "extensionRecommendations:open" : { @@ -338,6 +350,35 @@ export class ExtensionsListView extends ViewsViewletPanel { }); } + // Given all recommendations, trims and returns recommendations in the relevant order after filtering out installed extensions + private getTrimmedRecommendations(installedExtensions: string[], value: string, fileBasedRecommendations: string[], otherRecommendations: string[], workpsaceRecommendations: string[], ) { + const totalCount = 8; + workpsaceRecommendations = workpsaceRecommendations + .filter(name => { + return installedExtensions.indexOf(name) === -1 + && name.toLowerCase().indexOf(value) > -1; + }); + fileBasedRecommendations = fileBasedRecommendations.filter(x => { + return installedExtensions.indexOf(x) === -1 + && workpsaceRecommendations.indexOf(x) === -1 + && x.toLowerCase().indexOf(value) > -1; + }); + otherRecommendations = otherRecommendations.filter(x => { + return installedExtensions.indexOf(x) === -1 + && fileBasedRecommendations.indexOf(x) === -1 + && workpsaceRecommendations.indexOf(x) === -1 + && x.toLowerCase().indexOf(value) > -1; + }); + + let otherCount = Math.min(2, otherRecommendations.length); + let fileBasedCount = Math.min(fileBasedRecommendations.length, totalCount - workpsaceRecommendations.length - otherCount); + let names = workpsaceRecommendations; + names.push(...fileBasedRecommendations.splice(0, fileBasedCount)); + names.push(...otherRecommendations.splice(0, otherCount)); + + return names; + } + private getWorkspaceRecommendationsModel(query: Query, options: IQueryOptions): TPromise> { const value = query.value.replace(/@recommended:workspace/g, '').trim().toLowerCase(); return this.tipsService.getWorkspaceRecommendations() @@ -497,6 +538,10 @@ export class InstalledExtensionsView extends ExtensionsListView { return super.show(searchInstalledQuery); } + showRecommendedLabel() { + return false; + } + } export class RecommendedExtensionsView extends ExtensionsListView { @@ -515,4 +560,8 @@ export class RecommendedExtensionsView extends ExtensionsListView { return super.show(searchInstalledQuery); } + showRecommendedLabel() { + return false; + } + } \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css index ee20c1d51a3..cf80b5fd9e8 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css @@ -27,6 +27,19 @@ height: calc(100% - 38px); } +.extensions-viewlet > .extensions .extensions-list > .monaco-list { + height: auto; +} + +.extensions-viewlet > .extensions .extensions-list > .list-actionbar-container { + padding: 4px 7px; +} + +.extensions-viewlet > .extensions .extensions-list > .list-actionbar-container.hidden, +.extensions-viewlet > .extensions .extensions-list > .list-actionbar-container .monaco-action-bar .action-item.disabled { + display: none; +} + .extensions-viewlet > .extensions .extensions-list.hidden, .extensions-viewlet > .extensions .message.hidden { display: none; @@ -103,7 +116,7 @@ overflow: hidden; } -.extensions-viewlet > .extensions .extension > .details > .header-container > .header > .version { +.extensions-viewlet > .extensions .extension > .details > .header-container > .header > .subtext-container { opacity: 0.85; font-size: 80%; padding-left: 6px; @@ -111,6 +124,14 @@ min-width: fit-content; } +.extensions-viewlet > .extensions .extension > .details > .header-container > .header > .subtext-container > span.subtext.recommended { + color: white; + background-color: green; + border: solid 1px green; + border-radius: 10px; + padding: 0 5px; +} + .extensions-viewlet > .extensions .extension > .details > .header-container > .header > .install-count:not(:empty) { font-size: 80%; margin: 0 6px; diff --git a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts index b21a040cde0..5ff2eb89af6 100644 --- a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts @@ -20,9 +20,9 @@ import { IPager, mapPager, singlePagePager } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, IExtensionManifest, - InstallExtensionEvent, DidInstallExtensionEvent, LocalExtensionType, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionTipsService + InstallExtensionEvent, DidInstallExtensionEvent, LocalExtensionType, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionTipsService, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getGalleryExtensionIdFromLocal, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { getGalleryExtensionIdFromLocal, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions } 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'; @@ -71,11 +71,15 @@ class Extension implements IExtension { get id(): string { if (this.gallery) { - return this.gallery.id; + return this.gallery.identifier.id; } return getGalleryExtensionIdFromLocal(this.local); } + get uuid(): string { + return this.gallery ? this.gallery.identifier.uuid : this.local.identifier.uuid; + } + get publisher(): string { return this.gallery ? this.gallery.publisher : this.local.manifest.publisher; } @@ -365,14 +369,14 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { queryLocal(): TPromise { return this.extensionService.getInstalled().then(result => { - const installedById = index(this.installed, e => e.local.id); + const installedById = index(this.installed, e => e.local.identifier.id); const globallyDisabledExtensions = this.extensionEnablementService.getGloballyDisabledExtensions(); const workspaceDisabledExtensions = this.extensionEnablementService.getWorkspaceDisabledExtensions(); this.installed = result.map(local => { - const extension = installedById[local.id] || new Extension(this.galleryService, this.stateProvider, local, null, this.telemetryService); + const extension = installedById[local.identifier.id] || new Extension(this.galleryService, this.stateProvider, local, null, this.telemetryService); extension.local = local; - extension.disabledGlobally = globallyDisabledExtensions.indexOf(extension.id) !== -1; - extension.disabledForWorkspace = workspaceDisabledExtensions.indexOf(extension.id) !== -1; + extension.disabledGlobally = globallyDisabledExtensions.some(d => areSameExtensions(d, extension)); + extension.disabledForWorkspace = workspaceDisabledExtensions.some(d => areSameExtensions(d, extension)); return extension; }); @@ -423,7 +427,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } private fromGallery(gallery: IGalleryExtension): Extension { - const installed = this.installed.filter(installed => installed.id === gallery.id)[0]; + const installed = this.getInstalledExtensionMatchingGallery(gallery); if (installed) { // Loading the compatible version only there is an engine property @@ -439,6 +443,21 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return new Extension(this.galleryService, this.stateProvider, null, gallery, this.telemetryService); } + private getInstalledExtensionMatchingGallery(gallery: IGalleryExtension): Extension { + for (const installed of this.installed) { + if (installed.uuid) { // Installed from Gallery + if (installed.uuid === gallery.identifier.uuid) { + return installed; + } + } else { + if (installed.id === gallery.identifier.id) { // Installed from other sources + return installed; + } + } + } + return null; + } + private syncLocalWithGalleryExtension(local: Extension, gallery: IGalleryExtension) { local.gallery = gallery; this._onChange.fire(); @@ -462,15 +481,26 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } private syncWithGallery(): TPromise { - const names = this.installed - .filter(e => e.type === LocalExtensionType.User) - .map(e => e.id); - - if (names.length === 0) { - return TPromise.as(null); + const ids = [], names = []; + for (const installed of this.installed) { + if (installed.type === LocalExtensionType.User) { + if (installed.uuid) { + ids.push(installed.uuid); + } else { + names.push(installed.id); + } + } } - return this.queryGallery({ names, pageSize: names.length }) as TPromise; + const promises = []; + if (ids.length) { + promises.push(this.queryGallery({ ids, pageSize: ids.length })); + } + if (names.length) { + promises.push(this.queryGallery({ names, pageSize: names.length })); + } + + return TPromise.join(promises) as TPromise; } private eventuallyAutoUpdateExtensions(): void { @@ -670,12 +700,12 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { private doSetEnablement(extension: IExtension, enable: boolean, workspace: boolean): TPromise { if (workspace) { - return this.extensionEnablementService.setEnablement(extension.id, enable, workspace); + return this.extensionEnablementService.setEnablement(extension, enable, workspace); } - const globalElablement = this.extensionEnablementService.setEnablement(extension.id, enable, false); + const globalElablement = this.extensionEnablementService.setEnablement(extension, enable, false); if (enable && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY) { - const workspaceEnablement = this.extensionEnablementService.setEnablement(extension.id, enable, true); + const workspaceEnablement = this.extensionEnablementService.setEnablement(extension, enable, true); return TPromise.join([globalElablement, workspaceEnablement]).then(values => values[0] || values[1]); } return globalElablement; @@ -695,7 +725,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return; } - let extension = this.installed.filter(e => e.id === gallery.id)[0]; + let extension = this.installed.filter(e => areSameExtensions(e, gallery.identifier))[0]; if (!extension) { extension = new Extension(this.galleryService, this.stateProvider, null, gallery, this.telemetryService); @@ -712,7 +742,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { private onDidInstallExtension(event: DidInstallExtensionEvent): void { const { local, zipPath, error, gallery } = event; - const installing = gallery ? this.installing.filter(e => e.extension.id === gallery.id)[0] : null; + const installing = gallery ? this.installing.filter(e => areSameExtensions(e.extension, gallery.identifier))[0] : null; const extension: Extension = installing ? installing.extension : zipPath ? new Extension(this.galleryService, this.stateProvider, null, null, this.telemetryService) : null; if (extension) { this.installing = installing ? this.installing.filter(e => e !== installing) : this.installing; @@ -738,9 +768,9 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { this._onChange.fire(); } - private onUninstallExtension(id: string): void { - const extension = this.installed.filter(e => e.local.id === id)[0]; - const newLength = this.installed.filter(e => e.local.id !== id).length; + private onUninstallExtension({ id }: IExtensionIdentifier): void { + const extension = this.installed.filter(e => e.local.identifier.id === id)[0]; + const newLength = this.installed.filter(e => e.local.identifier.id !== id).length; // TODO: Ask @Joao why is this? if (newLength === this.installed.length) { return; @@ -748,19 +778,20 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { const start = new Date(); const operation = Operation.Uninstalling; - const uninstalling = this.uninstalling.filter(e => e.extension.local.id === id)[0] || { id, operation, extension, start }; - this.uninstalling = [uninstalling, ...this.uninstalling.filter(e => e.extension.local.id !== id)]; + const uninstalling = this.uninstalling.filter(e => e.extension.local.identifier.id === id)[0] || { id, operation, extension, start }; + this.uninstalling = [uninstalling, ...this.uninstalling.filter(e => e.extension.local.identifier.id !== id)]; this._onChange.fire(); } - private onDidUninstallExtension({ id, error }: DidUninstallExtensionEvent): void { + private onDidUninstallExtension({ identifier, error }: DidUninstallExtensionEvent): void { + const id = identifier.id; if (!error) { - this.installed = this.installed.filter(e => e.local.id !== id); + this.installed = this.installed.filter(e => e.local.identifier.id !== id); } - const uninstalling = this.uninstalling.filter(e => e.extension.local.id === id)[0]; - this.uninstalling = this.uninstalling.filter(e => e.extension.local.id !== id); + const uninstalling = this.uninstalling.filter(e => e.extension.local.identifier.id === id)[0]; + this.uninstalling = this.uninstalling.filter(e => e.extension.local.identifier.id !== id); if (!uninstalling) { return; } @@ -772,19 +803,19 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { this._onChange.fire(); } - private onEnablementChanged(extensionIdentifier: string) { - const [extension] = this.local.filter(e => e.id === extensionIdentifier); + private onEnablementChanged(extensionIdentifier: IExtensionIdentifier) { + const [extension] = this.local.filter(e => areSameExtensions(e, extensionIdentifier)); if (extension) { const globallyDisabledExtensions = this.extensionEnablementService.getGloballyDisabledExtensions(); const workspaceDisabledExtensions = this.extensionEnablementService.getWorkspaceDisabledExtensions(); - extension.disabledGlobally = globallyDisabledExtensions.indexOf(extension.id) !== -1; - extension.disabledForWorkspace = workspaceDisabledExtensions.indexOf(extension.id) !== -1; + extension.disabledGlobally = globallyDisabledExtensions.some(disabled => areSameExtensions(disabled, extension)); + extension.disabledForWorkspace = workspaceDisabledExtensions.some(disabled => areSameExtensions(disabled, extension)); this._onChange.fire(); } } private getExtensionState(extension: Extension): ExtensionState { - if (extension.gallery && this.installing.some(e => e.extension.gallery && e.extension.gallery.id === extension.gallery.id)) { + if (extension.gallery && this.installing.some(e => e.extension.gallery && areSameExtensions(e.extension.gallery.identifier, extension.gallery.identifier))) { return ExtensionState.Installing; } @@ -792,7 +823,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return ExtensionState.Uninstalling; } - const local = this.installed.filter(e => e === extension || (e.gallery && extension.gallery && e.gallery.id === extension.gallery.id))[0]; + const local = this.installed.filter(e => e === extension || (e.gallery && extension.gallery && areSameExtensions(e.gallery.identifier, extension.gallery.identifier)))[0]; return local ? ExtensionState.Installed : ExtensionState.Uninstalled; } 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 17f180eedc1..518df124a0e 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 @@ -14,10 +14,10 @@ import * as ExtensionsActions from 'vs/workbench/parts/extensions/browser/extens import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, LocalExtensionType, IGalleryExtension, - DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent + DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getLocalExtensionIdFromManifest, getGalleryExtensionId, getLocalExtensionIdFromGallery } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { ExtensionManagementService, getLocalExtensionIdFromGallery, getLocalExtensionIdFromManifest } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionTipsService } from 'vs/workbench/parts/extensions/electron-browser/extensionTipsService'; import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/common/extensionEnablementService.test'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; @@ -38,14 +38,14 @@ suite('ExtensionsActions Test', () => { let installEvent: Emitter, didInstallEvent: Emitter, - uninstallEvent: Emitter, + uninstallEvent: Emitter, didUninstallEvent: Emitter; suiteSetup(() => { installEvent = new Emitter(); didInstallEvent = new Emitter(); - uninstallEvent = new Emitter(); + uninstallEvent = new Emitter(); didUninstallEvent = new Emitter(); instantiationService = new TestInstantiationService(); @@ -94,7 +94,7 @@ suite('ExtensionsActions Test', () => { const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); workbenchService.queryLocal().done(() => { - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier }))); workbenchService.queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; assert.ok(!testObject.enabled); @@ -112,7 +112,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); workbenchService.queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); assert.equal('Installing', testObject.label); @@ -140,8 +140,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); testObject.extension = extensions[0]; assert.ok(!testObject.enabled); done(); @@ -154,8 +154,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); testObject.extension = extensions[0]; assert.ok(!testObject.enabled); done(); @@ -175,7 +175,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); assert.equal('Uninstalling', testObject.label); assert.equal('extension-action uninstall uninstalling', testObject.class); @@ -219,8 +219,8 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(paged => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(testObject.enabled); assert.equal('Uninstall', testObject.label); @@ -285,7 +285,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); workbenchService.queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); assert.equal('Installing', testObject.label); @@ -301,7 +301,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); assert.equal('Uninstalling', testObject.label); assert.equal('extension-action uninstall uninstalling', testObject.class); @@ -333,7 +333,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id, version: local.manifest.version }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier, version: local.manifest.version }))); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { assert.ok(!testObject.enabled); done(); @@ -348,7 +348,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id, version: '1.0.1' }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier, version: '1.0.1' }))); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { assert.ok(!testObject.enabled); done(); @@ -363,7 +363,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id, version: '1.0.1' }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier, version: '1.0.1' }))); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { assert.ok(testObject.enabled); done(); @@ -378,10 +378,10 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - const gallery = aGalleryExtension('a', { id: local.id, version: '1.0.1' }); + const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.1' }); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { - installEvent.fire({ id: local.id, gallery }); + installEvent.fire({ identifier: local.identifier, gallery }); assert.ok(!testObject.enabled); done(); }); @@ -432,7 +432,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { testObject.extension = page.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); assert.equal('extension-action manage hide', testObject.class); assert.equal('', testObject.tooltip); @@ -448,8 +448,8 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { testObject.extension = page.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(testObject.enabled); assert.equal('extension-action manage', testObject.class); @@ -481,7 +481,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); assert.equal('extension-action manage', testObject.class); @@ -510,7 +510,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableForWorkspaceAction when there extension is disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -523,7 +523,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableForWorkspaceAction when extension is disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -536,8 +536,8 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableForWorkspaceAction when the extension is disabled in both', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -568,7 +568,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableGloballyAction when the extension is disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -581,7 +581,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableGloballyAction when the extension is disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -594,8 +594,8 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableGloballyAction when the extension is disabled in both', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -626,7 +626,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableAction when extension is installed and disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.EnableAction = instantiationService.createInstance(ExtensionsActions.EnableAction); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -639,7 +639,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableAction when extension is installed and disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableAction = instantiationService.createInstance(ExtensionsActions.EnableAction); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -671,7 +671,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { testObject.extension = page.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); done(); @@ -685,7 +685,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); done(); }); @@ -698,7 +698,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableForWorkspaceAction when the extension is disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.DisableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.DisableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -711,7 +711,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableForWorkspaceAction when the extension is disabled workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.DisableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.DisableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -742,7 +742,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableGloballyAction when the extension is disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.DisableGloballyAction = instantiationService.createInstance(ExtensionsActions.DisableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -755,7 +755,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableGloballyAction when the extension is disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.DisableGloballyAction = instantiationService.createInstance(ExtensionsActions.DisableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -798,7 +798,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableAction when extension is installed and disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.DisableAction = instantiationService.createInstance(ExtensionsActions.DisableAction); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -811,7 +811,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableAction when extension is installed and disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.DisableAction = instantiationService.createInstance(ExtensionsActions.DisableAction); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -843,7 +843,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { testObject.extension = page.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); done(); @@ -857,7 +857,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); done(); }); @@ -884,7 +884,7 @@ suite('ExtensionsActions Test', () => { const workbenchService = instantiationService.get(IExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', local); workbenchService.queryLocal().done(() => { - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local[0].id, version: '1.0.2' }), aGalleryExtension('b', { id: local[1].id, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local[0].identifier, version: '1.0.2' }), aGalleryExtension('b', { identifier: local[1].identifier, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest))); workbenchService.queryGallery().done(() => { assert.ok(testObject.enabled); done(); @@ -895,13 +895,13 @@ suite('ExtensionsActions Test', () => { test('Test UpdateAllAction when some installed extensions are outdated and some outdated are being installed', (done) => { const testObject: ExtensionsActions.UpdateAllAction = instantiationService.createInstance(ExtensionsActions.UpdateAllAction, 'id', 'label'); const local = [aLocalExtension('a', { version: '1.0.1' }), aLocalExtension('b', { version: '1.0.1' }), aLocalExtension('c', { version: '1.0.1' })]; - const gallery = [aGalleryExtension('a', { id: local[0].id, version: '1.0.2' }), aGalleryExtension('b', { id: local[1].id, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest)]; + const gallery = [aGalleryExtension('a', { identifier: local[0].identifier, version: '1.0.2' }), aGalleryExtension('b', { identifier: local[1].identifier, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest)]; const workbenchService = instantiationService.get(IExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', local); workbenchService.queryLocal().done(() => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(...gallery)); workbenchService.queryGallery().done(() => { - installEvent.fire({ id: local[0].id, gallery: gallery[0] }); + installEvent.fire({ identifier: local[0].identifier, gallery: gallery[0] }); assert.ok(testObject.enabled); done(); }); @@ -911,14 +911,14 @@ suite('ExtensionsActions Test', () => { test('Test UpdateAllAction when some installed extensions are outdated and all outdated are being installed', (done) => { const testObject: ExtensionsActions.UpdateAllAction = instantiationService.createInstance(ExtensionsActions.UpdateAllAction, 'id', 'label'); const local = [aLocalExtension('a', { version: '1.0.1' }), aLocalExtension('b', { version: '1.0.1' }), aLocalExtension('c', { version: '1.0.1' })]; - const gallery = [aGalleryExtension('a', { id: local[0].id, version: '1.0.2' }), aGalleryExtension('b', { id: local[1].id, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest)]; + const gallery = [aGalleryExtension('a', { identifier: local[0].identifier, version: '1.0.2' }), aGalleryExtension('b', { identifier: local[1].identifier, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest)]; const workbenchService = instantiationService.get(IExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', local); workbenchService.queryLocal().done(() => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(...gallery)); workbenchService.queryGallery().done(() => { - installEvent.fire({ id: local[0].id, gallery: gallery[0] }); - installEvent.fire({ id: local[1].id, gallery: gallery[1] }); + installEvent.fire({ identifier: local[0].identifier, gallery: gallery[0] }); + installEvent.fire({ identifier: local[1].identifier, gallery: gallery[1] }); assert.ok(!testObject.enabled); done(); }); @@ -938,7 +938,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); workbenchService.queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); done(); @@ -952,7 +952,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); done(); }); @@ -965,8 +965,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(testObject.enabled); assert.equal('Reload to activate', testObject.tooltip); @@ -982,11 +982,11 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - const id = getLocalExtensionIdFromGallery(gallery, gallery.version); - installEvent.fire({ id, gallery }); - didInstallEvent.fire({ id, gallery, local: aLocalExtension('a', gallery, { id }) }); - uninstallEvent.fire(id); - didUninstallEvent.fire({ id }); + const identifier = { id: getLocalExtensionIdFromGallery(gallery, gallery.version) }; + installEvent.fire({ identifier: identifier, gallery }); + didInstallEvent.fire({ identifier: identifier, gallery, local: aLocalExtension('a', gallery, { identifier }) }); + uninstallEvent.fire(identifier); + didUninstallEvent.fire({ identifier: identifier }); assert.ok(!testObject.enabled); done(); @@ -1000,8 +1000,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); assert.ok(testObject.enabled); assert.equal('Reload to deactivate', testObject.tooltip); @@ -1017,13 +1017,13 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); const gallery = aGalleryExtension('a'); const id = getLocalExtensionIdFromGallery(gallery, gallery.version); - installEvent.fire({ id, gallery }); - didInstallEvent.fire({ id, gallery, local }); + installEvent.fire({ identifier: { id }, gallery }); + didInstallEvent.fire({ identifier: { id }, gallery, local }); assert.ok(!testObject.enabled); done(); @@ -1039,9 +1039,9 @@ suite('ExtensionsActions Test', () => { workbenchService.queryLocal().done(extensions => { testObject.extension = extensions[0]; - const gallery = aGalleryExtension('a', { uuid: local.id, version: '1.0.2' }); - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + const gallery = aGalleryExtension('a', { uuid: local.identifier.id, version: '1.0.2' }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(testObject.enabled); assert.equal('Reload to update', testObject.tooltip); @@ -1053,7 +1053,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension is updated when not running', (done) => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); const local = aLocalExtension('a', { version: '1.0.1' }); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); @@ -1061,9 +1061,9 @@ suite('ExtensionsActions Test', () => { workbenchService.queryLocal().done(extensions => { testObject.extension = extensions[0]; - const gallery = aGalleryExtension('a', { id: local.id, version: '1.0.2' }); - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.2' }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(!testObject.enabled); done(); @@ -1105,7 +1105,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension is enabled when not running', (done) => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); const local = aLocalExtension('a'); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); @@ -1123,7 +1123,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension enablement is toggled when not running', (done) => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); const local = aLocalExtension('a'); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); @@ -1140,7 +1140,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension is updated when not running and enabled', (done) => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); const local = aLocalExtension('a', { version: '1.0.1' }); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); @@ -1148,9 +1148,9 @@ suite('ExtensionsActions Test', () => { workbenchService.queryLocal().done(extensions => { testObject.extension = extensions[0]; - const gallery = aGalleryExtension('a', { id: local.id, version: '1.0.2' }); - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.2' }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); workbenchService.setEnablement(extensions[0], true); assert.ok(testObject.enabled); @@ -1164,17 +1164,17 @@ suite('ExtensionsActions Test', () => { const localExtension = Object.create({ manifest: {} }); assign(localExtension, { type: LocalExtensionType.User, manifest: {} }, properties); assign(localExtension.manifest, { name, publisher: 'pub', version: '1.0.0' }, manifest); - localExtension.metadata = { id: localExtension.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; - localExtension.id = getLocalExtensionIdFromManifest(localExtension.manifest); + localExtension.identifier = { id: getLocalExtensionIdFromManifest(localExtension.manifest) }; + localExtension.metadata = { id: localExtension.identifier.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; return localExtension; } function aGalleryExtension(name: string, properties: any = {}, galleryExtensionProperties: any = {}, assets: any = {}): IGalleryExtension { const galleryExtension = Object.create({}); - assign(galleryExtension, { name, publisher: 'pub', uuid: generateUuid(), version: '1.0.0', properties: {}, assets: {} }, properties); + assign(galleryExtension, { name, publisher: 'pub', version: '1.0.0', properties: {}, assets: {} }, properties); assign(galleryExtension.properties, { dependencies: [] }, galleryExtensionProperties); assign(galleryExtension.assets, assets); - galleryExtension.id = getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name); + galleryExtension.identifier = { id: getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name), uuid: generateUuid() }; return galleryExtension; } 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 2fad5c275f0..d7c1978b713 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 @@ -15,10 +15,10 @@ import { IExtensionsWorkbenchService, ExtensionState } from 'vs/workbench/parts/ import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, LocalExtensionType, IGalleryExtension, - DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets + DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getLocalExtensionIdFromManifest, getGalleryExtensionId, getLocalExtensionIdFromGallery } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { ExtensionManagementService, getLocalExtensionIdFromGallery, getLocalExtensionIdFromManifest } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionTipsService } from 'vs/workbench/parts/extensions/electron-browser/extensionTipsService'; import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/common/extensionEnablementService.test'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; @@ -40,13 +40,13 @@ suite('ExtensionsWorkbenchService Test', () => { let installEvent: Emitter, didInstallEvent: Emitter, - uninstallEvent: Emitter, + uninstallEvent: Emitter, didUninstallEvent: Emitter; suiteSetup(() => { installEvent = new Emitter(); didInstallEvent = new Emitter(); - uninstallEvent = new Emitter(); + uninstallEvent = new Emitter(); didUninstallEvent = new Emitter(); instantiationService = new TestInstantiationService(); @@ -232,7 +232,7 @@ suite('ExtensionsWorkbenchService Test', () => { changelogUrl: 'localChangelogUrl2', }); const gallery1 = aGalleryExtension(local1.manifest.name, { - id: local1.id, + identifier: local1.identifier, displayName: 'expectedDisplayName', version: '1.5.0', publisherId: 'expectedPublisherId', @@ -309,10 +309,10 @@ suite('ExtensionsWorkbenchService Test', () => { assert.equal(ExtensionState.Uninstalled, extension.state); testObject.install(extension); - const id = getLocalExtensionIdFromGallery(gallery, gallery.version); + const identifier = { id: getLocalExtensionIdFromGallery(gallery, gallery.version) }; // Installing - installEvent.fire({ id, gallery }); + installEvent.fire({ identifier, gallery }); let local = testObject.local; assert.equal(1, local.length); const actual = local[0]; @@ -320,18 +320,18 @@ suite('ExtensionsWorkbenchService Test', () => { assert.equal(ExtensionState.Installing, actual.state); // Installed - didInstallEvent.fire({ id, gallery, local: aLocalExtension(gallery.name, gallery, { id }) }); + didInstallEvent.fire({ identifier, gallery, local: aLocalExtension(gallery.name, gallery, { identifier }) }); assert.equal(ExtensionState.Installed, actual.state); assert.equal(1, testObject.local.length); testObject.uninstall(actual); // Uninstalling - uninstallEvent.fire(id); + uninstallEvent.fire(identifier); assert.equal(ExtensionState.Uninstalling, actual.state); // Uninstalled - didUninstallEvent.fire({ id }); + didUninstallEvent.fire({ identifier }); assert.equal(ExtensionState.Uninstalled, actual.state); assert.equal(0, testObject.local.length); @@ -341,7 +341,7 @@ suite('ExtensionsWorkbenchService Test', () => { test('test extension doesnot show outdated for system extensions', () => { const local = aLocalExtension('a', { version: '1.0.1' }, { type: LocalExtensionType.System }); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { id: local.id, version: '1.0.2' }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { identifier: local.identifier, version: '1.0.2' }))); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); assert.ok(!testObject.local[0].outdated); @@ -353,8 +353,8 @@ suite('ExtensionsWorkbenchService Test', () => { testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = testObject.local[0]; testObject.uninstall(target); - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); assert.ok(!testObject.canInstall(target)); }); @@ -362,7 +362,7 @@ suite('ExtensionsWorkbenchService Test', () => { test('test canInstall returns false for a system extension', () => { const local = aLocalExtension('a', { version: '1.0.1' }, { type: LocalExtensionType.System }); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { id: local.id }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { identifier: local.identifier }))); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = testObject.local[0]; @@ -372,7 +372,7 @@ suite('ExtensionsWorkbenchService Test', () => { test('test canInstall returns true for extensions with gallery', () => { const local = aLocalExtension('a', { version: '1.0.1' }, { type: LocalExtensionType.User }); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { id: local.id }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { identifier: local.identifier }))); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = testObject.local[0]; @@ -392,11 +392,11 @@ suite('ExtensionsWorkbenchService Test', () => { assert.equal(ExtensionState.Uninstalled, extension.state); testObject.install(extension); - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); testObject.onChange(target); // Installed - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension(gallery.name, gallery, gallery) }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension(gallery.name, gallery, gallery) }); assert.ok(target.calledOnce); }); @@ -416,7 +416,7 @@ suite('ExtensionsWorkbenchService Test', () => { testObject.onChange(target); // Installing - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(target.calledOnce); }); @@ -430,7 +430,7 @@ suite('ExtensionsWorkbenchService Test', () => { testObject.uninstall(testObject.local[0]); testObject.onChange(target); - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(target.calledOnce); }); @@ -442,9 +442,9 @@ suite('ExtensionsWorkbenchService Test', () => { const target = sinon.spy(); testObject.uninstall(testObject.local[0]); - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); testObject.onChange(target); - didUninstallEvent.fire({ id: local.id }); + didUninstallEvent.fire({ identifier: local.identifier }); assert.ok(target.calledOnce); }); @@ -692,8 +692,8 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled flags are false for uninstalled extension', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false, true); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a'))); return testObject.queryGallery().then(pagedResponse => { @@ -705,8 +705,8 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled flags are false for installed enabled extension', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -717,10 +717,10 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled for workspace is set', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.d', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.e', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.d' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.e' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -732,9 +732,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled globally is set', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.d', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.d' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -746,8 +746,8 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable flags are updated for user extensions', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -759,7 +759,7 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test enable extension globally when extension is disabled for workspace', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -793,12 +793,12 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled flags are updated on change from outside', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const actual = testObject.local[0]; assert.ok(!actual.disabledForWorkspace); @@ -806,9 +806,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension with dependencies disable only itself', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -819,9 +819,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension with dependencies disable all', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c')]); instantiationService.stubPromise(IChoiceService, 'choose', 1); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -833,9 +833,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension fails if extension is a dependent of other', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -843,9 +843,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension does not fail if its dependency is a dependent of other but chosen to disable only itself', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c', { extensionDependencies: ['pub.b'] })]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -856,9 +856,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension fails if its dependency is a dependent of other', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c', { extensionDependencies: ['pub.b'] })]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -868,9 +868,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension if its dependency is a dependent of other disabled extension', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c', { extensionDependencies: ['pub.b'] })]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -883,9 +883,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension if its dependencys dependency is itself', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b', { extensionDependencies: ['pub.a'] }), aLocalExtension('c')]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -898,9 +898,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension if its dependency is dependent and is disabled', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c', { extensionDependencies: ['pub.b'] })]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -912,9 +912,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension with cyclic dependencies', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b', { extensionDependencies: ['pub.c'] }), aLocalExtension('c', { extensionDependencies: ['pub.a'] })]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -928,9 +928,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test enable extension with dependencies enable all', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -941,9 +941,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test enable extension with cyclic dependencies', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b', { extensionDependencies: ['pub.c'] }), aLocalExtension('c', { extensionDependencies: ['pub.a'] })]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -956,8 +956,8 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test change event is fired when disablement flags are changed', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = sinon.spy(); @@ -969,14 +969,14 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test change event is fired when disablement flags are changed from outside', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = sinon.spy(); testObject.onChange(target); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); assert.ok(target.calledOnce); }); @@ -985,8 +985,8 @@ suite('ExtensionsWorkbenchService Test', () => { const localExtension = Object.create({ manifest: {} }); assign(localExtension, { type: LocalExtensionType.User, manifest: {} }, properties); assign(localExtension.manifest, { name, publisher: 'pub', version: '1.0.0' }, manifest); - localExtension.metadata = { id: localExtension.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; - localExtension.id = getLocalExtensionIdFromManifest(localExtension.manifest); + localExtension.identifier = { id: getLocalExtensionIdFromManifest(localExtension.manifest) }; + localExtension.metadata = { id: localExtension.identifier.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; return localExtension; } @@ -1001,10 +1001,10 @@ suite('ExtensionsWorkbenchService Test', () => { function aGalleryExtension(name: string, properties: any = {}, galleryExtensionProperties: any = {}, assets: IGalleryExtensionAssets = noAssets): IGalleryExtension { const galleryExtension = Object.create({}); - assign(galleryExtension, { name, publisher: 'pub', uuid: generateUuid(), version: '1.0.0', properties: {}, assets: {} }, properties); + assign(galleryExtension, { name, publisher: 'pub', version: '1.0.0', properties: {}, assets: {} }, properties); assign(galleryExtension.properties, { dependencies: [] }, galleryExtensionProperties); assign(galleryExtension.assets, assets); - galleryExtension.id = getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name); + galleryExtension.identifier = { id: getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name), uuid: generateUuid() }; return galleryExtension; } diff --git a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts index 478d1d9ef84..69f877671f9 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts @@ -7,10 +7,9 @@ import nls = require('vs/nls'); import { Registry } from 'vs/platform/registry/common/platform'; import { Action, IAction } from 'vs/base/common/actions'; -import { isMacintosh } from 'vs/base/common/platform'; import { ActionItem, BaseActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarContributor } from 'vs/workbench/browser/actions'; -import { GlobalNewUntitledFileAction, SaveFileAsAction, OpenFileAction, ShowOpenedFileInNewWindow, CopyPathAction, GlobalCopyPathAction, RevealInOSAction, GlobalRevealInOSAction, pasteIntoFocusedFilesExplorerViewItem, FocusOpenEditorsView, FocusFilesExplorer, GlobalCompareResourcesAction, GlobalNewFileAction, GlobalNewFolderAction, RevertFileAction, SaveFilesAction, SaveAllAction, SaveFileAction, MoveFileToTrashAction, TriggerRenameFileAction, PasteFileAction, CopyFileAction, SelectResourceForCompareAction, CompareResourcesAction, NewFolderAction, NewFileAction, OpenToSideAction, ShowActiveFileInExplorer, CollapseExplorerView, RefreshExplorerView, CompareWithSavedAction } from 'vs/workbench/parts/files/browser/fileActions'; +import { GlobalNewUntitledFileAction, SaveFileAsAction, ShowOpenedFileInNewWindow, CopyPathAction, GlobalCopyPathAction, RevealInOSAction, GlobalRevealInOSAction, pasteIntoFocusedFilesExplorerViewItem, FocusOpenEditorsView, FocusFilesExplorer, GlobalCompareResourcesAction, GlobalNewFileAction, GlobalNewFolderAction, RevertFileAction, SaveFilesAction, SaveAllAction, SaveFileAction, MoveFileToTrashAction, TriggerRenameFileAction, PasteFileAction, CopyFileAction, SelectResourceForCompareAction, CompareResourcesAction, NewFolderAction, NewFileAction, OpenToSideAction, ShowActiveFileInExplorer, CollapseExplorerView, RefreshExplorerView, CompareWithSavedAction } from 'vs/workbench/parts/files/browser/fileActions'; import { revertLocalChangesCommand, acceptLocalChangesCommand, CONFLICT_RESOLUTION_CONTEXT } from 'vs/workbench/parts/files/browser/saveErrorHandler'; import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; @@ -19,8 +18,8 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { FileStat, Model } from 'vs/workbench/parts/files/common/explorerModel'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; -import { OpenFolderAction, OpenFileFolderAction, AddRootFolderAction, RemoveRootFolderAction, OpenFolderSettingsAction } from 'vs/workbench/browser/actions/workspaceActions'; -import { copyFocusedFilesExplorerViewItem, revealInOSFocusedFilesExplorerItem, openFocusedExplorerItemSideBySideCommand, copyPathOfFocusedExplorerItem, copyPathCommand, revealInExplorerCommand, revealInOSCommand, openFolderPickerCommand, openWindowCommand, openFileInNewWindowCommand, deleteFocusedFilesExplorerViewItemCommand, moveFocusedFilesExplorerViewItemToTrashCommand, renameFocusedFilesExplorerViewItemCommand } from 'vs/workbench/parts/files/browser/fileCommands'; +import { AddRootFolderAction, RemoveRootFolderAction, OpenFolderSettingsAction } from 'vs/workbench/browser/actions/workspaceActions'; +import { copyFocusedFilesExplorerViewItem, revealInOSFocusedFilesExplorerItem, openFocusedExplorerItemSideBySideCommand, copyPathOfFocusedExplorerItem, copyPathCommand, revealInExplorerCommand, revealInOSCommand, openWindowCommand, deleteFocusedFilesExplorerViewItemCommand, moveFocusedFilesExplorerViewItemToTrashCommand, renameFocusedFilesExplorerViewItemCommand } from 'vs/workbench/parts/files/browser/fileCommands'; import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -212,17 +211,8 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRevealInOSAction registry.registerWorkbenchAction(new SyncActionDescriptor(ShowOpenedFileInNewWindow, ShowOpenedFileInNewWindow.ID, ShowOpenedFileInNewWindow.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_O) }), 'File: Open Active File in New Window', category); registry.registerWorkbenchAction(new SyncActionDescriptor(CompareWithSavedAction, CompareWithSavedAction.ID, CompareWithSavedAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_D) }), 'File: Compare Active File with Saved', category); -if (isMacintosh) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', category); -} else { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', category); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', category); -} - // Commands -CommandsRegistry.registerCommand('_files.pickFolderAndOpen', openFolderPickerCommand); CommandsRegistry.registerCommand('_files.windowOpen', openWindowCommand); -CommandsRegistry.registerCommand('workbench.action.files.openFileInNewWindow', openFileInNewWindowCommand); const explorerCommandsWeightBonus = 10; // give our commands a little bit more weight over other default list/tree commands diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index c56c5a48fa7..e0847276fb3 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -44,9 +44,8 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; import { IEditorViewState } from 'vs/editor/common/editorCommon'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; +import { IWindowsService } from 'vs/platform/windows/common/windows'; import { withFocusedFilesExplorer, revealInOSCommand, revealInExplorerCommand, copyPathCommand } from 'vs/workbench/parts/files/browser/fileCommands'; -import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; @@ -1824,27 +1823,6 @@ export class RefreshExplorerView extends Action { } } -export class OpenFileAction extends Action { - - static ID = 'workbench.action.files.openFile'; - static LABEL = nls.localize('openFile', "Open File..."); - - constructor( - id: string, - label: string, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IWindowService private windowService: IWindowService - ) { - super(id, label); - } - - run(event?: any, data?: ITelemetryData): TPromise { - const fileResource = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' }); - - return this.windowService.pickFileAndOpen({ telemetryExtraData: data, dialogOptions: { defaultPath: fileResource ? paths.dirname(fileResource.fsPath) : void 0 } }); - } -} - export class ShowOpenedFileInNewWindow extends Action { public static ID = 'workbench.action.files.showOpenedFileInNewWindow'; @@ -1982,20 +1960,28 @@ export function validateFileName(parent: IFileStat, name: string, allowOverwriti // Invalid File name if (!paths.isValidBasename(name)) { - return nls.localize('invalidFileNameError', "The name **{0}** is not valid as a file or folder name. Please choose a different name.", name); + return nls.localize('invalidFileNameError', "The name **{0}** is not valid as a file or folder name. Please choose a different name.", trimLongName(name)); } // Max length restriction (on Windows) if (isWindows) { const fullPathLength = name.length + parent.resource.fsPath.length + 1 /* path segment */; if (fullPathLength > 255) { - return nls.localize('filePathTooLongError', "The name **{0}** results in a path that is too long. Please choose a shorter name.", name); + return nls.localize('filePathTooLongError', "The name **{0}** results in a path that is too long. Please choose a shorter name.", trimLongName(name)); } } return null; } +function trimLongName(name: string): string { + if (name && name.length > 255) { + return `${name.substr(0, 255)}...`; + } + + return name; +} + export function getWellFormedFileName(filename: string): string { if (!filename) { return filename; diff --git a/src/vs/workbench/parts/files/browser/fileCommands.ts b/src/vs/workbench/parts/files/browser/fileCommands.ts index a3f1f860180..969405abdec 100644 --- a/src/vs/workbench/parts/files/browser/fileCommands.ts +++ b/src/vs/workbench/parts/files/browser/fileCommands.ts @@ -12,7 +12,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { toResource } from 'vs/workbench/common/editor'; -import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; +import { IWindowsService } from 'vs/platform/windows/common/windows'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -50,26 +50,11 @@ export const copyPathCommand = (accessor: ServicesAccessor, resource?: URI) => { } }; -export const openFolderPickerCommand = (accessor: ServicesAccessor, forceNewWindow: boolean) => { - const windowService = accessor.get(IWindowService); - - windowService.pickFolderAndOpen({ forceNewWindow }); -}; - export const openWindowCommand = (accessor: ServicesAccessor, paths: string[], forceNewWindow: boolean) => { const windowsService = accessor.get(IWindowsService); windowsService.openWindow(paths, { forceNewWindow }); }; -export const openFileInNewWindowCommand = (accessor: ServicesAccessor) => { - const windowService = accessor.get(IWindowService); - const editorService = accessor.get(IWorkbenchEditorService); - - const fileResource = toResource(editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' }); - - windowService.pickFileAndOpen({ forceNewWindow: true, dialogOptions: { defaultPath: fileResource ? paths.dirname(fileResource.fsPath) : void 0 } }); -}; - export const revealInOSCommand = (accessor: ServicesAccessor, resource?: URI) => { // Without resource, try to look at the active editor diff --git a/src/vs/workbench/parts/files/browser/media/explorerviewlet.css b/src/vs/workbench/parts/files/browser/media/explorerviewlet.css index 4ef2be5ab15..07ff1c0ca4b 100644 --- a/src/vs/workbench/parts/files/browser/media/explorerviewlet.css +++ b/src/vs/workbench/parts/files/browser/media/explorerviewlet.css @@ -26,7 +26,7 @@ } .explorer-viewlet .explorer-item > a, -.explorer-viewlet .open-editor, +.explorer-viewlet .open-editor > a, .explorer-viewlet .editor-group { text-overflow: ellipsis; overflow: hidden; @@ -37,10 +37,6 @@ flex: 1; } -.explorer-viewlet .explorer-item::before { - flex-shrink: 0; /* fix for https://github.com/Microsoft/vscode/issues/13787 */ -} - .explorer-viewlet .explorer-item.explorer-item-edited .label-name { flex: 0; /* do not steal space when label is hidden because we are in edit mode */ } @@ -193,4 +189,4 @@ .hc-black .monaco-workbench .explorer-viewlet .open-editor, .hc-black .monaco-workbench .explorer-viewlet .editor-group { line-height: 20px; -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index 2c2d45cb9c6..4bfa0322764 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -19,7 +19,7 @@ import { memoize } from 'vs/base/common/decorators'; import { ITree } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, SortOrderConfiguration, SortOrder } from 'vs/workbench/parts/files/common/files'; -import { FileOperation, FileOperationEvent, IResolveFileOptions, FileChangeType, FileChangesEvent, IFileService } from 'vs/platform/files/common/files'; +import { FileOperation, FileOperationEvent, IResolveFileOptions, FileChangeType, FileChangesEvent, IFileService, FILES_EXCLUDE_CONFIG } from 'vs/platform/files/common/files'; import { RefreshViewExplorerAction, NewFolderAction, NewFileAction } from 'vs/workbench/parts/files/browser/fileActions'; import { FileDragAndDrop, FileFilter, FileSorter, FileController, FileRenderer, FileDataSource, FileViewletState, FileAccessibilityProvider } from 'vs/workbench/parts/files/browser/views/explorerViewer'; import { toResource } from 'vs/workbench/common/editor'; @@ -115,7 +115,11 @@ export class ExplorerView extends ViewsViewletPanel { this.filesExplorerFocusedContext = FilesExplorerFocusedContext.bindTo(contextKeyService); this.explorerFocusedContext = ExplorerFocusedContext.bindTo(contextKeyService); - this.fileEventsFilter = instantiationService.createInstance(ResourceGlobMatcher, (root: URI) => this.getFileEventsExcludes(root), (expression: glob.IExpression) => glob.parse(expression)); + this.fileEventsFilter = instantiationService.createInstance( + ResourceGlobMatcher, + (root: URI) => this.getFileEventsExcludes(root), + (event: IConfigurationChangeEvent) => event.affectsConfiguration(FILES_EXCLUDE_CONFIG) + ); } private getFileEventsExcludes(root?: URI): glob.IExpression { @@ -144,6 +148,14 @@ export class ExplorerView extends ViewsViewletPanel { return this.contextService.getWorkspace().name; } + public get title(): string { + return this.name; + } + + public set title(value: string) { + // noop + } + public set name(value) { // noop } diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 8c02ed1ac07..a1c6639f096 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -53,7 +53,6 @@ import { attachInputBoxStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; -import { distinct } from 'vs/base/common/arrays'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { getPathLabel } from 'vs/base/common/labels'; import { extractResources } from 'vs/base/browser/dnd'; @@ -909,23 +908,19 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { // Handle folders by adding to workspace if we are in workspace context const folders = result.filter(result => result.stat.isDirectory).map(result => result.stat.resource); if (folders.length > 0) { - if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { - return this.contextService.addFolders(folders); + + // If we are in no-workspace context, ask for confirmation to create a workspace + let confirmed = true; + if (this.contextService.getWorkbenchState() !== WorkbenchState.WORKSPACE) { + confirmed = this.messageService.confirmSync({ + message: folders.length > 1 ? nls.localize('dropFolders', "Do you want to add the folders to the workspace?") : nls.localize('dropFolder', "Do you want to add the folder to the workspace?"), + type: 'question', + primaryButton: folders.length > 1 ? nls.localize('addFolders', "&&Add Folders") : nls.localize('addFolder', "&&Add Folder") + }); } - // If we are in single-folder context, ask for confirmation to create a workspace - const result = this.messageService.confirmSync({ - message: folders.length > 1 ? nls.localize('dropFolders', "Do you want to add the folders to the workspace?") : nls.localize('dropFolder', "Do you want to add the folder to the workspace?"), - type: 'question', - primaryButton: folders.length > 1 ? nls.localize('addFolders', "&&Add Folders") : nls.localize('addFolder', "&&Add Folder") - }); - - if (result) { - const currentFolders = this.contextService.getWorkspace().folders.map(folder => folder.uri); - const newRoots = [...currentFolders, ...folders]; - - // Create and open workspace - return this.workspaceEditingService.createAndEnterWorkspace(distinct(newRoots.map(root => root.fsPath))); + if (confirmed) { + return this.workspaceEditingService.addFolders(folders); } } diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts index 9dd0ce444fb..5630a44f061 100644 --- a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -46,7 +46,7 @@ class MarkersDecorationsProvider implements IDecorationsProvider { weight: 100 * first.severity, bubble: true, title: markers.length === 1 ? localize('tooltip.1', "1 problem in this file") : localize('tooltip.N', "{0} problems in this file", markers.length), - letter: markers.length.toString(), + letter: markers.length < 10 ? markers.length.toString() : '+9', color: first.severity === Severity.Error ? editorErrorForeground : editorWarningForeground, }; } diff --git a/src/vs/workbench/parts/markers/common/constants.ts b/src/vs/workbench/parts/markers/common/constants.ts index 2ac068df006..d470ebfc8b0 100644 --- a/src/vs/workbench/parts/markers/common/constants.ts +++ b/src/vs/workbench/parts/markers/common/constants.ts @@ -8,6 +8,7 @@ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export default { MARKERS_PANEL_ID: 'workbench.panel.markers', MARKER_COPY_ACTION_ID: 'problems.action.copy', + MARKER_COPY_MESSAGE_ACTION_ID: 'problems.action.copyMessage', MARKER_OPEN_SIDE_ACTION_ID: 'problems.action.openToSide', MarkerFocusContextKey: new RawContextKey('problemFocus', false) diff --git a/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts b/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts index dabfc282a26..8664daaf52b 100644 --- a/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts +++ b/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts @@ -25,7 +25,8 @@ export function registerContributions(): void { }, menu: { menuId: MenuId.ProblemsPanelContext, - when: Constants.MarkerFocusContextKey + when: Constants.MarkerFocusContextKey, + group: 'navigation' }, keybinding: { keys: { @@ -34,6 +35,18 @@ export function registerContributions(): void { when: Constants.MarkerFocusContextKey } }); + registerAction({ + id: Constants.MARKER_COPY_MESSAGE_ACTION_ID, + title: localize('copyMarkerMessage', "Copy Message"), + handler(accessor) { + copyMessage(accessor.get(IPanelService)); + }, + menu: { + menuId: MenuId.ProblemsPanelContext, + when: Constants.MarkerFocusContextKey, + group: 'navigation' + } + }); } function copyMarker(panelService: IPanelService) { @@ -46,6 +59,16 @@ function copyMarker(panelService: IPanelService) { } } +function copyMessage(panelService: IPanelService) { + const activePanel = panelService.getActivePanel(); + if (activePanel instanceof MarkersPanel) { + const element = (activePanel).getFocusElement(); + if (element instanceof Marker) { + clipboard.writeText(element.marker.message); + } + } +} + interface IActionDescriptor { id: string; handler: ICommandHandler; diff --git a/src/vs/workbench/parts/preferences/browser/media/preferences.css b/src/vs/workbench/parts/preferences/browser/media/preferences.css index 22b490dcd6b..4084078ea86 100644 --- a/src/vs/workbench/parts/preferences/browser/media/preferences.css +++ b/src/vs/workbench/parts/preferences/browser/media/preferences.css @@ -73,18 +73,38 @@ padding-right: 32px; } -.settings-header-widget > .settings-count-widget { +.settings-header-widget > .settings-search-controls > .settings-count-widget { margin: 6px 0px; padding: 0px 8px; - position: absolute; - right: 10px; border-radius: 2px; + float: left; } -.settings-header-widget > .settings-count-widget.hide { +.settings-header-widget > .settings-search-controls { + position: absolute; + right: 10px; +} + +.settings-header-widget > .settings-search-controls > .settings-count-widget.hide { display: none; } +.settings-header-widget > .settings-search-controls > .prefs-fuzzy-search-toggle { + margin: 5px 3px 5px 0px; +} + +.settings-header-widget > .settings-search-controls > .prefs-fuzzy-search-toggle.hidden { + display: none; +} + +.vs .settings-header-widget > .settings-search-controls > .prefs-fuzzy-search-toggle { + background: url('regex.svg') center center no-repeat; +} + +.vs-dark .settings-header-widget > .settings-search-controls > .prefs-fuzzy-search-toggle { + background: url('regex-dark.svg') center center no-repeat; +} + .settings-header-widget > .settings-search-container { flex: 1; } @@ -106,8 +126,13 @@ padding-left:10px; } +.monaco-editor .view-zones > .settings-header-widget { + z-index: 1; +} + .monaco-editor .settings-header-widget .title-container { display: flex; + user-select: none; } .vs .monaco-editor .settings-header-widget .title-container { @@ -130,6 +155,16 @@ white-space: nowrap; } +.monaco-editor .settings-header-widget .title-container .settings-header-fuzzy-link { + margin-left: 4px; + text-decoration: underline; + cursor: pointer; +} + +.monaco-editor .settings-header-widget .title-container .settings-header-fuzzy-link.hidden { + display: none; +} + .monaco-editor .settings-group-title-widget { z-index: 1; } diff --git a/src/vs/workbench/parts/preferences/browser/media/regex-dark.svg b/src/vs/workbench/parts/preferences/browser/media/regex-dark.svg new file mode 100644 index 00000000000..c303032e6a9 --- /dev/null +++ b/src/vs/workbench/parts/preferences/browser/media/regex-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/preferences/browser/media/regex.svg b/src/vs/workbench/parts/preferences/browser/media/regex.svg new file mode 100644 index 00000000000..c677843beef --- /dev/null +++ b/src/vs/workbench/parts/preferences/browser/media/regex.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts index 910dcb09831..52779469801 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts @@ -6,8 +6,9 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as nls from 'vs/nls'; import URI from 'vs/base/common/uri'; +import { onUnexpectedError } from 'vs/base/common/errors'; import * as DOM from 'vs/base/browser/dom'; -import { Delayer } from 'vs/base/common/async'; +import { Delayer, ThrottledDelayer } from 'vs/base/common/async'; import { Dimension, Builder } from 'vs/base/browser/builder'; import { ArrayNavigator, INavigator } from 'vs/base/common/iterator'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; @@ -29,6 +30,7 @@ import { SettingsEditorModel, DefaultSettingsEditorModel } from 'vs/workbench/pa import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; import { ICodeEditor, IEditorContributionCtor } from 'vs/editor/browser/editorBrowser'; import { SearchWidget, SettingsTargetsWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets'; +import { PreferencesSearchProvider, PreferencesSearchModel } from 'vs/workbench/parts/preferences/browser/preferencesSearch'; import { ContextKeyExpr, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Command } from 'vs/editor/common/editorCommonExtensions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -49,7 +51,7 @@ import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; import { FoldingController } from 'vs/editor/contrib/folding/browser/folding'; import { FindController } from 'vs/editor/contrib/find/browser/find'; -import { SelectionHighlighter } from 'vs/editor/contrib/find/common/findController'; +import { SelectionHighlighter } from 'vs/editor/contrib/multicursor/common/multicursor'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { attachStylerCallback } from 'vs/platform/theme/common/styler'; @@ -87,10 +89,10 @@ export class DefaultPreferencesEditorInput extends ResourceEditorInput { } matches(other: any): boolean { - if (!super.matches(other)) { - return false; + if (other instanceof DefaultPreferencesEditorInput) { + return true; } - if (!(other instanceof DefaultPreferencesEditorInput)) { + if (!super.matches(other)) { return false; } return true; @@ -108,8 +110,10 @@ export class PreferencesEditor extends BaseEditor { private settingsTargetsWidget: SettingsTargetsWidget; private sideBySidePreferencesWidget: SideBySidePreferencesWidget; private preferencesRenderers: PreferencesRenderers; + private searchProvider: PreferencesSearchProvider; private delayedFilterLogging: Delayer; + private filterThrottle: ThrottledDelayer; private latestEmptyFilters: string[] = []; private lastFocusedWidget: SearchWidget | SideBySidePreferencesWidget = null; @@ -128,6 +132,8 @@ export class PreferencesEditor extends BaseEditor { this.defaultSettingsEditorContextKey = CONTEXT_SETTINGS_EDITOR.bindTo(this.contextKeyService); this.focusSettingsContextKey = CONTEXT_SETTINGS_SEARCH_FOCUS.bindTo(this.contextKeyService); this.delayedFilterLogging = new Delayer(1000); + this.searchProvider = this.instantiationService.createInstance(PreferencesSearchProvider); + this.filterThrottle = new ThrottledDelayer(200); } public createEditor(parent: Builder): void { @@ -141,7 +147,9 @@ export class PreferencesEditor extends BaseEditor { placeholder: nls.localize('SearchSettingsWidget.Placeholder', "Search Settings"), focusKey: this.focusSettingsContextKey })); - this._register(this.searchWidget.onDidChange(value => this.filterPreferences(value.trim()))); + this.searchWidget.setFuzzyToggleVisible(this.searchProvider.remoteSearchEnabled); + this._register(this.searchProvider.onRemoteSearchEnablementChanged(enabled => this.searchWidget.setFuzzyToggleVisible(enabled))); + this._register(this.searchWidget.onDidChange(value => this.onInputChanged())); this._register(this.searchWidget.onFocus(() => this.lastFocusedWidget = this.searchWidget)); this.lastFocusedWidget = this.searchWidget; @@ -155,6 +163,11 @@ export class PreferencesEditor extends BaseEditor { this.preferencesRenderers = this._register(new PreferencesRenderers()); this._register(this.workspaceContextService.onDidChangeWorkspaceFolders(() => this.onWorkspaceFoldersChanged())); this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => this.onWorkbenchStateChanged())); + + this._register(this.preferencesRenderers.onTriggeredFuzzy(() => { + this.searchWidget.fuzzyEnabled = true; + this.filterPreferences(); + })); } public clearSearchResults(): void { @@ -235,10 +248,22 @@ export class PreferencesEditor extends BaseEditor { return this.sideBySidePreferencesWidget.setInput(newInput.details, newInput.master, options).then(({ defaultPreferencesRenderer, editablePreferencesRenderer }) => { this.preferencesRenderers.defaultPreferencesRenderer = defaultPreferencesRenderer; this.preferencesRenderers.editablePreferencesRenderer = editablePreferencesRenderer; - this.filterPreferences(this.searchWidget.getValue()); + this.onInputChanged(); }); } + private onInputChanged(): void { + if (this.searchWidget.fuzzyEnabled) { + this.triggerThrottledFilter(); + } else { + this.filterPreferences(); + } + } + + private triggerThrottledFilter(): void { + this.filterThrottle.trigger(() => this.filterPreferences()); + } + private getSettingsConfigurationTarget(resource: URI): ConfigurationTarget { if (this.preferencesService.userSettingsResource.toString() === resource.toString()) { return ConfigurationTarget.USER; @@ -302,14 +327,16 @@ export class PreferencesEditor extends BaseEditor { promise.done(value => this.preferencesService.switchSettings(this.getSettingsConfigurationTarget(resource), resource)); } - private filterPreferences(filter: string) { - const count = this.preferencesRenderers.filterPreferences(filter); - const message = filter ? this.showSearchResultsMessage(count) : nls.localize('totalSettingsMessage', "Total {0} Settings", count); - this.searchWidget.showMessage(message, count); - if (count === 0) { - this.latestEmptyFilters.push(filter); - } - this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(filter)); + private filterPreferences(): TPromise { + const filter = this.searchWidget.getValue().trim(); + return this.preferencesRenderers.filterPreferences(filter, this.searchProvider, this.searchWidget.fuzzyEnabled).then(count => { + const message = filter ? this.showSearchResultsMessage(count) : nls.localize('totalSettingsMessage', "Total {0} Settings", count); + this.searchWidget.showMessage(message, count); + if (count === 0) { + this.latestEmptyFilters.push(filter); + } + this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(filter)); + }, onUnexpectedError); } private showSearchResultsMessage(count: number): string { @@ -383,9 +410,13 @@ class PreferencesRenderers extends Disposable { private _defaultPreferencesRenderer: IPreferencesRenderer; private _editablePreferencesRenderer: IPreferencesRenderer; private _settingsNavigator: SettingsNavigator; + private _filtersInProgress: TPromise[]; private _disposables: IDisposable[] = []; + private _onTriggeredFuzzy: Emitter = new Emitter(); + public onTriggeredFuzzy: Event = this._onTriggeredFuzzy.event; + public get defaultPreferencesRenderer(): IPreferencesRenderer { return this._defaultPreferencesRenderer; } @@ -400,6 +431,9 @@ class PreferencesRenderers extends Disposable { this._defaultPreferencesRenderer.onUpdatePreference(({ key, value, source }) => this._updatePreference(key, value, source, this._editablePreferencesRenderer), this, this._disposables); this._defaultPreferencesRenderer.onFocusPreference(preference => this._focusPreference(preference, this._editablePreferencesRenderer), this, this._disposables); this._defaultPreferencesRenderer.onClearFocusPreference(preference => this._clearFocus(preference, this._editablePreferencesRenderer), this, this._disposables); + if (this._defaultPreferencesRenderer.onTriggeredFuzzy) { + this._register(this._defaultPreferencesRenderer.onTriggeredFuzzy(() => this._onTriggeredFuzzy.fire())); + } } } } @@ -408,19 +442,37 @@ class PreferencesRenderers extends Disposable { this._editablePreferencesRenderer = editableSettingsRenderer; } - public filterPreferences(filter: string): number { - const defaultPreferencesFilterResult = this._filterPreferences(filter, this._defaultPreferencesRenderer); - const editablePreferencesFilterResult = this._filterPreferences(filter, this._editablePreferencesRenderer); + public filterPreferences(filter: string, searchProvider: PreferencesSearchProvider, fuzzy: boolean): TPromise { + if (this._filtersInProgress) { + // Resolved/rejected promises have no .cancel() + this._filtersInProgress.forEach(p => p.cancel && p.cancel()); + } - const defaultPreferencesFilteredGroups = defaultPreferencesFilterResult ? defaultPreferencesFilterResult.filteredGroups : this._getAllPreferences(this._defaultPreferencesRenderer); - const editablePreferencesFilteredGroups = editablePreferencesFilterResult ? editablePreferencesFilterResult.filteredGroups : this._getAllPreferences(this._editablePreferencesRenderer); - const consolidatedSettings = this._consolidateSettings(editablePreferencesFilteredGroups, defaultPreferencesFilteredGroups); - this._settingsNavigator = new SettingsNavigator(filter ? consolidatedSettings : []); + const searchModel = searchProvider.startSearch(filter, fuzzy); + this._filtersInProgress = [ + this._filterPreferences(searchModel, searchProvider, this._defaultPreferencesRenderer), + this._filterPreferences(searchModel, searchProvider, this._editablePreferencesRenderer)]; - return consolidatedSettings.length; + return TPromise.join(this._filtersInProgress).then(filterResults => { + this._filtersInProgress = null; + const defaultPreferencesFilterResult = filterResults[0]; + const editablePreferencesFilterResult = filterResults[1]; + + const defaultPreferencesFilteredGroups = defaultPreferencesFilterResult ? defaultPreferencesFilterResult.filteredGroups : this._getAllPreferences(this._defaultPreferencesRenderer); + const editablePreferencesFilteredGroups = editablePreferencesFilterResult ? editablePreferencesFilterResult.filteredGroups : this._getAllPreferences(this._editablePreferencesRenderer); + const consolidatedSettings = this._consolidateSettings(editablePreferencesFilteredGroups, defaultPreferencesFilteredGroups); + + this._settingsNavigator = new SettingsNavigator(filter ? consolidatedSettings : []); + + return consolidatedSettings.length; + }); } public focusNextPreference(forward: boolean = true) { + if (!this._settingsNavigator) { + return; + } + const setting = forward ? this._settingsNavigator.next() : this._settingsNavigator.previous(); this._focusPreference(setting, this._defaultPreferencesRenderer); this._focusPreference(setting, this._editablePreferencesRenderer); @@ -430,13 +482,17 @@ class PreferencesRenderers extends Disposable { return preferencesRenderer ? (preferencesRenderer.preferencesModel).settingsGroups : []; } - private _filterPreferences(filter: string, preferencesRenderer: IPreferencesRenderer): IFilterResult { - let filterResult = null; + private _filterPreferences(searchModel: PreferencesSearchModel, searchProvider: PreferencesSearchProvider, preferencesRenderer: IPreferencesRenderer): TPromise { if (preferencesRenderer) { - filterResult = filter ? (preferencesRenderer.preferencesModel).filterSettings(filter) : null; - preferencesRenderer.filterPreferences(filterResult); + const prefSearchP = searchModel.filterPreferences(preferencesRenderer.preferencesModel); + + return prefSearchP.then(filterResult => { + preferencesRenderer.filterPreferences(filterResult, searchProvider.remoteSearchEnabled); + return filterResult; + }); } - return filterResult; + + return TPromise.wrap(null); } private _focusPreference(preference: ISetting, preferencesRenderer: IPreferencesRenderer): void { @@ -552,6 +608,9 @@ class SideBySidePreferencesWidget extends Widget { } public clearInput(): void { + if (this.defaultPreferencesEditor) { + this.defaultPreferencesEditor.clearInput(); + } if (this.editablePreferencesEditor) { this.editablePreferencesEditor.clearInput(); } @@ -767,6 +826,14 @@ export class DefaultPreferencesEditor extends BaseTextEditor { .then(editorModel => this.getControl().setModel((editorModel).textEditorModel))); } + public clearInput(): void { + // Clear Model + this.getControl().setModel(null); + + // Pass to super + super.clearInput(); + } + public layout(dimension: Dimension) { this.getControl().layout(dimension); } @@ -856,6 +923,7 @@ abstract class AbstractSettingsEditorContribution extends Disposable { if (preferencesRenderer.associatedPreferencesModel) { preferencesRenderer.associatedPreferencesModel.dispose(); } + preferencesRenderer.preferencesModel.dispose(); preferencesRenderer.dispose(); } }); @@ -912,16 +980,16 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl protected _createPreferencesRenderer(): TPromise> { if (this.isSettingsModel()) { - return TPromise.join([this.preferencesService.createPreferencesEditorModel(this.preferencesService.defaultSettingsResource), this.preferencesService.createPreferencesEditorModel(this.editor.getModel().uri)]) - .then(([defaultSettingsModel, settingsModel]) => { + return this.preferencesService.createPreferencesEditorModel(this.editor.getModel().uri) + .then(settingsModel => { if (settingsModel instanceof SettingsEditorModel && this.editor.getModel()) { switch (settingsModel.configurationTarget) { case ConfigurationTarget.USER: - return this.instantiationService.createInstance(UserSettingsRenderer, this.editor, settingsModel, defaultSettingsModel); + return this.instantiationService.createInstance(UserSettingsRenderer, this.editor, settingsModel); case ConfigurationTarget.WORKSPACE: - return this.instantiationService.createInstance(WorkspaceSettingsRenderer, this.editor, settingsModel, defaultSettingsModel); + return this.instantiationService.createInstance(WorkspaceSettingsRenderer, this.editor, settingsModel); case ConfigurationTarget.WORKSPACE_FOLDER: - return this.instantiationService.createInstance(FolderSettingsRenderer, this.editor, settingsModel, defaultSettingsModel); + return this.instantiationService.createInstance(FolderSettingsRenderer, this.editor, settingsModel); } } return null; diff --git a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts index 08edba32488..4795b7be614 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts @@ -6,6 +6,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as nls from 'vs/nls'; import { Delayer } from 'vs/base/common/async'; +import { tail } from 'vs/base/common/arrays'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IAction } from 'vs/base/common/actions'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; @@ -19,7 +20,7 @@ import { IPreferencesService, ISettingsGroup, ISetting, IPreferencesEditorModel, import { SettingsEditorModel, DefaultSettingsEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { IContextMenuService, ContextSubMenu } from 'vs/platform/contextview/browser/contextView'; -import { SettingsGroupTitleWidget, EditPreferenceWidget, SettingsHeaderWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets'; +import { SettingsGroupTitleWidget, EditPreferenceWidget, SettingsHeaderWidget, DefaultSettingsHeaderWidget, FloatingClickWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { RangeHighlightDecorations } from 'vs/workbench/common/editor/rangeDecorations'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; @@ -40,21 +41,22 @@ export interface IPreferencesRenderer extends IDisposable { onFocusPreference: Event; onClearFocusPreference: Event; onUpdatePreference: Event<{ key: string, value: any, source: T }>; + onTriggeredFuzzy?: Event; render(): void; updatePreference(key: string, value: any, source: T): void; - filterPreferences(filterResult: IFilterResult): void; + filterPreferences(filterResult: IFilterResult, fuzzySearchAvailable: boolean): void; focusPreference(setting: T): void; clearFocus(setting: T): void; } - export class UserSettingsRenderer extends Disposable implements IPreferencesRenderer { private settingHighlighter: SettingHighlighter; private editSettingActionRenderer: EditSettingRenderer; private highlightMatchesRenderer: HighlightMatchesRenderer; private modelChangeDelayer: Delayer = new Delayer(200); + private _associatedPreferencesModel: IPreferencesEditorModel; private _onFocusPreference: Emitter = new Emitter(); public readonly onFocusPreference: Event = this._onFocusPreference.event; @@ -67,7 +69,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend private filterResult: IFilterResult; - constructor(protected editor: ICodeEditor, public readonly preferencesModel: SettingsEditorModel, private _associatedPreferencesModel: IPreferencesEditorModel, + constructor(protected editor: ICodeEditor, public readonly preferencesModel: SettingsEditorModel, @IPreferencesService protected preferencesService: IPreferencesService, @ITelemetryService private telemetryService: ITelemetryService, @ITextFileService private textFileService: ITextFileService, @@ -76,7 +78,6 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend @IInstantiationService protected instantiationService: IInstantiationService ) { super(); - this._register(preferencesModel); this.settingHighlighter = this._register(instantiationService.createInstance(SettingHighlighter, editor, this._onFocusPreference, this._onClearFocusPreference)); this.highlightMatchesRenderer = this._register(instantiationService.createInstance(HighlightMatchesRenderer, editor)); this.editSettingActionRenderer = this._register(this.instantiationService.createInstance(EditSettingRenderer, this.editor, this.preferencesModel, this.settingHighlighter)); @@ -176,7 +177,7 @@ export class WorkspaceSettingsRenderer extends UserSettingsRenderer implements I private untrustedSettingRenderer: UnsupportedWorkspaceSettingsRenderer; private workspaceConfigurationRenderer: WorkspaceConfigurationRenderer; - constructor(editor: ICodeEditor, preferencesModel: SettingsEditorModel, associatedPreferencesModel: IPreferencesEditorModel, + constructor(editor: ICodeEditor, preferencesModel: SettingsEditorModel, @IPreferencesService preferencesService: IPreferencesService, @ITelemetryService telemetryService: ITelemetryService, @ITextFileService textFileService: ITextFileService, @@ -184,7 +185,7 @@ export class WorkspaceSettingsRenderer extends UserSettingsRenderer implements I @IMessageService messageService: IMessageService, @IInstantiationService instantiationService: IInstantiationService ) { - super(editor, preferencesModel, associatedPreferencesModel, preferencesService, telemetryService, textFileService, configurationService, messageService, instantiationService); + super(editor, preferencesModel, preferencesService, telemetryService, textFileService, configurationService, messageService, instantiationService); this.untrustedSettingRenderer = this._register(instantiationService.createInstance(UnsupportedWorkspaceSettingsRenderer, editor, preferencesModel)); this.workspaceConfigurationRenderer = this._register(instantiationService.createInstance(WorkspaceConfigurationRenderer, editor, preferencesModel)); } @@ -204,7 +205,7 @@ export class FolderSettingsRenderer extends UserSettingsRenderer implements IPre private unsupportedWorkbenchSettingsRenderer: UnsupportedWorkbenchSettingsRenderer; - constructor(editor: ICodeEditor, preferencesModel: SettingsEditorModel, associatedPreferencesModel: IPreferencesEditorModel, + constructor(editor: ICodeEditor, preferencesModel: SettingsEditorModel, @IPreferencesService preferencesService: IPreferencesService, @ITelemetryService telemetryService: ITelemetryService, @ITextFileService textFileService: ITextFileService, @@ -212,7 +213,7 @@ export class FolderSettingsRenderer extends UserSettingsRenderer implements IPre @IMessageService messageService: IMessageService, @IInstantiationService instantiationService: IInstantiationService ) { - super(editor, preferencesModel, associatedPreferencesModel, preferencesService, telemetryService, textFileService, configurationService, messageService, instantiationService); + super(editor, preferencesModel, preferencesService, telemetryService, textFileService, configurationService, messageService, instantiationService); this.unsupportedWorkbenchSettingsRenderer = this._register(instantiationService.createInstance(UnsupportedWorkbenchSettingsRenderer, editor, preferencesModel)); } @@ -235,6 +236,7 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR private filteredMatchesRenderer: FilteredMatchesRenderer; private hiddenAreasRenderer: HiddenAreasRenderer; private editSettingActionRenderer: EditSettingRenderer; + private feedbackWidgetRenderer: FeedbackWidgetRenderer; private _onUpdatePreference: Emitter<{ key: string, value: any, source: ISetting }> = new Emitter<{ key: string, value: any, source: ISetting }>(); public readonly onUpdatePreference: Event<{ key: string, value: any, source: ISetting }> = this._onUpdatePreference.event; @@ -245,6 +247,8 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR private _onClearFocusPreference: Emitter = new Emitter(); public readonly onClearFocusPreference: Event = this._onClearFocusPreference.event; + public readonly onTriggeredFuzzy: Event; + private filterResult: IFilterResult; constructor(protected editor: ICodeEditor, public readonly preferencesModel: DefaultSettingsEditorModel, @@ -258,11 +262,17 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR this.settingsGroupTitleRenderer = this._register(instantiationService.createInstance(SettingsGroupTitleRenderer, editor)); this.filteredMatchesRenderer = this._register(instantiationService.createInstance(FilteredMatchesRenderer, editor)); this.editSettingActionRenderer = this._register(instantiationService.createInstance(EditSettingRenderer, editor, preferencesModel, this.settingHighlighter)); + this.feedbackWidgetRenderer = this._register(instantiationService.createInstance(FeedbackWidgetRenderer, editor)); + this._register(this.editSettingActionRenderer.onUpdateSetting(e => this._onUpdatePreference.fire(e))); - const paranthesisHidingRenderer = this._register(instantiationService.createInstance(StaticContentHidingRenderer, editor, preferencesModel.settingsGroups)); - this.hiddenAreasRenderer = this._register(instantiationService.createInstance(HiddenAreasRenderer, editor, [this.settingsGroupTitleRenderer, this.filteredMatchesRenderer, paranthesisHidingRenderer])); + const parenthesisHidingRenderer = this._register(instantiationService.createInstance(StaticContentHidingRenderer, editor, preferencesModel.settingsGroups)); + + const hiddenAreasProviders = [this.settingsGroupTitleRenderer, this.filteredMatchesRenderer, parenthesisHidingRenderer]; + this.hiddenAreasRenderer = this._register(instantiationService.createInstance(HiddenAreasRenderer, editor, hiddenAreasProviders)); this._register(this.settingsGroupTitleRenderer.onHiddenAreasChanged(() => this.hiddenAreasRenderer.render())); + + this.onTriggeredFuzzy = this.settingsHeaderRenderer.onClick; } public get associatedPreferencesModel(): IPreferencesEditorModel { @@ -277,28 +287,32 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR public render() { this.settingsGroupTitleRenderer.render(this.preferencesModel.settingsGroups); this.editSettingActionRenderer.render(this.preferencesModel.settingsGroups, this._associatedPreferencesModel); + this.feedbackWidgetRenderer.render(null); this.hiddenAreasRenderer.render(); this.settingHighlighter.clear(true); - this.settingsGroupTitleRenderer.showGroup(1); + this.settingsGroupTitleRenderer.showGroup(0); this.hiddenAreasRenderer.render(); } - public filterPreferences(filterResult: IFilterResult): void { + public filterPreferences(filterResult: IFilterResult, fuzzySearchAvailable: boolean): void { this.filterResult = filterResult; - if (!filterResult) { - this.settingHighlighter.clear(true); - this.filteredMatchesRenderer.render(null); - this.settingsHeaderRenderer.render(this.preferencesModel.settingsGroups); - this.settingsGroupTitleRenderer.render(this.preferencesModel.settingsGroups); - this.settingsGroupTitleRenderer.showGroup(1); - this.editSettingActionRenderer.render(this.preferencesModel.settingsGroups, this._associatedPreferencesModel); - } else { - this.filteredMatchesRenderer.render(filterResult); - this.settingsHeaderRenderer.render(filterResult.filteredGroups); + if (filterResult) { + this.filteredMatchesRenderer.render(filterResult, this.preferencesModel.settingsGroups); this.settingsGroupTitleRenderer.render(filterResult.filteredGroups); + this.feedbackWidgetRenderer.render(filterResult); + this.settingsHeaderRenderer.render(filterResult, fuzzySearchAvailable); this.settingHighlighter.clear(true); this.editSettingActionRenderer.render(filterResult.filteredGroups, this._associatedPreferencesModel); + } else { + this.settingHighlighter.clear(true); + this.filteredMatchesRenderer.render(null, this.preferencesModel.settingsGroups); + this.feedbackWidgetRenderer.render(null); + this.settingsHeaderRenderer.render(null); + this.settingsGroupTitleRenderer.render(this.preferencesModel.settingsGroups); + this.settingsGroupTitleRenderer.showGroup(0); + this.editSettingActionRenderer.render(this.preferencesModel.settingsGroups, this._associatedPreferencesModel); } + this.hiddenAreasRenderer.render(); } @@ -365,6 +379,9 @@ export class StaticContentHidingRenderer extends Disposable implements HiddenAre get hiddenAreas(): IRange[] { const model = this.editor.getModel(); + + // Hide extra chars for "search results" and "commonly used" groups + const lastGroup = tail(this.settingsGroups); return [ { startLineNumber: 1, @@ -378,6 +395,12 @@ export class StaticContentHidingRenderer extends Disposable implements HiddenAre endLineNumber: this.settingsGroups[0].range.endLineNumber + 4, endColumn: model.getLineMaxColumn(this.settingsGroups[0].range.endLineNumber + 4) }, + { + startLineNumber: lastGroup.range.endLineNumber + 1, + startColumn: model.getLineMinColumn(lastGroup.range.endLineNumber + 1), + endLineNumber: Math.min(model.getLineCount(), lastGroup.range.endLineNumber + 4), + endColumn: model.getLineMaxColumn(Math.min(model.getLineCount(), lastGroup.range.endLineNumber + 4)) + }, { startLineNumber: model.getLineCount() - 1, startColumn: model.getLineMinColumn(model.getLineCount() - 1), @@ -391,20 +414,20 @@ export class StaticContentHidingRenderer extends Disposable implements HiddenAre class DefaultSettingsHeaderRenderer extends Disposable { - private settingsHeaderWidget: SettingsHeaderWidget; + private settingsHeaderWidget: DefaultSettingsHeaderWidget; + public onClick: Event; constructor(private editor: ICodeEditor, scope: ConfigurationScope) { super(); const title = scope === ConfigurationScope.RESOURCE ? nls.localize('defaultFolderSettingsTitle', "Default Folder Settings") : nls.localize('defaultSettingsTitle', "Default Settings"); - this.settingsHeaderWidget = this._register(new SettingsHeaderWidget(editor, title)); + this.settingsHeaderWidget = this._register(new DefaultSettingsHeaderWidget(editor, title)); + this.onClick = this.settingsHeaderWidget.onClick; } - public render(settingsGroups: ISettingsGroup[]) { - if (settingsGroups.length) { - this.settingsHeaderWidget.setMessage(nls.localize('defaultSettings', "Place your settings in the right hand side editor to override.")); - } else { - this.settingsHeaderWidget.setMessage(nls.localize('noSettingsFound', "No Settings Found.")); - } + public render(filterResult: IFilterResult, fuzzySearchAvailable = false) { + const hasSettings = !filterResult || filterResult.filteredGroups.length > 0; + const promptFuzzy = fuzzySearchAvailable && filterResult && !filterResult.metadata; + this.settingsHeaderWidget.toggleMessage(hasSettings, promptFuzzy); } } @@ -434,9 +457,17 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea public render(settingsGroups: ISettingsGroup[]) { this.disposeWidgets(); + if (!settingsGroups) { + return; + } + this.settingsGroups = settingsGroups.slice(); this.settingsGroupTitleWidgets = []; for (const group of this.settingsGroups.slice().reverse()) { + if (group.sections.every(sect => sect.settings.length === 0)) { + continue; + } + const settingsGroupTitleWidget = this.instantiationService.createInstance(SettingsGroupTitleWidget, this.editor, group); settingsGroupTitleWidget.render(); this.settingsGroupTitleWidgets.push(settingsGroupTitleWidget); @@ -446,9 +477,11 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea this.settingsGroupTitleWidgets.reverse(); } - public showGroup(group: number) { - this.hiddenGroups = this.settingsGroups.filter((g, i) => i !== group - 1); - for (const groupTitleWidget of this.settingsGroupTitleWidgets.filter((g, i) => i !== group - 1)) { + public showGroup(groupIdx: number) { + const shownGroup = this.settingsGroupTitleWidgets[groupIdx].settingsGroup; + + this.hiddenGroups = this.settingsGroups.filter(g => g !== shownGroup); + for (const groupTitleWidget of this.settingsGroupTitleWidgets.filter(widget => widget.settingsGroup !== shownGroup)) { groupTitleWidget.toggleCollapse(true); } this._onHiddenAreasChanged.fire(); @@ -519,6 +552,115 @@ export class HiddenAreasRenderer extends Disposable { } } +export class FeedbackWidgetRenderer extends Disposable { + private static COMMENT_TEXT = 'Modify the below results to match your expectations. Assign scores to indicate their relevance. Replace this comment with any text feedback.'; + + private _feedbackWidget: FloatingClickWidget; + private _currentResult: IFilterResult; + + constructor(private editor: ICodeEditor, + @IInstantiationService private instantiationService: IInstantiationService, + @IWorkbenchEditorService private editorService: IWorkbenchEditorService, + @ITelemetryService private telemetryService: ITelemetryService + ) { + super(); + } + + public render(result: IFilterResult): void { + this._currentResult = result; + if (result && result.metadata) { + this.showWidget(); + } else if (this._feedbackWidget) { + this.disposeWidget(); + } + } + + private showWidget(): void { + if (!this._feedbackWidget) { + this._feedbackWidget = this._register(this.instantiationService.createInstance(FloatingClickWidget, this.editor, 'Provide feedback', null)); + this._register(this._feedbackWidget.onClick(() => this.getFeedback())); + this._feedbackWidget.render(); + } + } + + private getFeedback(): void { + const result = this._currentResult; + const actualResults = result.filteredGroups[0] ? result.filteredGroups[0].sections[0].settings.map(setting => setting.key) : []; + + const feedbackQuery = {}; + feedbackQuery['_comment'] = FeedbackWidgetRenderer.COMMENT_TEXT; + feedbackQuery['queryString'] = result.query; + feedbackQuery['resultScores'] = {}; + actualResults.forEach(settingKey => { + feedbackQuery['resultScores'][settingKey] = 10; + }); + + const contents = JSON.stringify(feedbackQuery, undefined, ' '); + this.editorService.openEditor({ contents }, /*sideBySide=*/true).then(feedbackEditor => { + const sendFeedbackWidget = this._register(this.instantiationService.createInstance(FloatingClickWidget, feedbackEditor.getControl(), 'Send feedback', null)); + sendFeedbackWidget.render(); + + this._register(sendFeedbackWidget.onClick(() => { + if (this.sendFeedback(feedbackEditor.getControl() as ICodeEditor, result, actualResults)) { + sendFeedbackWidget.dispose(); + } + })); + }); + } + + private sendFeedback(feedbackEditor: ICodeEditor, result: IFilterResult, actualResults: string[]): boolean { + const model = feedbackEditor.getModel(); + const expectedQueryLines = model.getLinesContent(); + let expectedQuery: string; + try { + expectedQuery = JSON.parse(expectedQueryLines.join('\n')); + if (expectedQuery['_comment'] === FeedbackWidgetRenderer.COMMENT_TEXT) { + delete expectedQuery['_comment']; + } + } catch (e) { + // invalid JSON + } + + if (expectedQuery) { + /* __GDPR__ + "settingsSearchResultFeedback" : { + "query" : { "classification": "CustomContent", "purpose": "FeatureInsight" }, + "userComment" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "actualResults" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "expectedResults" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "url" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "timestamp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('settingsSearchResultFeedback', { + query: result.query, + actualResults, + expectedQuery, + url: result.metadata.remoteUrl, + duration: result.metadata.duration, + timestamp: result.metadata.timestamp + }); + return true; + } + + return false; + } + + private disposeWidget(): void { + if (this._feedbackWidget) { + this._feedbackWidget.dispose(); + this._feedbackWidget = null; + } + } + + public dispose() { + this.disposeWidget(); + + super.dispose(); + } +} + export class FilteredMatchesRenderer extends Disposable implements HiddenAreasProvider { private decorationIds: string[] = []; @@ -530,7 +672,7 @@ export class FilteredMatchesRenderer extends Disposable implements HiddenAreasPr super(); } - public render(result: IFilterResult): void { + public render(result: IFilterResult, allSettingsGroups: ISettingsGroup[]): void { const model = this.editor.getModel(); this.hiddenAreas = []; this.editor.changeDecorations(changeAccessor => { @@ -541,6 +683,8 @@ export class FilteredMatchesRenderer extends Disposable implements HiddenAreasPr this.editor.changeDecorations(changeAccessor => { this.decorationIds = changeAccessor.deltaDecorations(this.decorationIds, result.matches.map(match => this.createDecoration(match, model))); }); + } else { + this.hiddenAreas = this.computeHiddenRanges(allSettingsGroups, allSettingsGroups, model); } } @@ -559,7 +703,7 @@ export class FilteredMatchesRenderer extends Disposable implements HiddenAreasPr const notMatchesRanges: IRange[] = []; for (const group of allSettingsGroups) { const filteredGroup = filteredGroups.filter(g => g.title === group.title)[0]; - if (!filteredGroup) { + if (!filteredGroup || filteredGroup.sections.every(sect => sect.settings.length === 0)) { notMatchesRanges.push({ startLineNumber: group.range.startLineNumber - 1, startColumn: model.getLineMinColumn(group.range.startLineNumber - 1), @@ -886,8 +1030,8 @@ class EditSettingRenderer extends Disposable { } private getDefaultActions(setting: ISetting): IAction[] { - const settingInOtherModel = this.associatedPreferencesModel.getPreference(setting.key); if (this.isDefaultSettings()) { + const settingInOtherModel = this.associatedPreferencesModel.getPreference(setting.key); return [{ id: 'setDefaultValue', label: settingInOtherModel ? nls.localize('replaceDefaultValue', "Replace in Settings") : nls.localize('copyDefaultValue', "Copy to Settings"), diff --git a/src/vs/workbench/parts/preferences/browser/preferencesSearch.ts b/src/vs/workbench/parts/preferences/browser/preferencesSearch.ts new file mode 100644 index 00000000000..52be0c1f328 --- /dev/null +++ b/src/vs/workbench/parts/preferences/browser/preferencesSearch.ts @@ -0,0 +1,329 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { TPromise } from 'vs/base/common/winjs.base'; +import Event, { Emitter } from 'vs/base/common/event'; +import { ISettingsEditorModel, IFilterResult, ISetting, ISettingsGroup, IWorkbenchSettingsConfiguration, IFilterMetadata } from 'vs/workbench/parts/preferences/common/preferences'; +import { IRange, Range } from 'vs/editor/common/core/range'; +import { distinct } from 'vs/base/common/arrays'; +import * as strings from 'vs/base/common/strings'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters'; +import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; + +export interface IEndpointDetails { + urlBase: string; + key: string; + boost: number; +} + +export class PreferencesSearchProvider { + private _onRemoteSearchEnablementChanged = new Emitter(); + public onRemoteSearchEnablementChanged: Event = this._onRemoteSearchEnablementChanged.event; + + constructor( @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService) { + configurationService.onDidChangeConfiguration(() => this._onRemoteSearchEnablementChanged.fire(this.remoteSearchEnabled)); + } + + get remoteSearchEnabled(): boolean { + const endpoint = this.endpoint; + return !!endpoint.urlBase && !!endpoint.key; + } + + get endpoint(): IEndpointDetails { + const workbenchSettings = this.configurationService.getConfiguration().workbench.settings; + return { + urlBase: workbenchSettings.experimentalFuzzySearchEndpoint, + key: workbenchSettings.experimentalFuzzySearchKey, + boost: workbenchSettings.experimentalFuzzySearchBoost + }; + } + + startSearch(filter: string, remote: boolean): PreferencesSearchModel { + return new PreferencesSearchModel(this, filter, remote); + } +} + +export class PreferencesSearchModel { + private _localProvider: LocalSearchProvider; + private _remoteProvider: RemoteSearchProvider; + + constructor(private provider: PreferencesSearchProvider, private filter: string, remote: boolean) { + this._localProvider = new LocalSearchProvider(filter); + + if (remote && filter) { + this._remoteProvider = new RemoteSearchProvider(filter, this.provider.endpoint); + } + } + + filterPreferences(preferencesModel: ISettingsEditorModel): TPromise { + if (!this.filter) { + return TPromise.wrap(null); + } + + if (this._remoteProvider) { + return this._remoteProvider.filterPreferences(preferencesModel).then(null, err => { + return this._localProvider.filterPreferences(preferencesModel); + }); + } else { + return this._localProvider.filterPreferences(preferencesModel); + } + } +} + +class LocalSearchProvider { + private _filter: string; + + constructor(filter: string) { + this._filter = filter; + } + + filterPreferences(preferencesModel: ISettingsEditorModel): TPromise { + const regex = strings.createRegExp(this._filter, false, { global: true }); + + const groupFilter = (group: ISettingsGroup) => { + return regex.test(group.title); + }; + + const settingFilter = (setting: ISetting) => { + return new SettingMatches(this._filter, setting, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; + }; + + return TPromise.wrap(preferencesModel.filterSettings(this._filter, groupFilter, settingFilter)); + } +} + +export interface IRemoteScores { + [key: string]: number; +} + +interface IRemoteResult { + metadata: IFilterMetadata; + scores: IRemoteScores; +} + +class RemoteSearchProvider { + private _filter: string; + private _remoteSearchP: TPromise; + + constructor(filter: string, endpoint: IEndpointDetails) { + this._filter = filter; + this._remoteSearchP = filter ? getSettingsFromBing(filter, endpoint) : TPromise.wrap(null); + } + + filterPreferences(preferencesModel: ISettingsEditorModel): TPromise { + return this._remoteSearchP.then(remoteResult => { + const settingFilter = (setting: ISetting) => { + if (!!remoteResult.scores[setting.key]) { + const settingMatches = new SettingMatches(this._filter, setting, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; + if (settingMatches.length) { + return settingMatches; + } else { + return [new Range(setting.keyRange.startLineNumber, setting.keyRange.startColumn, setting.keyRange.endLineNumber, setting.keyRange.startColumn)]; + } + } else { + return null; + } + }; + + if (remoteResult) { + const sortedNames = Object.keys(remoteResult.scores).sort((a, b) => remoteResult.scores[b] - remoteResult.scores[a]); + const result = preferencesModel.filterSettings(this._filter, group => null, settingFilter, sortedNames); + result.metadata = remoteResult.metadata; + return result; + } else { + return null; + } + }); + } +} + +function getSettingsFromBing(filter: string, endpoint: IEndpointDetails): TPromise { + const url = prepareUrl(filter, endpoint); + console.log('fetching: ' + url); + const start = Date.now(); + const p = fetch(url, { + headers: new Headers({ + 'User-Agent': 'request', + 'Content-Type': 'application/json; charset=utf-8', + 'api-key': endpoint.key + }) + }) + .then(r => r.json()) + .then(result => { + const timestamp = Date.now(); + const duration = timestamp - start; + console.log('time: ' + duration / 1000); + const suggestions = (result.value || []) + .map(r => ({ + name: r.setting || r.Setting, + score: r['@search.score'] + })); + + const scores = Object.create(null); + suggestions.forEach(s => { + const name = s.name + .replace(/^"/, '') + .replace(/"$/, ''); + scores[name] = s.score; + }); + + return { + metadata: { + remoteUrl: url, + duration, + timestamp + }, + scores + }; + }); + + return TPromise.as(p as any); +} + +const API_VERSION = 'api-version=2015-02-28-Preview'; +const QUERY_TYPE = 'querytype=full'; +const SCORING_PROFILE = 'scoringProfile=ranking1'; + +function escapeSpecialChars(query: string): string { + return query.replace(/\./g, ' ') + .replace(/[\\/+\-&|!"~*?:(){}\[\]\^]/g, '\\$&') + .replace(/ /g, ' ') // collapse spaces + .trim(); +} + +function prepareUrl(query: string, endpoint: IEndpointDetails): string { + query = escapeSpecialChars(query); + const boost = endpoint.boost || 1; + const userQuery = `(${query})^${boost}`; + + // Appending Fuzzy after each word. + query = query.replace(/\ +/g, '~ ') + '~'; + + return `${endpoint.urlBase}?${API_VERSION}&search=${encodeURIComponent(userQuery + ' || ' + query)}&${QUERY_TYPE}&${SCORING_PROFILE}`; +} + +class SettingMatches { + + private readonly descriptionMatchingWords: Map = new Map(); + private readonly keyMatchingWords: Map = new Map(); + private readonly valueMatchingWords: Map = new Map(); + + public readonly matches: IRange[]; + + constructor(searchString: string, setting: ISetting, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) { + this.matches = distinct(this._findMatchesInSetting(searchString, setting), (match) => `${match.startLineNumber}_${match.startColumn}_${match.endLineNumber}_${match.endColumn}_`); + } + + private _findMatchesInSetting(searchString: string, setting: ISetting): IRange[] { + const result = this._doFindMatchesInSetting(searchString, setting); + if (setting.overrides && setting.overrides.length) { + for (const subSetting of setting.overrides) { + const subSettingMatches = new SettingMatches(searchString, subSetting, this.valuesMatcher); + let words = searchString.split(' '); + const descriptionRanges: IRange[] = this.getRangesForWords(words, this.descriptionMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); + const keyRanges: IRange[] = this.getRangesForWords(words, this.keyMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); + const subSettingKeyRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.keyMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.valueMatchingWords]); + const subSettinValueRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.valueMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.keyMatchingWords]); + result.push(...descriptionRanges, ...keyRanges, ...subSettingKeyRanges, ...subSettinValueRanges); + result.push(...subSettingMatches.matches); + } + } + return result; + } + + private _doFindMatchesInSetting(searchString: string, setting: ISetting): IRange[] { + const registry: { [qualifiedKey: string]: IJSONSchema } = Registry.as(Extensions.Configuration).getConfigurationProperties(); + const schema: IJSONSchema = registry[setting.key]; + + let words = searchString.split(' '); + const settingKeyAsWords: string = setting.key.split('.').join(' '); + + for (const word of words) { + for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) { + const descriptionMatches = matchesWords(word, setting.description[lineIndex], true); + if (descriptionMatches) { + this.descriptionMatchingWords.set(word, descriptionMatches.map(match => this.toDescriptionRange(setting, match, lineIndex))); + } + } + + const keyMatches = or(matchesWords, matchesCamelCase)(word, settingKeyAsWords); + if (keyMatches) { + this.keyMatchingWords.set(word, keyMatches.map(match => this.toKeyRange(setting, match))); + } + + const valueMatches = typeof setting.value === 'string' ? matchesContiguousSubString(word, setting.value) : null; + if (valueMatches) { + this.valueMatchingWords.set(word, valueMatches.map(match => this.toValueRange(setting, match))); + } else if (schema && schema.enum && schema.enum.some(enumValue => typeof enumValue === 'string' && !!matchesContiguousSubString(word, enumValue))) { + this.valueMatchingWords.set(word, []); + } + } + + const descriptionRanges: IRange[] = []; + for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) { + const matches = or(matchesContiguousSubString)(searchString, setting.description[lineIndex] || '') || []; + descriptionRanges.push(...matches.map(match => this.toDescriptionRange(setting, match, lineIndex))); + } + if (descriptionRanges.length === 0) { + descriptionRanges.push(...this.getRangesForWords(words, this.descriptionMatchingWords, [this.keyMatchingWords, this.valueMatchingWords])); + } + + const keyMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.key); + const keyRanges: IRange[] = keyMatches ? keyMatches.map(match => this.toKeyRange(setting, match)) : this.getRangesForWords(words, this.keyMatchingWords, [this.descriptionMatchingWords, this.valueMatchingWords]); + + let valueRanges: IRange[] = []; + if (setting.value && typeof setting.value === 'string') { + const valueMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.value); + valueRanges = valueMatches ? valueMatches.map(match => this.toValueRange(setting, match)) : this.getRangesForWords(words, this.valueMatchingWords, [this.keyMatchingWords, this.descriptionMatchingWords]); + } else { + valueRanges = this.valuesMatcher(searchString, setting); + } + + return [...descriptionRanges, ...keyRanges, ...valueRanges]; + } + + private getRangesForWords(words: string[], from: Map, others: Map[]): IRange[] { + const result: IRange[] = []; + for (const word of words) { + const ranges = from.get(word); + if (ranges) { + result.push(...ranges); + } else if (others.every(o => !o.has(word))) { + return []; + } + } + return result; + } + + private toKeyRange(setting: ISetting, match: IMatch): IRange { + return { + startLineNumber: setting.keyRange.startLineNumber, + startColumn: setting.keyRange.startColumn + match.start, + endLineNumber: setting.keyRange.startLineNumber, + endColumn: setting.keyRange.startColumn + match.end + }; + } + + private toDescriptionRange(setting: ISetting, match: IMatch, lineIndex: number): IRange { + return { + startLineNumber: setting.descriptionRanges[lineIndex].startLineNumber, + startColumn: setting.descriptionRanges[lineIndex].startColumn + match.start, + endLineNumber: setting.descriptionRanges[lineIndex].endLineNumber, + endColumn: setting.descriptionRanges[lineIndex].startColumn + match.end + }; + } + + private toValueRange(setting: ISetting, match: IMatch): IRange { + return { + startLineNumber: setting.valueRange.startLineNumber, + startColumn: setting.valueRange.startColumn + match.start + 1, + endLineNumber: setting.valueRange.startLineNumber, + endColumn: setting.valueRange.startColumn + match.end + 1 + }; + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/preferences/browser/preferencesService.ts b/src/vs/workbench/parts/preferences/browser/preferencesService.ts index fdf08f805c2..b7860ec16de 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesService.ts @@ -8,7 +8,6 @@ import * as network from 'vs/base/common/network'; import { TPromise } from 'vs/base/common/winjs.base'; import * as nls from 'vs/nls'; import URI from 'vs/base/common/uri'; -import { ResourceMap } from 'vs/base/common/map'; import * as labels from 'vs/base/common/labels'; import * as strings from 'vs/base/common/strings'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -18,7 +17,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { Position as EditorPosition, IEditor, IEditorOptions } from 'vs/platform/editor/common/editor'; -import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; +import { ICommonCodeEditor, IModel } from 'vs/editor/common/editorCommon'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; @@ -27,7 +26,7 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IPreferencesService, IPreferencesEditorModel, ISetting, getSettingsTargetName, FOLDER_SETTINGS_PATH, DEFAULT_SETTINGS_EDITOR_SETTING } from 'vs/workbench/parts/preferences/common/preferences'; -import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, WorkspaceConfigModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; +import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, WorkspaceConfigModel, DefaultSettingsModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { DefaultPreferencesEditorInput, PreferencesEditorInput } from 'vs/workbench/parts/preferences/browser/preferencesEditor'; import { KeybindingsEditorInput } from 'vs/workbench/parts/preferences/browser/keybindingsEditor'; @@ -40,6 +39,7 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IModeService } from 'vs/editor/common/services/modeService'; const emptyEditableSettingsContent = '{\n}'; @@ -47,12 +47,15 @@ export class PreferencesService extends Disposable implements IPreferencesServic _serviceBrand: any; - // TODO:@sandy merge these models into editor inputs by extending resource editor model - private defaultPreferencesEditorModels: ResourceMap>>; private lastOpenedSettingsInput: PreferencesEditorInput = null; private _onDispose: Emitter = new Emitter(); + private _defaultSettingsUriCounter = 0; + private _defaultSettingsContentModel: DefaultSettingsModel; + private _defaultResourceSettingsUriCounter = 0; + private _defaultResourceSettingsContentModel: DefaultSettingsModel; + constructor( @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEditorGroupService private editorGroupService: IEditorGroupService, @@ -69,10 +72,10 @@ export class PreferencesService extends Disposable implements IPreferencesServic @IExtensionService private extensionService: IExtensionService, @IKeybindingService keybindingService: IKeybindingService, @IModelService private modelService: IModelService, - @IJSONEditingService private jsonEditingService: IJSONEditingService + @IJSONEditingService private jsonEditingService: IJSONEditingService, + @IModeService private modeService: IModeService ) { super(); - this.defaultPreferencesEditorModels = new ResourceMap>>(); this.editorGroupService.onEditorsChanged(() => { const activeEditorInput = this.editorService.getActiveEditorInput(); if (activeEditorInput instanceof PreferencesEditorInput) { @@ -92,8 +95,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic }); } - readonly defaultSettingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/settings.json' }); - readonly defaultResourceSettingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/resourceSettings.json' }); readonly defaultKeybindingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/keybindings.json' }); private readonly workspaceConfigSettingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'settings', path: '/workspaceSettings.json' }); @@ -109,54 +110,35 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, resource); } - resolveContent(uri: URI): TPromise { - const workspaceSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); - if (workspaceSettingsUri && workspaceSettingsUri.toString() === uri.toString()) { - return this.resolveSettingsContentFromWorkspaceConfiguration(); - } - return this.createPreferencesEditorModel(uri) - .then(preferencesEditorModel => preferencesEditorModel ? preferencesEditorModel.content : null); - } - - createPreferencesEditorModel(uri: URI): TPromise> { - let promise = this.defaultPreferencesEditorModels.get(uri); - if (promise) { - return promise; - } - - if (this.defaultSettingsResource.toString() === uri.toString()) { - promise = TPromise.join([this.extensionService.onReady(), this.fetchMostCommonlyUsedSettings()]) - .then(result => { - const mostCommonSettings = result[1]; - const model = this.instantiationService.createInstance(DefaultSettingsEditorModel, uri, mostCommonSettings, ConfigurationScope.WINDOW); + resolveModel(uri: URI): TPromise { + if (this.isDefaultSettingsResource(uri) || this.isDefaultResourceSettingsResource(uri)) { + return this.extensionService.onReady() + .then(() => { + const scope = this.isDefaultSettingsResource(uri) ? ConfigurationScope.WINDOW : ConfigurationScope.RESOURCE; + const settingsModel = this.getDefaultSettingsModel(scope); + const mode = this.modeService.getOrCreateMode('json'); + const model = this._register(this.modelService.createModel(settingsModel.content, mode, uri)); return model; }); - this.defaultPreferencesEditorModels.set(uri, promise); - return promise; - } - - if (this.defaultResourceSettingsResource.toString() === uri.toString()) { - promise = TPromise.join([this.extensionService.onReady(), this.fetchMostCommonlyUsedSettings()]) - .then(result => { - const mostCommonSettings = result[1]; - const model = this.instantiationService.createInstance(DefaultSettingsEditorModel, uri, mostCommonSettings, ConfigurationScope.RESOURCE); - return model; - }); - this.defaultPreferencesEditorModels.set(uri, promise); - return promise; } if (this.defaultKeybindingsResource.toString() === uri.toString()) { - const model = this.instantiationService.createInstance(DefaultKeybindingsEditorModel, uri); - promise = TPromise.wrap(model); - this.defaultPreferencesEditorModels.set(uri, promise); - return promise; + const defaultKeybindingsEditorModel = this.instantiationService.createInstance(DefaultKeybindingsEditorModel, uri); + const mode = this.modeService.getOrCreateMode('json'); + const model = this._register(this.modelService.createModel(defaultKeybindingsEditorModel.content, mode, uri)); + return TPromise.as(model); + } + + return TPromise.as(null); + } + + createPreferencesEditorModel(uri: URI): TPromise> { + if (this.isDefaultSettingsResource(uri) || this.isDefaultResourceSettingsResource(uri)) { + return this.createDefaultSettingsEditorModel(uri); } if (this.workspaceConfigSettingsResource.toString() === uri.toString()) { - promise = this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, uri); - this.defaultPreferencesEditorModels.set(uri, promise); - return promise; + return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, uri); } if (this.getEditableSettingsURI(ConfigurationTarget.USER).toString() === uri.toString()) { @@ -268,11 +250,20 @@ export class PreferencesService extends Disposable implements IPreferencesServic }); } + private isDefaultSettingsResource(uri: URI): boolean { + return uri.authority === 'defaultsettings' && uri.scheme === network.Schemas.vscode && !!uri.path.match(/\/(\d+\/)?settings\.json$/); + } + + private isDefaultResourceSettingsResource(uri: URI): boolean { + return uri.authority === 'defaultsettings' && uri.scheme === network.Schemas.vscode && !!uri.path.match(/\/(\d+\/)?resourceSettings\.json$/); + } + private getDefaultSettingsResource(configurationTarget: ConfigurationTarget): URI { if (configurationTarget === ConfigurationTarget.WORKSPACE_FOLDER) { - return this.defaultResourceSettingsResource; + return URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: `/${this._defaultResourceSettingsUriCounter++}/resourceSettings.json` }); + } else { + return URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: `/${this._defaultSettingsUriCounter++}/settings.json` }); } - return this.defaultSettingsResource; } private getPreferencesEditorInputName(target: ConfigurationTarget, resource: URI): string { @@ -298,17 +289,27 @@ export class PreferencesService extends Disposable implements IPreferencesServic return TPromise.wrap(null); } - private resolveSettingsContentFromWorkspaceConfiguration(): TPromise { - if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { - return this.textModelResolverService.createModelReference(this.contextService.getWorkspace().configuration) - .then(reference => { - const model = reference.object.textEditorModel; - const settingsContent = WorkspaceConfigModel.getSettingsContentFromConfigContent(model.getValue()); - reference.dispose(); - return TPromise.as(settingsContent ? settingsContent : emptyEditableSettingsContent); - }); + private createDefaultSettingsEditorModel(defaultSettingsUri: URI): TPromise { + return this.textModelResolverService.createModelReference(defaultSettingsUri) + .then(reference => { + const scope = this.isDefaultSettingsResource(defaultSettingsUri) ? ConfigurationScope.WINDOW : ConfigurationScope.RESOURCE; + return this.instantiationService.createInstance(DefaultSettingsEditorModel, defaultSettingsUri, reference, scope, this.getDefaultSettingsModel(scope).settingsGroups); + }); + } + + private getDefaultSettingsModel(scope: ConfigurationScope): DefaultSettingsModel { + switch (scope) { + case ConfigurationScope.WINDOW: + if (!this._defaultSettingsContentModel) { + this._defaultSettingsContentModel = new DefaultSettingsModel(this.getMostCommonlyUsedSettings(), scope); + } + return this._defaultSettingsContentModel; + case ConfigurationScope.RESOURCE: + if (!this._defaultResourceSettingsContentModel) { + this._defaultResourceSettingsContentModel = new DefaultSettingsModel(this.getMostCommonlyUsedSettings(), scope); + } + return this._defaultResourceSettingsContentModel; } - return TPromise.as(null); } private getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): URI { @@ -349,8 +350,8 @@ export class PreferencesService extends Disposable implements IPreferencesServic }); } - private fetchMostCommonlyUsedSettings(): TPromise { - return TPromise.wrap([ + private getMostCommonlyUsedSettings(): string[] { + return [ 'files.autoSave', 'editor.fontSize', 'editor.fontFamily', @@ -362,7 +363,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic 'editor.wordWrap', 'files.exclude', 'files.associations' - ]); + ]; } private getPosition(language: string, codeEditor: ICommonCodeEditor): TPromise { @@ -407,7 +408,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic public dispose(): void { this._onDispose.fire(); - this.defaultPreferencesEditorModels.clear(); super.dispose(); } } diff --git a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts index 0eeeadfeb47..cf03fd27d6f 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts @@ -10,6 +10,7 @@ import * as DOM from 'vs/base/browser/dom'; import { TPromise } from 'vs/base/common/winjs.base'; import { Disposable } from 'vs/base/common/lifecycle'; import { Widget } from 'vs/base/browser/ui/widget'; +import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox'; import Event, { Emitter } from 'vs/base/common/event'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; @@ -22,7 +23,7 @@ import { ISettingsGroup, IPreferencesService, getSettingsTargetName } from 'vs/w import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IAction, IActionRunner } from 'vs/base/common/actions'; -import { attachInputBoxStyler, attachStylerCallback, attachSelectBoxStyler } from 'vs/platform/theme/common/styler'; +import { attachInputBoxStyler, attachStylerCallback, attachSelectBoxStyler, attachCheckboxStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Position } from 'vs/editor/common/core/position'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -42,10 +43,10 @@ export class SettingsHeaderWidget extends Widget implements IViewZone { private id: number; private _domNode: HTMLElement; - private titleContainer: HTMLElement; + protected titleContainer: HTMLElement; private messageElement: HTMLElement; - constructor(private editor: ICodeEditor, private title: string) { + constructor(protected editor: ICodeEditor, private title: string) { super(); this.create(); this._register(this.editor.onDidChangeConfiguration(() => this.layout())); @@ -64,7 +65,7 @@ export class SettingsHeaderWidget extends Widget implements IViewZone { return 0; } - private create() { + protected create() { this._domNode = DOM.$('.settings-header-widget'); this.titleContainer = DOM.append(this._domNode, DOM.$('.title-container')); @@ -102,6 +103,38 @@ export class SettingsHeaderWidget extends Widget implements IViewZone { } } +export class DefaultSettingsHeaderWidget extends SettingsHeaderWidget { + + private linkElement: HTMLElement; + private _onClick = this._register(new Emitter()); + public onClick: Event = this._onClick.event; + + protected create() { + super.create(); + + this.linkElement = DOM.append(this.titleContainer, DOM.$('a.settings-header-fuzzy-link')); + this.linkElement.textContent = localize('defaultSettingsFuzzyPrompt', "Try fuzzy search!"); + + this.onclick(this.linkElement, e => this._onClick.fire()); + this.toggleMessage(true); + } + + public toggleMessage(hasSettings: boolean, promptFuzzy = false): void { + if (hasSettings) { + this.setMessage(localize('defaultSettings', "Place your settings in the right hand side editor to override.")); + DOM.addClass(this.linkElement, 'hidden'); + } else { + this.setMessage(localize('noSettingsFound', "No Settings Found.")); + + if (promptFuzzy) { + DOM.removeClass(this.linkElement, 'hidden'); + } else { + DOM.addClass(this.linkElement, 'hidden'); + } + } + } +} + export class SettingsGroupTitleWidget extends Widget implements IViewZone { private id: number; @@ -400,6 +433,8 @@ export class SearchWidget extends Widget { private countElement: HTMLElement; private searchContainer: HTMLElement; private inputBox: InputBox; + private fuzzyToggle: Checkbox; + private controlsDiv: HTMLElement; private _onDidChange: Emitter = this._register(new Emitter()); public readonly onDidChange: Event = this._onDidChange.event; @@ -417,10 +452,31 @@ export class SearchWidget extends Widget { this.create(parent); } + public get fuzzyEnabled(): boolean { + return this.fuzzyToggle.checked && this.fuzzyToggle.enabled; + } + + public set fuzzyEnabled(value: boolean) { + this.fuzzyToggle.checked = value; + } + private create(parent: HTMLElement) { this.domNode = DOM.append(parent, DOM.$('div.settings-header-widget')); this.createSearchContainer(DOM.append(this.domNode, DOM.$('div.settings-search-container'))); - this.countElement = DOM.append(this.domNode, DOM.$('.settings-count-widget')); + this.controlsDiv = DOM.append(this.domNode, DOM.$('div.settings-search-controls')); + this.fuzzyToggle = this._register(new Checkbox({ + actionClassName: 'prefs-fuzzy-search-toggle', + isChecked: false, + onChange: () => { + this.inputBox.focus(); + this._onDidChange.fire(); + }, + title: localize('enableFuzzySearch', 'Enable experimental fuzzy search') + })); + DOM.append(this.controlsDiv, this.fuzzyToggle.domNode); + this._register(attachCheckboxStyler(this.fuzzyToggle, this.themeService)); + + this.countElement = DOM.append(this.controlsDiv, DOM.$('.settings-count-widget')); this._register(attachStylerCallback(this.themeService, { badgeBackground, contrastBorder }, colors => { const background = colors.badgeBackground ? colors.badgeBackground.toString() : null; const border = colors.contrastBorder ? colors.contrastBorder.toString() : null; @@ -462,10 +518,20 @@ export class SearchWidget extends Widget { this.countElement.textContent = message; this.inputBox.inputElement.setAttribute('aria-label', message); DOM.toggleClass(this.countElement, 'no-results', count === 0); - this.inputBox.inputElement.style.paddingRight = DOM.getTotalWidth(this.countElement) + 20 + 'px'; + this.inputBox.inputElement.style.paddingRight = this.getControlsWidth() + 'px'; this.styleCountElementForeground(); } + public setFuzzyToggleVisible(visible: boolean): void { + if (visible) { + this.fuzzyToggle.domNode.classList.remove('hidden'); + this.fuzzyToggle.enable(); + } else { + this.fuzzyToggle.domNode.classList.add('hidden'); + this.fuzzyToggle.disable(); + } + } + private styleCountElementForeground() { const colorId = DOM.hasClass(this.countElement, 'no-results') ? errorForeground : badgeForeground; const color = this.themeService.getTheme().getColor(colorId); @@ -478,10 +544,14 @@ export class SearchWidget extends Widget { this.inputBox.inputElement.style.paddingRight = '0px'; } else { DOM.removeClass(this.countElement, 'hide'); - this.inputBox.inputElement.style.paddingRight = DOM.getTotalWidth(this.countElement) + 20 + 'px'; + this.inputBox.inputElement.style.paddingRight = this.getControlsWidth() + 'px'; } } + private getControlsWidth(): number { + return DOM.getTotalWidth(this.countElement) + DOM.getTotalWidth(this.fuzzyToggle.domNode) + 20; + } + public focus() { this.inputBox.focus(); if (this.getValue()) { diff --git a/src/vs/workbench/parts/preferences/common/preferences.ts b/src/vs/workbench/parts/preferences/common/preferences.ts index 4bd6f7acdef..035a15c877b 100644 --- a/src/vs/workbench/parts/preferences/common/preferences.ts +++ b/src/vs/workbench/parts/preferences/common/preferences.ts @@ -9,12 +9,24 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IEditor, Position, IEditorOptions } from 'vs/platform/editor/common/editor'; +import { IModel } from 'vs/editor/common/editorCommon'; import { IKeybindingItemEntry } from 'vs/workbench/parts/preferences/common/keybindingsEditorModel'; import { IRange } from 'vs/editor/common/core/range'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { join } from 'vs/base/common/paths'; import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +export interface IWorkbenchSettingsConfiguration { + workbench: { + settings: { + openDefaultSettings: boolean; + experimentalFuzzySearchEndpoint: string; + experimentalFuzzySearchKey: string; + experimentalFuzzySearchBoost: number; + } + }; +} + export interface ISettingsGroup { id: string; range: IRange; @@ -42,22 +54,34 @@ export interface ISetting { } export interface IFilterResult { + query: string; filteredGroups: ISettingsGroup[]; allGroups: ISettingsGroup[]; matches: IRange[]; + fuzzySearchAvailable?: boolean; + metadata?: IFilterMetadata; +} + +export interface IFilterMetadata { + remoteUrl: string; + timestamp: number; + duration: number; } export interface IPreferencesEditorModel { uri: URI; - content: string; getPreference(key: string): T; dispose(): void; } +export type IGroupFilter = (group: ISettingsGroup) => boolean; +export type ISettingFilter = (setting: ISetting) => IRange[]; + export interface ISettingsEditorModel extends IPreferencesEditorModel { settingsGroups: ISettingsGroup[]; groupsTerms: string[]; - filterSettings(filter: string): IFilterResult; + filterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter, mostRelevantSettings?: string[]): IFilterResult; + findValueMatches(filter: string, setting: ISetting): IRange[]; } export interface IKeybindingsEditorModel extends IPreferencesEditorModel { @@ -68,13 +92,11 @@ export const IPreferencesService = createDecorator('prefere export interface IPreferencesService { _serviceBrand: any; - defaultSettingsResource: URI; - defaultResourceSettingsResource: URI; userSettingsResource: URI; workspaceSettingsResource: URI; getFolderSettingsResource(resource: URI): URI; - resolveContent(uri: URI): TPromise; + resolveModel(uri: URI): TPromise; createPreferencesEditorModel(uri: URI): TPromise>; openGlobalSettings(options?: IEditorOptions, position?: Position): TPromise; diff --git a/src/vs/workbench/parts/preferences/common/preferencesContribution.ts b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts index 665bb232104..b9021dc6437 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesContribution.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts @@ -120,15 +120,7 @@ export class PreferencesContribution implements IWorkbenchContribution { return TPromise.as(schemaModel); } } - return this.preferencesService.resolveContent(uri) - .then(content => { - if (content !== null && content !== void 0) { - let mode = this.modeService.getOrCreateMode('json'); - const model = this.modelService.createModel(content, mode, uri); - return TPromise.as(model); - } - return null; - }); + return this.preferencesService.resolveModel(uri); } }); } diff --git a/src/vs/workbench/parts/preferences/common/preferencesModels.ts b/src/vs/workbench/parts/preferences/common/preferencesModels.ts index 1233bd69199..9a97ffcdf6d 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesModels.ts @@ -4,163 +4,41 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import * as strings from 'vs/base/common/strings'; import { assign } from 'vs/base/common/objects'; -import { distinct } from 'vs/base/common/arrays'; +import { tail } from 'vs/base/common/arrays'; import URI from 'vs/base/common/uri'; import { IReference } from 'vs/base/common/lifecycle'; import Event from 'vs/base/common/event'; import { Registry } from 'vs/platform/registry/common/platform'; import { visit, JSONVisitor } from 'vs/base/common/json'; import { IModel } from 'vs/editor/common/editorCommon'; -import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { EditorModel } from 'vs/workbench/common/editor'; import { IConfigurationNode, IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN, IConfigurationPropertySchema, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { ISettingsEditorModel, IKeybindingsEditorModel, ISettingsGroup, ISetting, IFilterResult, ISettingsSection } from 'vs/workbench/parts/preferences/common/preferences'; +import { ISettingsEditorModel, IKeybindingsEditorModel, ISettingsGroup, ISetting, IFilterResult, ISettingsSection, IGroupFilter, ISettingFilter } from 'vs/workbench/parts/preferences/common/preferences'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters'; import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; -import { IRange } from 'vs/editor/common/core/range'; +import { IRange, Range } from 'vs/editor/common/core/range'; import { ITextFileService, StateChange } from 'vs/workbench/services/textfile/common/textfiles'; import { TPromise } from 'vs/base/common/winjs.base'; import { Queue } from 'vs/base/common/async'; import { IFileService } from 'vs/platform/files/common/files'; import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; -class SettingMatches { - - private readonly descriptionMatchingWords: Map = new Map(); - private readonly keyMatchingWords: Map = new Map(); - private readonly valueMatchingWords: Map = new Map(); - - public readonly matches: IRange[]; - - constructor(searchString: string, setting: ISetting, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) { - this.matches = distinct(this._findMatchesInSetting(searchString, setting), (match) => `${match.startLineNumber}_${match.startColumn}_${match.endLineNumber}_${match.endColumn}_`); - } - - private _findMatchesInSetting(searchString: string, setting: ISetting): IRange[] { - const result = this._doFindMatchesInSetting(searchString, setting); - if (setting.overrides && setting.overrides.length) { - for (const subSetting of setting.overrides) { - const subSettingMatches = new SettingMatches(searchString, subSetting, this.valuesMatcher); - let words = searchString.split(' '); - const descriptionRanges: IRange[] = this.getRangesForWords(words, this.descriptionMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); - const keyRanges: IRange[] = this.getRangesForWords(words, this.keyMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); - const subSettingKeyRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.keyMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.valueMatchingWords]); - const subSettinValueRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.valueMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.keyMatchingWords]); - result.push(...descriptionRanges, ...keyRanges, ...subSettingKeyRanges, ...subSettinValueRanges); - result.push(...subSettingMatches.matches); - } - } - return result; - } - - private _doFindMatchesInSetting(searchString: string, setting: ISetting): IRange[] { - const registry: { [qualifiedKey: string]: IJSONSchema } = Registry.as(Extensions.Configuration).getConfigurationProperties(); - const schema: IJSONSchema = registry[setting.key]; - - let words = searchString.split(' '); - const settingKeyAsWords: string = setting.key.split('.').join(' '); - - for (const word of words) { - for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) { - const descriptionMatches = matchesWords(word, setting.description[lineIndex], true); - if (descriptionMatches) { - this.descriptionMatchingWords.set(word, descriptionMatches.map(match => this.toDescriptionRange(setting, match, lineIndex))); - } - } - - const keyMatches = or(matchesWords, matchesCamelCase)(word, settingKeyAsWords); - if (keyMatches) { - this.keyMatchingWords.set(word, keyMatches.map(match => this.toKeyRange(setting, match))); - } - - const valueMatches = typeof setting.value === 'string' ? matchesContiguousSubString(word, setting.value) : null; - if (valueMatches) { - this.valueMatchingWords.set(word, valueMatches.map(match => this.toValueRange(setting, match))); - } else if (schema && schema.enum && schema.enum.some(enumValue => typeof enumValue === 'string' && !!matchesContiguousSubString(word, enumValue))) { - this.valueMatchingWords.set(word, []); - } - } - - const descriptionRanges: IRange[] = []; - for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) { - const matches = or(matchesContiguousSubString)(searchString, setting.description[lineIndex] || '') || []; - descriptionRanges.push(...matches.map(match => this.toDescriptionRange(setting, match, lineIndex))); - } - if (descriptionRanges.length === 0) { - descriptionRanges.push(...this.getRangesForWords(words, this.descriptionMatchingWords, [this.keyMatchingWords, this.valueMatchingWords])); - } - - const keyMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.key); - const keyRanges: IRange[] = keyMatches ? keyMatches.map(match => this.toKeyRange(setting, match)) : this.getRangesForWords(words, this.keyMatchingWords, [this.descriptionMatchingWords, this.valueMatchingWords]); - - let valueRanges: IRange[] = []; - if (setting.value && typeof setting.value === 'string') { - const valueMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.value); - valueRanges = valueMatches ? valueMatches.map(match => this.toValueRange(setting, match)) : this.getRangesForWords(words, this.valueMatchingWords, [this.keyMatchingWords, this.descriptionMatchingWords]); - } else { - valueRanges = this.valuesMatcher(searchString, setting); - } - - return [...descriptionRanges, ...keyRanges, ...valueRanges]; - } - - private getRangesForWords(words: string[], from: Map, others: Map[]): IRange[] { - const result: IRange[] = []; - for (const word of words) { - const ranges = from.get(word); - if (ranges) { - result.push(...ranges); - } else if (others.every(o => !o.has(word))) { - return []; - } - } - return result; - } - - private toKeyRange(setting: ISetting, match: IMatch): IRange { - return { - startLineNumber: setting.keyRange.startLineNumber, - startColumn: setting.keyRange.startColumn + match.start, - endLineNumber: setting.keyRange.startLineNumber, - endColumn: setting.keyRange.startColumn + match.end - }; - } - - private toDescriptionRange(setting: ISetting, match: IMatch, lineIndex: number): IRange { - return { - startLineNumber: setting.descriptionRanges[lineIndex].startLineNumber, - startColumn: setting.descriptionRanges[lineIndex].startColumn + match.start, - endLineNumber: setting.descriptionRanges[lineIndex].endLineNumber, - endColumn: setting.descriptionRanges[lineIndex].startColumn + match.end - }; - } - - private toValueRange(setting: ISetting, match: IMatch): IRange { - return { - startLineNumber: setting.valueRange.startLineNumber, - startColumn: setting.valueRange.startColumn + match.start + 1, - endLineNumber: setting.valueRange.startLineNumber, - endColumn: setting.valueRange.startColumn + match.end + 1 - }; - } -} - - export abstract class AbstractSettingsModel extends EditorModel { public get groupsTerms(): string[] { return this.settingsGroups.map(group => '@' + group.id); } - protected doFilterSettings(filter: string, allGroups: ISettingsGroup[]): IFilterResult { + protected doFilterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter): IFilterResult { + const allGroups = this.settingsGroups; + if (!filter) { return { filteredGroups: allGroups, allGroups, - matches: [] + matches: [], + query: filter }; } @@ -169,24 +47,27 @@ export abstract class AbstractSettingsModel extends EditorModel { return { filteredGroups: [group], allGroups, - matches: [] + matches: [], + query: filter }; } const matches: IRange[] = []; const filteredGroups: ISettingsGroup[] = []; - const regex = strings.createRegExp(filter, false, { global: true }); for (const group of allGroups) { - const groupMatched = regex.test(group.title); + const groupMatched = groupFilter(group); const sections: ISettingsSection[] = []; for (const section of group.sections) { const settings: ISetting[] = []; for (const setting of section.settings) { - const settingMatches = new SettingMatches(filter, setting, (filter, setting) => this.findValueMatches(filter, setting)).matches; - if (groupMatched || settingMatches.length > 0) { + const settingMatches = settingFilter(setting); + if (groupMatched || settingMatches && settingMatches.length) { settings.push(setting); } - matches.push(...settingMatches); + + if (settingMatches) { + matches.push(...settingMatches); + } } if (settings.length) { sections.push({ @@ -206,7 +87,7 @@ export abstract class AbstractSettingsModel extends EditorModel { }); } } - return { filteredGroups, matches, allGroups }; + return { filteredGroups, matches, allGroups, query: filter }; } private filterByGroupTerm(filter: string): ISettingsGroup { @@ -232,7 +113,7 @@ export abstract class AbstractSettingsModel extends EditorModel { public abstract settingsGroups: ISettingsGroup[]; - protected abstract findValueMatches(filter: string, setting: ISetting): IRange[]; + public abstract findValueMatches(filter: string, setting: ISetting): IRange[]; } export class SettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel { @@ -270,8 +151,12 @@ export class SettingsEditorModel extends AbstractSettingsModel implements ISetti return this.settingsModel.getValue(); } - public filterSettings(filter: string): IFilterResult { - return this.doFilterSettings(filter, this.settingsGroups); + public filterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter): IFilterResult { + return this.doFilterSettings(filter, groupFilter, settingFilter); + } + + public findValueMatches(filter: string, setting: ISetting): IRange[] { + return this.settingsModel.findMatches(filter, setting.valueRange, false, false, null, false).map(match => match.range); } public save(): TPromise { @@ -282,10 +167,6 @@ export class SettingsEditorModel extends AbstractSettingsModel implements ISetti return this.textFileService.save(this.uri); } - protected findValueMatches(filter: string, setting: ISetting): IRange[] { - return this.settingsModel.findMatches(filter, setting.valueRange, false, false, null, false).map(match => match.range); - } - private parse() { const model = this.settingsModel; const settings: ISetting[] = []; @@ -592,18 +473,16 @@ export class WorkspaceConfigModel extends SettingsEditorModel implements ISettin } } -export class DefaultSettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel { +export class DefaultSettingsModel { private _allSettingsGroups: ISettingsGroup[]; private _content: string; - private _contentByLines: string[]; + private _settingsByName: Map; - constructor(private _uri: URI, private _mostCommonlyUsedSettingsKeys: string[], readonly configurationScope: ConfigurationScope) { - super(); - } - - public get uri(): URI { - return this._uri; + constructor( + private _mostCommonlyUsedSettingsKeys: string[], + readonly configurationScope: ConfigurationScope, + ) { } public get content(): string { @@ -620,46 +499,29 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements return this._allSettingsGroups; } - public get mostCommonlyUsedSettings(): ISettingsGroup { - return this.settingsGroups[0]; - } - - public filterSettings(filter: string): IFilterResult { - return this.doFilterSettings(filter, this.settingsGroups); - } - - public getPreference(key: string): ISetting { - for (const group of this.settingsGroups) { - for (const section of group.sections) { - for (const setting of section.settings) { - if (setting.key === key) { - return setting; - } - } - } - } - return null; - } - private parse() { const configurations = Registry.as(Extensions.Configuration).getConfigurations().slice(); const settingsGroups = this.removeEmptySettingsGroups(configurations.sort(this.compareConfigurationNodes).reduce((result, config, index, array) => this.parseConfig(config, result, array), [])); + this.initAllSettingsMap(settingsGroups); const mostCommonlyUsed = this.getMostCommonlyUsedSettings(settingsGroups); this._allSettingsGroups = [mostCommonlyUsed, ...settingsGroups]; this._content = this.toContent(mostCommonlyUsed, settingsGroups); } - private getMostCommonlyUsedSettings(allSettingsGroups: ISettingsGroup[]): ISettingsGroup { - const map: Map = new Map(); + private initAllSettingsMap(allSettingsGroups: ISettingsGroup[]): void { + this._settingsByName = new Map(); for (const group of allSettingsGroups) { for (const section of group.sections) { for (const setting of section.settings) { - map.set(setting.key, setting); + this._settingsByName.set(setting.key, setting); } } } + } + + private getMostCommonlyUsedSettings(allSettingsGroups: ISettingsGroup[]): ISettingsGroup { const settings = this._mostCommonlyUsedSettingsKeys.map(key => { - const setting = map.get(key); + const setting = this._settingsByName.get(key); if (setting) { return { description: setting.description, @@ -773,25 +635,171 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements } private toContent(mostCommonlyUsed: ISettingsGroup, settingsGroups: ISettingsGroup[]): string { - this._contentByLines = []; - this._contentByLines.push('['); - this.pushGroups([mostCommonlyUsed]); - this._contentByLines.push(','); - this.pushGroups(settingsGroups); - this._contentByLines.push(']'); - return this._contentByLines.join('\n'); + const builder = new SettingsContentBuilder(); + builder.pushLine('['); + builder.pushGroups([mostCommonlyUsed]); + builder.pushLine(','); + builder.pushGroups(settingsGroups); + builder.pushLine(']'); + return builder.getContent(); } - private pushGroups(settingsGroups: ISettingsGroup[]): void { +} + +export class DefaultSettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel { + + private _model: IModel; + private _settingsByName: Map; + private _mostRelevantLineOffset: number; + + constructor( + private _uri: URI, + reference: IReference, + readonly configurationScope: ConfigurationScope, + readonly settingsGroups: ISettingsGroup[] + ) { + super(); + this._model = reference.object.textEditorModel; + this._register(this.onDispose(() => reference.dispose())); + + this.initAllSettingsMap(); + this._mostRelevantLineOffset = tail(this.settingsGroups).range.endLineNumber + 2; + } + + public get uri(): URI { + return this._uri; + } + + public filterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter, mostRelevantSettings?: string[]): IFilterResult { + if (mostRelevantSettings) { + const builder = new SettingsContentBuilder(this._mostRelevantLineOffset - 1); + builder.pushLine(','); + const mostRelevantGroup = this.getMostRelevantSettings(mostRelevantSettings); + builder.pushGroups([mostRelevantGroup]); + builder.pushLine(''); + + // note: 1-indexed line numbers here + const mostRelevantContent = builder.getContent(); + const mostRelevantEndLine = this._model.getLineCount(); + this._model.applyEdits([ + { + text: mostRelevantContent, + forceMoveMarkers: false, + range: new Range(this._mostRelevantLineOffset, 1, mostRelevantEndLine, 1), + identifier: { major: 1, minor: 0 } + } + ]); + + return { + allGroups: [...this.settingsGroups, mostRelevantGroup], + filteredGroups: mostRelevantGroup.sections[0].settings.length ? [mostRelevantGroup] : [], + matches: [], + query: filter + }; + } else { + // local + return this.doFilterSettings(filter, groupFilter, settingFilter); + } + } + + public findValueMatches(filter: string, setting: ISetting): IRange[] { + return []; + } + + public getPreference(key: string): ISetting { + for (const group of this.settingsGroups) { + for (const section of group.sections) { + for (const setting of section.settings) { + if (setting.key === key) { + return setting; + } + } + } + } + return null; + } + + private initAllSettingsMap(): void { + this._settingsByName = new Map(); + for (const group of this.settingsGroups) { + for (const section of group.sections) { + for (const setting of section.settings) { + this._settingsByName.set(setting.key, setting); + } + } + } + } + + private getMostRelevantSettings(rankedSettingNames: string[]): ISettingsGroup { + const settings = rankedSettingNames.map(key => { + const setting = this._settingsByName.get(key); + if (setting) { + return { + description: setting.description, + key: setting.key, + value: setting.value, + range: null, + valueRange: null, + overrides: [] + }; + } + return null; + }).filter(setting => !!setting); + + return { + id: 'mostRelevant', + range: null, + title: nls.localize('mostRelevant', "Most Relevant"), + titleRange: null, + sections: [ + { + settings + } + ] + }; + } +} + +class SettingsContentBuilder { + private _contentByLines: string[]; + + get lines(): string[] { + return this._contentByLines; + } + + private get lineCountWithOffset(): number { + return this._contentByLines.length + this._rangeOffset; + } + + private get lastLine(): string { + return this._contentByLines[this._contentByLines.length - 1] || ''; + } + + constructor(private _rangeOffset = 0, private _maxLines = Infinity) { + this._contentByLines = []; + } + + private offsetIndexToIndex(offsetIdx: number): number { + return offsetIdx - this._rangeOffset; + } + + pushLine(...lineText: string[]): void { + this._contentByLines.push(...lineText); + } + + pushGroups(settingsGroups: ISettingsGroup[]): void { let lastSetting: ISetting = null; this._contentByLines.push('{'); this._contentByLines.push(''); for (const group of settingsGroups) { + this._contentByLines.push(''); lastSetting = this.pushGroup(group); } if (lastSetting) { - const content = this._contentByLines[lastSetting.range.endLineNumber - 2]; - this._contentByLines[lastSetting.range.endLineNumber - 2] = content.substring(0, content.length - 1); + // Strip the comma from the last setting + const lineIdx = this.offsetIndexToIndex(lastSetting.range.endLineNumber); + const content = this._contentByLines[lineIdx - 2]; + this._contentByLines[lineIdx - 2] = content.substring(0, content.length - 1); } this._contentByLines.push('}'); } @@ -799,13 +807,12 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements private pushGroup(group: ISettingsGroup): ISetting { const indent = ' '; let lastSetting: ISetting = null; - this._contentByLines.push(''); - let groupStart = this._contentByLines.length + 1; + let groupStart = this.lineCountWithOffset + 1; for (const section of group.sections) { if (section.title) { - let sectionTitleStart = this._contentByLines.length + 1; + let sectionTitleStart = this.lineCountWithOffset + 1; this.addDescription([section.title], indent, this._contentByLines); - section.titleRange = { startLineNumber: sectionTitleStart, startColumn: 1, endLineNumber: this._contentByLines.length, endColumn: this._contentByLines[this._contentByLines.length - 1].length }; + section.titleRange = { startLineNumber: sectionTitleStart, startColumn: 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length }; } if (section.settings.length) { @@ -813,38 +820,39 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements this.pushSetting(setting, indent); lastSetting = setting; } - } else { - this._contentByLines.push('// ' + nls.localize('noSettings', "No Settings")); - this._contentByLines.push(''); } } - group.range = { startLineNumber: groupStart, startColumn: 1, endLineNumber: this._contentByLines.length, endColumn: this._contentByLines[this._contentByLines.length - 1].length }; + group.range = { startLineNumber: groupStart, startColumn: 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length }; return lastSetting; } + getContent(): string { + return this._contentByLines.join('\n'); + } + private pushSetting(setting: ISetting, indent: string): void { - const settingStart = this._contentByLines.length + 1; + const settingStart = this.lineCountWithOffset + 1; setting.descriptionRanges = []; const descriptionPreValue = indent + '// '; for (const line of setting.description) { this._contentByLines.push(descriptionPreValue + line); - setting.descriptionRanges.push({ startLineNumber: this._contentByLines.length, startColumn: this._contentByLines[this._contentByLines.length - 1].indexOf(line) + 1, endLineNumber: this._contentByLines.length, endColumn: this._contentByLines[this._contentByLines.length - 1].length }); + setting.descriptionRanges.push({ startLineNumber: this.lineCountWithOffset, startColumn: this.lastLine.indexOf(line) + 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length }); } let preValueConent = indent; const keyString = JSON.stringify(setting.key); preValueConent += keyString; - setting.keyRange = { startLineNumber: this._contentByLines.length + 1, startColumn: preValueConent.indexOf(setting.key) + 1, endLineNumber: this._contentByLines.length + 1, endColumn: setting.key.length }; + setting.keyRange = { startLineNumber: this.lineCountWithOffset + 1, startColumn: preValueConent.indexOf(setting.key) + 1, endLineNumber: this.lineCountWithOffset + 1, endColumn: setting.key.length }; preValueConent += ': '; - const valueStart = this._contentByLines.length + 1; + const valueStart = this.lineCountWithOffset + 1; this.pushValue(setting, preValueConent, indent); - setting.valueRange = { startLineNumber: valueStart, startColumn: preValueConent.length + 1, endLineNumber: this._contentByLines.length, endColumn: this._contentByLines[this._contentByLines.length - 1].length + 1 }; + setting.valueRange = { startLineNumber: valueStart, startColumn: preValueConent.length + 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length + 1 }; this._contentByLines[this._contentByLines.length - 1] += ','; this._contentByLines.push(''); - setting.range = { startLineNumber: settingStart, startColumn: 1, endLineNumber: this._contentByLines.length, endColumn: this._contentByLines[this._contentByLines.length - 1].length }; + setting.range = { startLineNumber: settingStart, startColumn: 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length }; } private pushValue(setting: ISetting, preValueConent: string, indent: string): void { @@ -877,14 +885,6 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements result.push(indent + '// ' + line); } } - - protected findValueMatches(filter: string, setting: ISetting): IRange[] { - return []; - } - - public dispose(): void { - // Not disposable - } } export function defaultKeybindingsContents(keybindingService: IKeybindingService): string { @@ -896,7 +896,8 @@ export class DefaultKeybindingsEditorModel implements IKeybindingsEditorModel 0 ? workspace.folders[0].uri.fsPath : void 0; + + // Install workspace folder listener if (!this.onDidChangeWorkspaceFoldersUnbind) { this.onDidChangeWorkspaceFoldersUnbind = this.contextService.onDidChangeWorkspaceFolders(() => this.onDidChangeWorkspaceFolders()); } diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index ec011aa71c6..d5fa6d871cf 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -11,7 +11,7 @@ import 'vs/css!./media/dirtydiffDecorator'; import { ThrottledDelayer, always } from 'vs/base/common/async'; import { IDisposable, dispose, toDisposable, empty as EmptyDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; -import Event, { Emitter, any as anyEvent, filterEvent, once } from 'vs/base/common/event'; +import Event, { Emitter, anyEvent as anyEvent, filterEvent, once } from 'vs/base/common/event'; import * as ext from 'vs/workbench/common/contributions'; import { CodeEditor } from 'vs/editor/browser/codeEditor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; diff --git a/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css b/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css index a20ef64cf68..ff68aea9db1 100644 --- a/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css +++ b/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css @@ -84,15 +84,12 @@ overflow: hidden; } -.scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label { - width: 100%; - height: 100%; - overflow: hidden; - text-overflow: ellipsis; +.scm-viewlet .monaco-list-row > .resource > .name.strike-through > .monaco-icon-label > .monaco-icon-label-description-container > .label-name { + text-decoration: line-through; } -.scm-viewlet .monaco-list-row > .resource > .name.strike-through > .monaco-icon-label > .label-name { - text-decoration: line-through; +.scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label::after { + padding: 0 4px; } .scm-viewlet .monaco-list-row > .resource > .decoration-icon { @@ -102,23 +99,26 @@ background-position: 50% 50%; } +.scm-viewlet .monaco-list .monaco-list-row > .resource > .name > .monaco-icon-label > .actions { + flex-grow: 100; +} .scm-viewlet .monaco-list .monaco-list-row > .resource-group > .actions, -.scm-viewlet .monaco-list .monaco-list-row > .resource > .actions { +.scm-viewlet .monaco-list .monaco-list-row > .resource > .name > .monaco-icon-label > .actions { display: none; } .scm-viewlet .monaco-list .monaco-list-row:hover > .resource-group > .actions, -.scm-viewlet .monaco-list .monaco-list-row:hover > .resource > .actions, +.scm-viewlet .monaco-list .monaco-list-row:hover > .resource > .name > .monaco-icon-label > .actions, .scm-viewlet .monaco-list .monaco-list-row.selected > .resource-group > .actions, .scm-viewlet .monaco-list .monaco-list-row.focused > .resource-group > .actions, -.scm-viewlet .monaco-list .monaco-list-row.selected > .resource > .actions, -.scm-viewlet .monaco-list .monaco-list-row.focused > .resource > .actions, +.scm-viewlet .monaco-list .monaco-list-row.selected > .resource > .name > .monaco-icon-label > .actions, +.scm-viewlet .monaco-list .monaco-list-row.focused > .resource > .name > .monaco-icon-label > .actions, .scm-viewlet .monaco-list:not(.selection-multiple) .monaco-list-row > .resource:hover > .actions { display: block; } -.scm-viewlet .monaco-list-row > .resource > .actions .action-label, +.scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label > .actions .action-label, .scm-viewlet .monaco-list-row > .resource-group > .actions .action-label { width: 16px; height: 100%; @@ -153,4 +153,4 @@ .scm-viewlet .spacer { flex: 1; -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts b/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts index 2558e2a1717..0ecdc26d618 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { basename } from 'vs/base/common/paths'; import { IDisposable, dispose, empty as EmptyDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; -import { filterEvent, any as anyEvent } from 'vs/base/common/event'; +import { filterEvent, anyEvent as anyEvent } from 'vs/base/common/event'; import { VIEWLET_ID } from 'vs/workbench/parts/scm/common/scm'; import { ISCMService, ISCMRepository } from 'vs/workbench/services/scm/common/scm'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; @@ -159,4 +159,4 @@ export class StatusBarController implements IWorkbenchContribution { this.statusBarDisposable.dispose(); this.disposables = dispose(this.disposables); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts index 990928f0af8..6b272185b6c 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts @@ -429,7 +429,7 @@ class ResourceRenderer implements IRenderer { const element = append(container, $('.resource')); const name = append(element, $('.name')); const fileLabel = this.instantiationService.createInstance(FileLabel, name, void 0); - const actionsContainer = append(element, $('.actions')); + const actionsContainer = append(fileLabel.element, $('.actions')); const actionBar = new ActionBar(actionsContainer, { actionItemProvider: this.actionItemProvider, actionRunner: new MultipleSelectionActionRunner(this.getSelectedResources) @@ -446,20 +446,23 @@ class ResourceRenderer implements IRenderer { } renderElement(resource: ISCMResource, index: number, template: ResourceTemplate): void { - template.fileLabel.setFile(resource.sourceUri); + + const theme = this.themeService.getTheme(); + const icon = theme.type === LIGHT ? resource.decorations.icon : resource.decorations.iconDark; + + template.fileLabel.setFile(resource.sourceUri, { fileDecorations: { colors: false, badges: !icon } }); template.actionBar.clear(); template.actionBar.context = resource; template.actionBar.push(this.scmMenus.getResourceActions(resource), { icon: true, label: false }); toggleClass(template.name, 'strike-through', resource.decorations.strikeThrough); toggleClass(template.element, 'faded', resource.decorations.faded); - const theme = this.themeService.getTheme(); - const icon = theme.type === LIGHT ? resource.decorations.icon : resource.decorations.iconDark; - if (icon) { + template.decorationIcon.style.display = ''; template.decorationIcon.style.backgroundImage = `url('${icon}')`; template.decorationIcon.title = resource.decorations.tooltip; } else { + template.decorationIcon.style.display = 'none'; template.decorationIcon.style.backgroundImage = ''; } } diff --git a/src/vs/workbench/parts/search/browser/search.contribution.ts b/src/vs/workbench/parts/search/browser/search.contribution.ts index 5c489ff6e63..07f79b0238b 100644 --- a/src/vs/workbench/parts/search/browser/search.contribution.ts +++ b/src/vs/workbench/parts/search/browser/search.contribution.ts @@ -371,6 +371,11 @@ configurationRegistry.registerConfiguration({ 'type': 'boolean', 'description': nls.localize('search.quickOpen.includeSymbols', "Configure to include results from a global symbol search in the file results for Quick Open."), 'default': false + }, + 'search.followSymlinks': { + 'type': 'boolean', + 'description': nls.localize('search.followSymlinks', "Controls whether to follow symlinks while searching."), + 'default': true } } }); diff --git a/src/vs/workbench/parts/search/common/queryBuilder.ts b/src/vs/workbench/parts/search/common/queryBuilder.ts index cf614eeaeb0..65d70195724 100644 --- a/src/vs/workbench/parts/search/common/queryBuilder.ts +++ b/src/vs/workbench/parts/search/common/queryBuilder.ts @@ -60,6 +60,8 @@ export class QueryBuilder { return folderConfig.search.useRipgrep; }); + const ignoreSymlinks = !this.configurationService.getConfiguration().search.followSymlinks; + const query = { type, folderQueries, @@ -74,7 +76,8 @@ export class QueryBuilder { contentPattern: contentPattern, useRipgrep, disregardIgnoreFiles: options.disregardIgnoreFiles, - disregardExcludeSettings: options.disregardExcludeSettings + disregardExcludeSettings: options.disregardExcludeSettings, + ignoreSymlinks }; // Filter extraFileResources against global include/exclude patterns - they are already expected to not belong to a workspace diff --git a/src/vs/workbench/parts/search/common/search.ts b/src/vs/workbench/parts/search/common/search.ts index 6b074a33287..a0bbd0554b4 100644 --- a/src/vs/workbench/parts/search/common/search.ts +++ b/src/vs/workbench/parts/search/common/search.ts @@ -80,7 +80,8 @@ export interface IWorkbenchSearchConfiguration extends ISearchConfiguration { }, exclude: glob.IExpression, useRipgrep: boolean, - useIgnoreFilesByDefault: boolean + useIgnoreFilesByDefault: boolean, + followSymlinks: boolean; }; } diff --git a/src/vs/workbench/parts/search/common/searchModel.ts b/src/vs/workbench/parts/search/common/searchModel.ts index d90eda8bb39..717213f614c 100644 --- a/src/vs/workbench/parts/search/common/searchModel.ts +++ b/src/vs/workbench/parts/search/common/searchModel.ts @@ -12,7 +12,7 @@ import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { TPromise, PPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; import { values, ResourceMap, TernarySearchTree } from 'vs/base/common/map'; -import Event, { Emitter, fromPromise, stopwatch, any } from 'vs/base/common/event'; +import Event, { Emitter, fromPromise, stopwatch, anyEvent } from 'vs/base/common/event'; import { ISearchService, ISearchProgressItem, ISearchComplete, ISearchQuery, IPatternInfo, IFileMatch } from 'vs/platform/search/common/search'; import { ReplacePattern } from 'vs/platform/search/common/replace'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -728,7 +728,7 @@ export class SearchModel extends Disposable { const onDone = fromPromise(this.currentRequest); const progressEmitter = new Emitter(); - const onFirstRender = any(onDone, progressEmitter.event); + const onFirstRender = anyEvent(onDone, progressEmitter.event); const onFirstRenderStopwatch = stopwatch(onFirstRender); /* __GDPR__ "searchResultsFirstRender" : { diff --git a/src/vs/workbench/parts/search/test/common/queryBuilder.test.ts b/src/vs/workbench/parts/search/test/common/queryBuilder.test.ts index 059f34fb3e3..4cf542b63a9 100644 --- a/src/vs/workbench/parts/search/test/common/queryBuilder.test.ts +++ b/src/vs/workbench/parts/search/test/common/queryBuilder.test.ts @@ -594,6 +594,8 @@ function assertEqualQueries(actual: ISearchQuery, expected: ISearchQuery): void }; }; + delete actual.ignoreSymlinks; + // Avoid comparing URI objects, not a good idea if (expected.folderQueries) { assert.deepEqual(actual.folderQueries.map(folderQueryToCompareObject), expected.folderQueries.map(folderQueryToCompareObject)); diff --git a/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.ts b/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.ts index e817505d469..6ed72114838 100644 --- a/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.ts +++ b/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.ts @@ -78,13 +78,13 @@ class InsertSnippetAction extends EditorAction { return new TPromise(async (resolve, reject) => { if (snippet) { - return resolve({ - codeSnippet: snippet, - description: undefined, - name: undefined, - source: undefined, - prefix: undefined - }); + return resolve(new Snippet( + undefined, + undefined, + undefined, + snippet, + undefined + )); } let languageId: LanguageId; diff --git a/src/vs/workbench/parts/snippets/electron-browser/snippets.contribution.ts b/src/vs/workbench/parts/snippets/electron-browser/snippets.contribution.ts index 5e51b4e6c97..1e83ba2ab3f 100644 --- a/src/vs/workbench/parts/snippets/electron-browser/snippets.contribution.ts +++ b/src/vs/workbench/parts/snippets/electron-browser/snippets.contribution.ts @@ -19,6 +19,8 @@ import * as nls from 'vs/nls'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { LanguageId } from 'vs/editor/common/modes'; import { TPromise } from 'vs/base/common/winjs.base'; +import { SnippetParser, Variable, Placeholder, Text } from 'vs/editor/contrib/snippet/browser/snippetParser'; +import { EditorSnippetVariableResolver } from 'vs/editor/contrib/snippet/browser/snippetVariables'; export const ISnippetsService = createDecorator('snippetService'); @@ -26,20 +28,50 @@ export interface ISnippetsService { _serviceBrand: any; - getSnippets(languageId: LanguageId): TPromise; + getSnippets(languageId: LanguageId): Promise; getSnippetsSync(languageId: LanguageId): Snippet[]; } export class Snippet { - readonly name: string; - readonly prefix: string; - readonly description: string; - readonly codeSnippet: string; - readonly source: string; - readonly isBogous?: boolean; - readonly isFromExtension?: boolean; + + private _codeSnippet: string; + private _isBogous: boolean; + + constructor( + readonly name: string, + readonly prefix: string, + readonly description: string, + readonly body: string, + readonly source: string, + readonly isFromExtension?: boolean, + ) { + // + } + + get codeSnippet(): string { + this._ensureCodeSnippet(); + return this._codeSnippet; + } + + get isBogous(): boolean { + this._ensureCodeSnippet(); + return this._isBogous; + } + + private _ensureCodeSnippet() { + if (!this._codeSnippet) { + const rewrite = Snippet._rewriteBogousVariables(this.body); + if (typeof rewrite === 'string') { + this._codeSnippet = rewrite; + this._isBogous = true; + } else { + this._codeSnippet = this.body; + this._isBogous = false; + } + } + } static compare(a: Snippet, b: Snippet): number { if (a.isFromExtension !== b.isFromExtension) { @@ -56,6 +88,49 @@ export class Snippet { return 0; } } + + static _rewriteBogousVariables(template: string): false | string { + const textmateSnippet = new SnippetParser().parse(template, false); + + let placeholders = new Map(); + let placeholderMax = 0; + for (const placeholder of textmateSnippet.placeholders) { + placeholderMax = Math.max(placeholderMax, placeholder.index); + } + + let didChange = false; + let stack = [...textmateSnippet.children]; + + while (stack.length > 0) { + let marker = stack.shift(); + + if ( + marker instanceof Variable + && marker.children.length === 0 + && !EditorSnippetVariableResolver.VariableNames[marker.name] + ) { + // a 'variable' without a default value and not being one of our supported + // variables is automatically turned into a placeholder. This is to restore + // a bug we had before. So `${foo}` becomes `${N:foo}` + const index = placeholders.has(marker.name) ? placeholders.get(marker.name) : ++placeholderMax; + placeholders.set(marker.name, index); + + const synthetic = new Placeholder(index).appendChild(new Text(marker.name)); + textmateSnippet.replace(marker, [synthetic]); + didChange = true; + + } else { + // recurse + stack.push(...marker.children); + } + } + + if (!didChange) { + return false; + } else { + return textmateSnippet.toTextmateString(); + } + } } namespace OpenSnippetsAction { diff --git a/src/vs/workbench/parts/snippets/electron-browser/snippetsFile.ts b/src/vs/workbench/parts/snippets/electron-browser/snippetsFile.ts index 11bf43c590f..3ee4e82d60b 100644 --- a/src/vs/workbench/parts/snippets/electron-browser/snippetsFile.ts +++ b/src/vs/workbench/parts/snippets/electron-browser/snippetsFile.ts @@ -7,9 +7,6 @@ import { readFile } from 'vs/base/node/pfs'; import { parse as jsonParse } from 'vs/base/common/json'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { SnippetParser, Variable, Placeholder, Text } from 'vs/editor/contrib/snippet/browser/snippetParser'; -import { EditorSnippetVariableResolver } from 'vs/editor/contrib/snippet/browser/snippetVariables'; import { forEach } from 'vs/base/common/collections'; import { Snippet } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution'; @@ -36,8 +33,8 @@ export class SnippetFile { // } - static fromFile(filepath: string, source: string, isFromExtension?: boolean): TPromise { - return readFile(filepath).then(value => { + static fromFile(filepath: string, source: string, isFromExtension?: boolean): Promise { + return Promise.resolve(readFile(filepath)).then(value => { const data = jsonParse(value.toString()); const snippets: Snippet[] = []; if (typeof data === 'object') { @@ -69,64 +66,13 @@ export class SnippetFile { return; } - let rewrite = SnippetFile._rewriteBogousVariables(body); - let isBogous = false; - if (typeof rewrite === 'string') { - body = rewrite; - isBogous = true; - } - - bucket.push({ - codeSnippet: body, + bucket.push(new Snippet( name, prefix, description, + body, source, - isFromExtension, - isBogous - }); - } - - static _rewriteBogousVariables(template: string): false | string { - const textmateSnippet = new SnippetParser().parse(template, false); - - let placeholders = new Map(); - let placeholderMax = 0; - for (const placeholder of textmateSnippet.placeholders) { - placeholderMax = Math.max(placeholderMax, placeholder.index); - } - - let didChange = false; - let stack = [...textmateSnippet.children]; - - while (stack.length > 0) { - let marker = stack.shift(); - - if ( - marker instanceof Variable - && marker.children.length === 0 - && !EditorSnippetVariableResolver.VariableNames[marker.name] - ) { - // a 'variable' without a default value and not being one of our supported - // variables is automatically turned into a placeholder. This is to restore - // a bug we had before. So `${foo}` becomes `${N:foo}` - const index = placeholders.has(marker.name) ? placeholders.get(marker.name) : ++placeholderMax; - placeholders.set(marker.name, index); - - const synthetic = new Placeholder(index).appendChild(new Text(marker.name)); - textmateSnippet.replace(marker, [synthetic]); - didChange = true; - - } else { - // recurse - stack.push(...marker.children); - } - } - - if (!didChange) { - return false; - } else { - return textmateSnippet.toTextmateString(); - } + isFromExtension + )); } } diff --git a/src/vs/workbench/parts/snippets/electron-browser/snippetsService.ts b/src/vs/workbench/parts/snippets/electron-browser/snippetsService.ts index c469f02372b..8f062847599 100644 --- a/src/vs/workbench/parts/snippets/electron-browser/snippetsService.ts +++ b/src/vs/workbench/parts/snippets/electron-browser/snippetsService.ts @@ -20,7 +20,6 @@ import { join } from 'path'; import { mkdirp } from 'vs/base/node/pfs'; import { watch } from 'fs'; import { SnippetFile } from 'vs/workbench/parts/snippets/electron-browser/snippetsFile'; -import { TPromise } from 'vs/base/common/winjs.base'; import { Snippet, ISnippetsService } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { ExtensionsRegistry, IExtensionPointUser } from 'vs/platform/extensions/common/extensionsRegistry'; @@ -96,14 +95,16 @@ class SnippetsService implements ISnippetsService { private readonly _extensionSnippets = new Map(); private readonly _userSnippets = new Map(); private readonly _userSnippetsFolder: string; + private readonly _wait: Promise; private readonly _disposables: IDisposable[] = []; constructor( - @IModeService readonly _modeService: IModeService, - @IExtensionService readonly _extensionService: IExtensionService, - @IEnvironmentService environmentService: IEnvironmentService, + @IModeService private readonly _modeService: IModeService, + @IEnvironmentService private readonly _environmentService: IEnvironmentService, + @IExtensionService extensionService: IExtensionService, ) { - this._userSnippetsFolder = join(environmentService.appSettingsHome, 'snippets'); + this._wait = Promise.resolve(extensionService.onReady()); + this._userSnippetsFolder = join(_environmentService.appSettingsHome, 'snippets'); this._prepUserSnippetsWatching(); this._prepExtensionSnippets(); @@ -114,32 +115,42 @@ class SnippetsService implements ISnippetsService { dispose(this._disposables); } - async getSnippets(languageId: LanguageId): TPromise { + getSnippets(languageId: LanguageId): Promise { let result: Snippet[] = []; - await TPromise.join([ - this._extensionService.onReady(), - this._getOrLoadUserSnippets(languageId, result), - this._getOrLoadExtensionSnippets(languageId, result) - ]); - return result; + return this._wait.then(() => { + return this._getOrLoadUserSnippets(languageId, result); + }).then(() => { + return this._getOrLoadExtensionSnippets(languageId, result); + }).then(() => { + return result; + }); } getSnippetsSync(languageId: LanguageId): Snippet[] { // just kick off snippet loading for this language such - // that subseqent calls to this method return more + // that subsequent calls to this method return more // correct results - this.getSnippets(languageId).done(undefined, undefined); + this.getSnippets(languageId).catch(undefined); // collect and return what we already have - let userSnippets = this._userSnippets.get(languageId); - let extensionSnippets = this._extensionSnippets.get(languageId); - return (userSnippets || []).concat(extensionSnippets || []); + const userSnippets = this._userSnippets.get(languageId); + const extensionSnippets = this._extensionSnippets.get(languageId); + + if (userSnippets && extensionSnippets) { + return userSnippets.concat(extensionSnippets); + } else if (!userSnippets) { + return extensionSnippets; + } else if (!extensionSnippets) { + return userSnippets; + } else { + return undefined; + } } // --- extension snippet logic --- - private async _prepExtensionSnippets(): TPromise { - ExtensionsRegistry.registerExtensionPoint('snippets', [languagesExtPoint], schema.snippetsContribution).setHandler(async extensions => { + private _prepExtensionSnippets(): void { + ExtensionsRegistry.registerExtensionPoint('snippets', [languagesExtPoint], schema.snippetsContribution).setHandler(extensions => { for (const extension of extensions) { for (const contribution of extension.value) { if (schema.isValidSnippet(extension, contribution, this._modeService)) { @@ -156,10 +167,11 @@ class SnippetsService implements ISnippetsService { }); } - private async _getOrLoadExtensionSnippets(languageId: LanguageId, bucket: Snippet[]): TPromise { + private _getOrLoadExtensionSnippets(languageId: LanguageId, bucket: Snippet[]): Promise { if (this._extensionSnippets.has(languageId)) { bucket.push(...this._extensionSnippets.get(languageId)); + return undefined; } else if (this._pendingExtensionSnippets.has(languageId)) { const pending = this._pendingExtensionSnippets.get(languageId); @@ -168,49 +180,59 @@ class SnippetsService implements ISnippetsService { const snippets = []; this._extensionSnippets.set(languageId, snippets); - for (const [extension, filepath] of pending) { - let file: SnippetFile; - try { - file = await SnippetFile.fromFile(filepath, extension.description.displayName || extension.description.name, true); - } catch (e) { + return Promise.all(pending.map(([extension, filepath]) => { + return SnippetFile.fromFile(filepath, extension.description.displayName || extension.description.name, true).then(file => { + + // collect + snippets.push(...file.data); + bucket.push(...file.data); + + // warn about bad tabstop/variable usage + if (this._environmentService.isExtensionDevelopment && file.data.some(snippet => snippet.isBogous)) { + extension.collector.warn(localize( + 'badVariableUse', + "One or more snippets from the extension '{0}' very likely confuse snippet-variables and snippet-placeholders (see https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax for more details)", + extension.description.name + )); + } + + }, err => { + // generic error extension.collector.warn(localize( 'badFile', "The snippet file \"{0}\" could not be read.", filepath )); - } - if (file) { - for (const snippet of file.data) { - snippets.push(snippet); - bucket.push(snippet); - if (snippet.isBogous) { - extension.collector.warn(localize( - 'badVariableUse', - "The \"{0}\"-snippet very likely confuses snippet-variables and snippet-placeholders. See https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax for more details.", - snippet.name - )); - } - } - } - } + }); + })).then(() => { + + }); + + } else { + return undefined; } } // --- user snippet logic --- - private async _getOrLoadUserSnippets(languageId: LanguageId, bucket: Snippet[]): TPromise { + private _getOrLoadUserSnippets(languageId: LanguageId, bucket: Snippet[]): Promise { let snippets = this._userSnippets.get(languageId); - if (snippets === undefined) { - try { - snippets = (await SnippetFile.fromFile(this._getUserSnippetFilepath(languageId), localize('source.snippet', "User Snippet"))).data; - } catch (e) { - snippets = null; - } - this._userSnippets.set(languageId, snippets); - } - if (snippets) { + // has data bucket.push(...snippets); + return undefined; + + } else if (snippets === undefined) { + // not yet loaded + return SnippetFile.fromFile(this._getUserSnippetFilepath(languageId), localize('source.snippet', "User Snippet")).then(file => { + this._userSnippets.set(languageId, file.data); + }, err => { + this._userSnippets.set(languageId, null); + }); + + } else { + // previous failure + return undefined; } } @@ -263,7 +285,7 @@ export class SnippetSuggestion implements ISuggestion { ) { this.label = snippet.prefix; this.detail = localize('detail.snippet', "{0} ({1})", snippet.description, snippet.source); - this.insertText = snippet.codeSnippet; + this.insertText = snippet.body; this.overwriteBefore = overwriteBefore; this.sortText = `${snippet.isFromExtension ? 'z' : 'a'}-${snippet.prefix}`; this.noAutoAccept = true; @@ -273,6 +295,7 @@ export class SnippetSuggestion implements ISuggestion { resolve(): this { this.documentation = new MarkdownString().appendCodeblock('', new SnippetParser().text(this.snippet.codeSnippet)); + this.insertText = this.snippet.codeSnippet; return this; } @@ -291,49 +314,51 @@ export class SnippetSuggestProvider implements ISuggestSupport { // } - async provideCompletionItems(model: IModel, position: Position): TPromise { + provideCompletionItems(model: IModel, position: Position): Promise { const languageId = this._getLanguageIdAtPosition(model, position); - const snippets = await this._snippets.getSnippets(languageId); - const suggestions: SnippetSuggestion[] = []; + return this._snippets.getSnippets(languageId).then(snippets => { - const lowWordUntil = model.getWordUntilPosition(position).word.toLowerCase(); - const lowLineUntil = model.getLineContent(position.lineNumber).substr(Math.max(0, position.column - 100), position.column - 1).toLowerCase(); + const suggestions: SnippetSuggestion[] = []; - for (const snippet of snippets) { + const lowWordUntil = model.getWordUntilPosition(position).word.toLowerCase(); + const lowLineUntil = model.getLineContent(position.lineNumber).substr(Math.max(0, position.column - 100), position.column - 1).toLowerCase(); - const lowPrefix = snippet.prefix.toLowerCase(); - let overwriteBefore = 0; - let accetSnippet = true; + for (const snippet of snippets) { - if (lowWordUntil.length > 0 && startsWith(lowPrefix, lowWordUntil)) { - // cheap match on the (none-empty) current word - overwriteBefore = lowWordUntil.length; - accetSnippet = true; + const lowPrefix = snippet.prefix.toLowerCase(); + let overwriteBefore = 0; + let accetSnippet = true; - } else if (lowLineUntil.length > 0 && lowLineUntil.match(/[^\s]$/)) { - // compute overlap between snippet and (none-empty) line on text - overwriteBefore = overlap(lowLineUntil, snippet.prefix.toLowerCase()); - accetSnippet = overwriteBefore > 0 && !model.getWordAtPosition(new Position(position.lineNumber, position.column - overwriteBefore)); + if (lowWordUntil.length > 0 && startsWith(lowPrefix, lowWordUntil)) { + // cheap match on the (none-empty) current word + overwriteBefore = lowWordUntil.length; + accetSnippet = true; + + } else if (lowLineUntil.length > 0 && lowLineUntil.match(/[^\s]$/)) { + // compute overlap between snippet and (none-empty) line on text + overwriteBefore = overlap(lowLineUntil, snippet.prefix.toLowerCase()); + accetSnippet = overwriteBefore > 0 && !model.getWordAtPosition(new Position(position.lineNumber, position.column - overwriteBefore)); + } + + if (accetSnippet) { + suggestions.push(new SnippetSuggestion(snippet, overwriteBefore)); + } } - if (accetSnippet) { - suggestions.push(new SnippetSuggestion(snippet, overwriteBefore)); + // dismbiguate suggestions with same labels + let lastItem: SnippetSuggestion; + for (const item of suggestions.sort(SnippetSuggestion.compareByLabel)) { + if (lastItem && lastItem.label === item.label) { + // use the disambiguateLabel instead of the actual label + lastItem.label = localize('snippetSuggest.longLabel', "{0}, {1}", lastItem.label, lastItem.snippet.name); + item.label = localize('snippetSuggest.longLabel', "{0}, {1}", item.label, item.snippet.name); + } + lastItem = item; } - } - // dismbiguate suggestions with same labels - let lastItem: SnippetSuggestion; - for (const item of suggestions.sort(SnippetSuggestion.compareByLabel)) { - if (lastItem && lastItem.label === item.label) { - // use the disambiguateLabel instead of the actual label - lastItem.label = localize('snippetSuggest.longLabel', "{0}, {1}", lastItem.label, lastItem.snippet.name); - item.label = localize('snippetSuggest.longLabel', "{0}, {1}", item.label, item.snippet.name); - } - lastItem = item; - } - - return { suggestions }; + return { suggestions }; + }); } resolveCompletionItem?(model: IModel, position: Position, item: ISuggestion): ISuggestion { diff --git a/src/vs/workbench/parts/snippets/electron-browser/tabCompletion.ts b/src/vs/workbench/parts/snippets/electron-browser/tabCompletion.ts index 5784ed551bb..620afaa6156 100644 --- a/src/vs/workbench/parts/snippets/electron-browser/tabCompletion.ts +++ b/src/vs/workbench/parts/snippets/electron-browser/tabCompletion.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { RawContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { RawContextKey, IContextKeyService, ContextKeyExpr, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ISnippetsService, Snippet } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution'; import { getNonWhitespacePrefix, SnippetSuggestion } from 'vs/workbench/parts/snippets/electron-browser/snippetsService'; @@ -15,11 +15,13 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { endsWith } from 'vs/base/common/strings'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import * as editorCommon from 'vs/editor/common/editorCommon'; +import { Range } from 'vs/editor/common/core/range'; import { CommonEditorRegistry, commonEditorContribution, EditorCommand } from 'vs/editor/common/editorCommonExtensions'; import { SnippetController2 } from 'vs/editor/contrib/snippet/browser/snippetController2'; import { showSimpleSuggestions } from 'vs/editor/contrib/suggest/browser/suggest'; import { IConfigurationRegistry, Extensions as ConfigExt } from 'vs/platform/configuration/common/configurationRegistry'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @commonEditorContribution export class TabCompletionController implements editorCommon.IEditorContribution { @@ -31,44 +33,24 @@ export class TabCompletionController implements editorCommon.IEditorContribution return editor.getContribution(TabCompletionController.ID); } - private readonly _editor: editorCommon.ICommonCodeEditor; - private readonly _snippetController: SnippetController2; - private readonly _dispoables: IDisposable[] = []; - private _snippets: Snippet[] = []; + private _hasSnippets: IContextKey; + private _activeSnippets: Snippet[] = []; + private _selectionListener: IDisposable; + private _configListener: IDisposable; constructor( - editor: editorCommon.ICommonCodeEditor, + private readonly _editor: editorCommon.ICommonCodeEditor, + @ISnippetsService private readonly _snippetService: ISnippetsService, + @IConfigurationService private readonly _configurationService: IConfigurationService, @IContextKeyService contextKeyService: IContextKeyService, - @ISnippetsService snippetService: ISnippetsService ) { - this._editor = editor; - this._snippetController = SnippetController2.get(editor); - - const hasSnippets = TabCompletionController.ContextKey.bindTo(contextKeyService); - this._dispoables.push(editor.onDidChangeCursorSelection(e => { - - this._snippets.length = 0; - let selectFn: (snippet: Snippet) => boolean; - - if (e.selection.isEmpty()) { - // empty selection -> real text (no whitespace) left of cursor - const prefix = getNonWhitespacePrefix(editor.getModel(), editor.getPosition()); - selectFn = prefix && (snippet => endsWith(prefix, snippet.prefix)); - - } else if (e.selection.startLineNumber === e.selection.endLineNumber && editor.getModel().getValueLengthInRange(e.selection) <= 100) { - // actual selection -> snippet must be a full match - const selected = editor.getModel().getValueInRange(e.selection); - selectFn = snippet => selected === snippet.prefix; + this._hasSnippets = TabCompletionController.ContextKey.bindTo(contextKeyService); + this._configListener = this._configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('editor.tabCompletion')) { + this._update(); } - - if (selectFn) { - const model = editor.getModel(); - model.tokenizeIfCheap(e.selection.positionLineNumber); - const id = model.getLanguageIdAtPosition(e.selection.positionLineNumber, e.selection.positionColumn); - this._snippets = snippetService.getSnippetsSync(id).filter(selectFn); - } - hasSnippets.set(this._snippets.length > 0); - })); + }); + this._update(); } getId(): string { @@ -76,19 +58,76 @@ export class TabCompletionController implements editorCommon.IEditorContribution } dispose(): void { - dispose(this._dispoables); + dispose(this._configListener); + dispose(this._selectionListener); + } + + private _update(): void { + const enabled = this._configurationService.getValue('editor.tabCompletion'); + if (!enabled) { + dispose(this._selectionListener); + } else { + this._selectionListener = this._editor.onDidChangeCursorSelection(e => this._updateSnippets()); + if (this._editor.getModel()) { + this._updateSnippets(); + } + } + } + + private _updateSnippets(): void { + + // reset first + this._activeSnippets = []; + + // lots of dance for getting the + const selection = this._editor.getSelection(); + const model = this._editor.getModel(); + model.tokenizeIfCheap(selection.positionLineNumber); + const id = model.getLanguageIdAtPosition(selection.positionLineNumber, selection.positionColumn); + const snippets = this._snippetService.getSnippetsSync(id); + + if (!snippets) { + // nothing for this language + this._hasSnippets.set(false); + return; + } + + if (Range.isEmpty(selection)) { + // empty selection -> real text (no whitespace) left of cursor + const prefix = getNonWhitespacePrefix(model, selection.getPosition()); + if (prefix) { + for (const snippet of snippets) { + if (endsWith(prefix, snippet.prefix)) { + this._activeSnippets.push(snippet); + } + } + } + + } else if (!Range.spansMultipleLines(selection) && model.getValueLengthInRange(selection) <= 100) { + // actual selection -> snippet must be a full match + const selected = model.getValueInRange(selection); + if (selected) { + for (const snippet of snippets) { + if (selected === snippet.prefix) { + this._activeSnippets.push(snippet); + } + } + } + } + + this._hasSnippets.set(this._activeSnippets.length > 0); } performSnippetCompletions(): void { - if (this._snippets.length === 1) { + if (this._activeSnippets.length === 1) { // one -> just insert - const [snippet] = this._snippets; - this._snippetController.insert(snippet.codeSnippet, snippet.prefix.length, 0); + const [snippet] = this._activeSnippets; + SnippetController2.get(this._editor).insert(snippet.codeSnippet, snippet.prefix.length, 0); - } else if (this._snippets.length > 1) { + } else if (this._activeSnippets.length > 1) { // two or more -> show IntelliSense box - showSimpleSuggestions(this._editor, this._snippets.map(snippet => new SnippetSuggestion(snippet, snippet.prefix.length))); + showSimpleSuggestions(this._editor, this._activeSnippets.map(snippet => new SnippetSuggestion(snippet, snippet.prefix.length))); } } } @@ -104,8 +143,7 @@ CommonEditorRegistry.registerEditorCommand(new TabCompletionCommand({ kbExpr: ContextKeyExpr.and( EditorContextKeys.textFocus, EditorContextKeys.tabDoesNotMoveFocus, - SnippetController2.InSnippetMode.toNegated(), - ContextKeyExpr.has('config.editor.tabCompletion') + SnippetController2.InSnippetMode.toNegated() ), primary: KeyCode.Tab } diff --git a/src/vs/workbench/parts/snippets/test/electron-browser/snippetsRewrite.test.ts b/src/vs/workbench/parts/snippets/test/electron-browser/snippetsRewrite.test.ts index 033528c8ca3..ab171d24f38 100644 --- a/src/vs/workbench/parts/snippets/test/electron-browser/snippetsRewrite.test.ts +++ b/src/vs/workbench/parts/snippets/test/electron-browser/snippetsRewrite.test.ts @@ -6,12 +6,12 @@ 'use strict'; import * as assert from 'assert'; -import { SnippetFile } from 'vs/workbench/parts/snippets/electron-browser/snippetsFile'; +import { Snippet } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution'; -suite('TMSnippets', function () { +suite('SnippetRewrite', function () { function assertRewrite(input: string, expected: string | boolean): void { - const actual = SnippetFile._rewriteBogousVariables(input); + const actual = Snippet._rewriteBogousVariables(input); assert.equal(actual, expected); } @@ -43,4 +43,11 @@ suite('TMSnippets', function () { test('Snippet choices: unable to escape comma and pipe, #31521', function () { assertRewrite('console.log(${1|not\\, not, five, 5, 1 23|});', false); }); + + test('lazy bogous variable rewrite', function () { + const snippet = new Snippet('foo', 'prefix', 'desc', 'This is ${bogous} because it is a ${var}', 'source'); + assert.equal(snippet.body, 'This is ${bogous} because it is a ${var}'); + assert.equal(snippet.codeSnippet, 'This is ${1:bogous} because it is a ${2:var}'); + assert.equal(snippet.isBogous, true); + }); }); diff --git a/src/vs/workbench/parts/snippets/test/electron-browser/snippetsService.test.ts b/src/vs/workbench/parts/snippets/test/electron-browser/snippetsService.test.ts index bfeb7ee9116..6093d376ea2 100644 --- a/src/vs/workbench/parts/snippets/test/electron-browser/snippetsService.test.ts +++ b/src/vs/workbench/parts/snippets/test/electron-browser/snippetsService.test.ts @@ -12,14 +12,13 @@ import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; import { Model } from 'vs/editor/common/model/model'; import { ISnippetsService, Snippet } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution'; -import { TPromise } from 'vs/base/common/winjs.base'; class SimpleSnippetService implements ISnippetsService { _serviceBrand: any; constructor(readonly snippets: Snippet[]) { } getSnippets() { - return TPromise.as(this.getSnippetsSync()); + return Promise.resolve(this.getSnippetsSync()); } getSnippetsSync(): Snippet[] { return this.snippets; @@ -40,118 +39,123 @@ suite('SnippetsService', function () { setup(function () { modeService = new ModeServiceImpl(); - snippetService = new SimpleSnippetService([{ - prefix: 'bar', - codeSnippet: 'barCodeSnippet', - name: 'barTest', - description: '', - source: '' - }, { - prefix: 'bazz', - codeSnippet: 'bazzCodeSnippet', - name: 'bazzTest', - description: '', - source: '' - }]); + snippetService = new SimpleSnippetService([new Snippet( + 'barTest', + 'bar', + '', + 'barCodeSnippet', + '' + ), new Snippet( + 'bazzTest', + 'bazz', + '', + 'bazzCodeSnippet', + '' + )]); }); - test('snippet completions - simple', async function () { + test('snippet completions - simple', function () { const provider = new SnippetSuggestProvider(modeService, snippetService); const model = Model.createFromString('', undefined, modeService.getLanguageIdentifier('fooLang')); - const result = await provider.provideCompletionItems(model, new Position(1, 1)); - - assert.equal(result.incomplete, undefined); - assert.equal(result.suggestions.length, 2); + return provider.provideCompletionItems(model, new Position(1, 1)).then(result => { + assert.equal(result.incomplete, undefined); + assert.equal(result.suggestions.length, 2); + }); }); - test('snippet completions - with prefix', async function () { + test('snippet completions - with prefix', function () { const provider = new SnippetSuggestProvider(modeService, snippetService); const model = Model.createFromString('bar', undefined, modeService.getLanguageIdentifier('fooLang')); - const result = await provider.provideCompletionItems(model, new Position(1, 4)); - - assert.equal(result.incomplete, undefined); - assert.equal(result.suggestions.length, 1); - assert.equal(result.suggestions[0].label, 'bar'); - assert.equal(result.suggestions[0].insertText, 'barCodeSnippet'); + return provider.provideCompletionItems(model, new Position(1, 4)).then(result => { + assert.equal(result.incomplete, undefined); + assert.equal(result.suggestions.length, 1); + assert.equal(result.suggestions[0].label, 'bar'); + assert.equal(result.suggestions[0].insertText, 'barCodeSnippet'); + }); }); - test('Cannot use " { + assert.equal(result.suggestions.length, 1); + model.dispose(); - model = Model.createFromString('\t { + assert.equal(result.suggestions.length, 1); + model.dispose(); - model = Model.createFromString('a { + + assert.equal(result.suggestions.length, 0); + model.dispose(); + }); }); - test('No user snippets in suggestions, when inside the code, #30508', async function () { + test('No user snippets in suggestions, when inside the code, #30508', function () { - snippetService = new SimpleSnippetService([{ - prefix: 'foo', - codeSnippet: '$0', - name: '', - description: '', - source: '' - }]); + snippetService = new SimpleSnippetService([new Snippet( + '', + 'foo', + '', + '$0', + '' + )]); const provider = new SnippetSuggestProvider(modeService, snippetService); let model = Model.createFromString('\n\t\n>/head>', undefined, modeService.getLanguageIdentifier('fooLang')); - let result = await provider.provideCompletionItems(model, new Position(1, 1)); - assert.equal(result.suggestions.length, 1); - - result = await provider.provideCompletionItems(model, new Position(2, 2)); - assert.equal(result.suggestions.length, 1); + return provider.provideCompletionItems(model, new Position(1, 1)).then(result => { + assert.equal(result.suggestions.length, 1); + return provider.provideCompletionItems(model, new Position(2, 2)); + }).then(result => { + assert.equal(result.suggestions.length, 1); + }); }); - test('SnippetSuggest - ensure extension snippets come last ', async function () { - snippetService = new SimpleSnippetService([{ - prefix: 'second', - codeSnippet: 'second', - name: 'second', - description: '', - source: '', - isFromExtension: true - }, { - prefix: 'first', - codeSnippet: 'first', - name: 'first', - description: '', - source: '', - isFromExtension: false - }]); + test('SnippetSuggest - ensure extension snippets come last ', function () { + snippetService = new SimpleSnippetService([new Snippet( + 'second', + 'second', + '', + 'second', + '', + true + ), new Snippet( + 'first', + 'first', + '', + 'first', + '', + false + )]); const provider = new SnippetSuggestProvider(modeService, snippetService); let model = Model.createFromString('', undefined, modeService.getLanguageIdentifier('fooLang')); - let result = await provider.provideCompletionItems(model, new Position(1, 1)); - assert.equal(result.suggestions.length, 2); - - let [first, second] = result.suggestions; - assert.equal(first.label, 'first'); - assert.equal(second.label, 'second'); + return provider.provideCompletionItems(model, new Position(1, 1)).then(result => { + assert.equal(result.suggestions.length, 2); + let [first, second] = result.suggestions; + assert.equal(first.label, 'first'); + assert.equal(second.label, 'second'); + }); }); }); diff --git a/src/vs/workbench/parts/tasks/electron-browser/jsonSchemaCommon.ts b/src/vs/workbench/parts/tasks/electron-browser/jsonSchemaCommon.ts index 51b794a250a..484af6701b0 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/jsonSchemaCommon.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/jsonSchemaCommon.ts @@ -175,6 +175,7 @@ const schema: IJSONSchema = { }, taskRunnerConfiguration: { type: 'object', + required: [], properties: { command: { type: 'string', diff --git a/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.ts b/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.ts index 7577edc410f..424cf790b3c 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.ts @@ -145,8 +145,13 @@ const group: IJSONSchema = { const taskType: IJSONSchema = { type: 'string', enum: ['shell', 'process'], - default: 'process', - description: nls.localize('JsonSchema.tasks.type', 'Defines whether the task is run as a process or as a command inside a shell. Default is process.') + default: 'shell', + description: nls.localize('JsonSchema.tasks.type', 'Defines whether the task is run as a process or as a command inside a shell.') +}; + +const label: IJSONSchema = { + type: 'string', + description: nls.localize('JsonSchema.tasks.label', "The task's user interface label") }; const version: IJSONSchema = { @@ -224,6 +229,8 @@ taskDefinitions.push(customize); let definitions = Objects.deepClone(commonSchema.definitions); let taskDescription: IJSONSchema = definitions.taskDescription; +taskDescription.required = ['label', 'type']; +taskDescription.properties.label = Objects.deepClone(label); taskDescription.properties.isShellCommand = Objects.deepClone(shellCommand); taskDescription.properties.dependsOn = dependsOn; taskDescription.properties.identifier = Objects.deepClone(identifier); @@ -231,6 +238,16 @@ taskDescription.properties.type = Objects.deepClone(taskType); taskDescription.properties.presentation = Objects.deepClone(presentation); taskDescription.properties.terminal = terminal; taskDescription.properties.group = Objects.deepClone(group); +taskDescription.properties.taskName.deprecationMessage = nls.localize( + 'JsonSchema.tasks.taskName.deprecated', + 'The task\'s name property is deprecated. Use the label property instead.' +); +taskDescription.default = { + label: 'My Task', + type: 'shell', + command: 'echo Hello', + problemMatcher: [] +}; definitions.showOutputType.deprecationMessage = nls.localize( 'JsonSchema.tasks.showOputput.deprecated', 'The property showOutput is deprecated. Use the reveal property inside the presentation property instead. See also the 1.14 release notes.' diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index 14c8cddf519..a476289267a 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -1411,7 +1411,9 @@ class TaskService extends EventEmitter implements ITaskService { let customTasksToDelete: Task[] = []; if (configurations || legacyTaskConfigurations) { let unUsedConfigurations: Set = new Set(); - Object.keys(configurations.byIdentifier).forEach(key => unUsedConfigurations.add(key)); + if (configurations) { + Object.keys(configurations.byIdentifier).forEach(key => unUsedConfigurations.add(key)); + } for (let task of contributed) { if (!ContributedTask.is(task)) { continue; diff --git a/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts b/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts index b3e4d73c599..bf9e700758e 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts @@ -552,14 +552,7 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { shellLaunchConfig.cwd = options.cwd; } if (options.env) { - let env: IStringDictionary = Object.create(null); - Object.keys(process.env).forEach((key) => { - env[key] = process.env[key]; - }); - Object.keys(options.env).forEach((key) => { - env[key] = options.env[key]; - }); - shellLaunchConfig.env = env; + shellLaunchConfig.env = options.env; } let prefersSameTerminal = task.command.presentation.panel === PanelKind.Dedicated; let allowsSharedTerminal = task.command.presentation.panel === PanelKind.Shared; diff --git a/src/vs/workbench/parts/tasks/node/taskConfiguration.ts b/src/vs/workbench/parts/tasks/node/taskConfiguration.ts index 83efb04743b..a98744c2025 100644 --- a/src/vs/workbench/parts/tasks/node/taskConfiguration.ts +++ b/src/vs/workbench/parts/tasks/node/taskConfiguration.ts @@ -1246,6 +1246,9 @@ namespace CustomTask { return undefined; } let taskName = external.taskName; + if (Types.isString(external.label) && context.schemaVersion === Tasks.JsonSchemaVersion.V2_0_0) { + taskName = external.label; + } if (!taskName) { context.problemReporter.error(nls.localize('ConfigurationParser.noTaskName', 'Error: tasks must provide a taskName property. The task will be ignored.\n{0}\n', JSON.stringify(external, null, 4))); return undefined; diff --git a/src/vs/workbench/parts/terminal/common/terminalService.ts b/src/vs/workbench/parts/terminal/common/terminalService.ts index 44815065a04..55e392cb988 100644 --- a/src/vs/workbench/parts/terminal/common/terminalService.ts +++ b/src/vs/workbench/parts/terminal/common/terminalService.ts @@ -59,7 +59,11 @@ export abstract class TerminalService implements ITerminalService { this._onInstanceTitleChanged = new Emitter(); this._onInstancesChanged = new Emitter(); - this._configurationService.onDidChangeConfiguration(() => this.updateConfig()); + this._configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('terminal.integrated')) { + this.updateConfig(); + } + }); lifecycleService.onWillShutdown(event => event.veto(this._onWillShutdown())); this._terminalFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_FOCUS.bindTo(this._contextKeyService); this._findWidgetVisible = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE.bindTo(this._contextKeyService); @@ -185,13 +189,17 @@ export abstract class TerminalService implements ITerminalService { if (!panel || panel.getId() !== TERMINAL_PANEL_ID) { return this._panelService.openPanel(TERMINAL_PANEL_ID, focus).then(() => { if (focus) { - this.getActiveInstance().focus(true); + // Do the focus call asynchronously as going through the + // command palette will force editor focus + setTimeout(() => this.getActiveInstance().focus(true), 0); } complete(void 0); }); } else { if (focus) { - this.getActiveInstance().focus(true); + // Do the focus call asynchronously as going through the + // command palette will force editor focus + setTimeout(() => this.getActiveInstance().focus(true), 0); } complete(void 0); } 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 d0771e15cb5..a59abbfbaa3 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts @@ -18,7 +18,7 @@ import { TERMINAL_DEFAULT_SHELL_LINUX, TERMINAL_DEFAULT_SHELL_OSX, TERMINAL_DEFA import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { KillTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ToggleTerminalAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, RenameTerminalAction, SelectAllTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, ShowNextFindTermTerminalFindWidgetAction, ShowPreviousFindTermTerminalFindWidgetAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, TERMINAL_PICKER_PREFIX, CreateNewSelectWorkspaceTerminalAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; +import { KillTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ToggleTerminalAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, RenameTerminalAction, SelectAllTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, ShowNextFindTermTerminalFindWidgetAction, ShowPreviousFindTermTerminalFindWidgetAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, TERMINAL_PICKER_PREFIX } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; import { Registry } from 'vs/platform/registry/common/platform'; import { ShowAllCommandsAction } from 'vs/workbench/parts/quickopen/browser/commandsHandler'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; @@ -188,12 +188,18 @@ configurationRegistry.registerConfiguration({ QUICKOPEN_FOCUS_SECONDARY_ACTION_ID, ShowAllCommandsAction.ID, CreateNewTerminalAction.ID, - CreateNewSelectWorkspaceTerminalAction.ID, CopyTerminalSelectionAction.ID, KillTerminalAction.ID, FocusActiveTerminalAction.ID, FocusPreviousTerminalAction.ID, FocusNextTerminalAction.ID, + 'workbench.action.tasks.build', + 'workbench.action.tasks.restartTask', + 'workbench.action.tasks.runTask', + 'workbench.action.tasks.showLog', + 'workbench.action.tasks.showTasks', + 'workbench.action.tasks.terminate', + 'workbench.action.tasks.test', 'workbench.action.terminal.focusAtIndex1', 'workbench.action.terminal.focusAtIndex2', 'workbench.action.terminal.focusAtIndex3', @@ -281,7 +287,6 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewTermina primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_BACKTICK, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.US_BACKTICK } }), 'Terminal: Create New Integrated Terminal', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewSelectWorkspaceTerminalAction, CreateNewSelectWorkspaceTerminalAction.ID, CreateNewSelectWorkspaceTerminalAction.LABEL), 'Terminal: Create New Integrated Terminal (Select Workspace)', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusActiveTerminalAction, FocusActiveTerminalAction.ID, FocusActiveTerminalAction.LABEL), 'Terminal: Focus Terminal', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextTerminalAction, FocusNextTerminalAction.ID, FocusNextTerminalAction.LABEL), 'Terminal: Focus Next Terminal', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousTerminalAction, FocusPreviousTerminalAction.ID, FocusPreviousTerminalAction.LABEL), 'Terminal: Focus Previous Terminal', category); diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts index 13ad6995359..ce3950c1dbb 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts @@ -8,7 +8,7 @@ import * as os from 'os'; import { Action, IAction } from 'vs/base/common/actions'; import { EndOfLinePreference } from 'vs/editor/common/editorCommon'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; -import { ITerminalService, TERMINAL_PANEL_ID } from 'vs/workbench/parts/terminal/common/terminal'; +import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance } from 'vs/workbench/parts/terminal/common/terminal'; import { SelectActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { TPromise } from 'vs/base/common/winjs.base'; import { TogglePanelAction } from 'vs/workbench/browser/panel'; @@ -23,6 +23,7 @@ import { TerminalEntry } from 'vs/workbench/parts/terminal/browser/terminalQuick import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { PICK_WORKSPACE_FOLDER_COMMAND } from 'vs/workbench/browser/actions/workspaceActions'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; export const TERMINAL_PICKER_PREFIX = 'term '; @@ -198,42 +199,37 @@ export class CreateNewTerminalAction extends Action { public static ID = 'workbench.action.terminal.new'; public static LABEL = nls.localize('workbench.action.terminal.new', "Create New Integrated Terminal"); - - constructor( - id: string, label: string, - @ITerminalService private terminalService: ITerminalService - ) { - super(id, label); - } - - public run(event?: any): TPromise { - const instance = this.terminalService.createInstance(undefined, true); - if (!instance) { - return TPromise.as(void 0); - } - this.terminalService.setActiveInstance(instance); - return this.terminalService.showPanel(true); - } -} - -export class CreateNewSelectWorkspaceTerminalAction extends Action { - - public static ID = 'workbench.action.terminal.newSelectWorkspace'; - public static LABEL = nls.localize('workbench.action.terminal.newSelectWorkspace', "Create New Integrated Terminal (Select Workspace)"); public static PANEL_LABEL = nls.localize('workbench.action.terminal.new.short', "New Terminal"); constructor( id: string, label: string, @ITerminalService private terminalService: ITerminalService, - @ICommandService private commandService: ICommandService + @ICommandService private commandService: ICommandService, + @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService ) { super(id, label); this.class = 'terminal-action new'; } public run(event?: any): TPromise { - return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND).then(workspace => { - const instance = this.terminalService.createInstance(workspace ? { cwd: workspace.uri.fsPath } : undefined, true); + const folders = this.workspaceContextService.getWorkspace().folders; + + let instancePromise: TPromise; + if (folders.length <= 1) { + // Allow terminal service to handle the path when there is only a + // single root + instancePromise = TPromise.as(this.terminalService.createInstance(undefined, true)); + } else { + instancePromise = this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND).then(workspace => { + if (!workspace) { + // Don't create the instance if the workspace picker was canceled + return null; + } + return this.terminalService.createInstance({ cwd: workspace.uri.fsPath }, true); + }); + } + + return instancePromise.then(instance => { if (!instance) { return TPromise.as(void 0); } diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts index 753f9d5e055..62281821b81 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts @@ -28,6 +28,8 @@ interface IFullTerminalConfiguration { const DEFAULT_LINE_HEIGHT = 1.0; +const MINIMUM_FONT_SIZE = 6; + /** * Encapsulates terminal configuration logic, the primary purpose of this file is so that platform * specific test cases can be written. @@ -99,10 +101,7 @@ export class TerminalConfigHelper implements ITerminalConfigHelper { } } - let fontSize = this._toInteger(terminalConfig.fontSize, 0); - if (fontSize <= 0) { - fontSize = EDITOR_FONT_DEFAULTS.fontSize; - } + let fontSize = this._toInteger(terminalConfig.fontSize, MINIMUM_FONT_SIZE, EDITOR_FONT_DEFAULTS.fontSize); const lineHeight = terminalConfig.lineHeight ? Math.max(terminalConfig.lineHeight, 1) : DEFAULT_LINE_HEIGHT; if (excludeDimensions) { @@ -180,10 +179,10 @@ export class TerminalConfigHelper implements ITerminalConfigHelper { } } - private _toInteger(source: any, minimum?: number): number { + private _toInteger(source: any, minimum: number, fallback: number): number { let r = parseInt(source, 10); if (isNaN(r)) { - r = 0; + return fallback; } if (typeof minimum === 'number') { r = Math.max(minimum, r); diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index 378e96b3648..07075759c0b 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -592,7 +592,7 @@ export class TerminalInstance implements ITerminalInstance { if (!this._shellLaunchConfig.executable) { this._configHelper.mergeDefaultShellPathAndArgs(this._shellLaunchConfig); } - this._initialCwd = this._getCwd(this._shellLaunchConfig, this._historyService.getLastActiveWorkspaceRoot()); + this._initialCwd = this._getCwd(this._shellLaunchConfig, this._historyService.getLastActiveWorkspaceRoot('file')); let envFromConfig: IStringDictionary; if (platform.isWindows) { envFromConfig = { ...process.env }; @@ -778,7 +778,18 @@ export class TerminalInstance implements ITerminalInstance { // TODO: This should be private/protected // TODO: locale should not be optional public static createTerminalEnv(parentEnv: IStringDictionary, shell: IShellLaunchConfig, cwd: string, locale?: string, cols?: number, rows?: number): IStringDictionary { - const env = shell.env ? shell.env : TerminalInstance._cloneEnv(parentEnv); + const env = TerminalInstance._cloneEnv(parentEnv); + if (shell.env) { + Object.keys(shell.env).forEach((key) => { + const value = shell.env[key]; + if (typeof value === 'string') { + env[key] = value; + } else { + delete env[key]; + } + }); + } + env['PTYPID'] = process.pid.toString(); env['PTYSHELL'] = shell.executable; env['TERM_PROGRAM'] = 'vscode'; diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts index d382d1f2aa5..a67a1bceefb 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts @@ -19,7 +19,7 @@ import { ITerminalService, ITerminalFont, TERMINAL_PANEL_ID } from 'vs/workbench import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { TerminalFindWidget } from './terminalFindWidget'; import { editorHoverBackground, editorHoverBorder, editorForeground } from 'vs/platform/theme/common/colorRegistry'; -import { KillTerminalAction, CreateNewSelectWorkspaceTerminalAction, SwitchTerminalInstanceAction, SwitchTerminalInstanceActionItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; +import { KillTerminalAction, SwitchTerminalInstanceAction, SwitchTerminalInstanceActionItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction, CreateNewTerminalAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; import { Panel } from 'vs/workbench/browser/panel'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -74,7 +74,11 @@ export class TerminalPanel extends Panel { this._terminalService.setContainers(this.getContainer().getHTMLElement(), this._terminalContainer); this._register(this.themeService.onThemeChange(theme => this._updateTheme(theme))); - this._register(this._configurationService.onDidChangeConfiguration(() => this._updateFont())); + this._register(this._configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('terminal.integrated') || e.affectsConfiguration('editor.fontFamily')) { + this._updateFont(); + } + })); this._updateFont(); this._updateTheme(); @@ -115,7 +119,7 @@ export class TerminalPanel extends Panel { if (!this._actions) { this._actions = [ this._instantiationService.createInstance(SwitchTerminalInstanceAction, SwitchTerminalInstanceAction.ID, SwitchTerminalInstanceAction.LABEL), - this._instantiationService.createInstance(CreateNewSelectWorkspaceTerminalAction, CreateNewSelectWorkspaceTerminalAction.ID, CreateNewSelectWorkspaceTerminalAction.PANEL_LABEL), + this._instantiationService.createInstance(CreateNewTerminalAction, CreateNewTerminalAction.ID, CreateNewTerminalAction.PANEL_LABEL), this._instantiationService.createInstance(KillTerminalAction, KillTerminalAction.ID, KillTerminalAction.PANEL_LABEL) ]; this._actions.forEach(a => { @@ -129,7 +133,7 @@ export class TerminalPanel extends Panel { if (!this._contextMenuActions) { this._copyContextMenuAction = this._instantiationService.createInstance(CopyTerminalSelectionAction, CopyTerminalSelectionAction.ID, nls.localize('copy', "Copy")); this._contextMenuActions = [ - this._instantiationService.createInstance(CreateNewSelectWorkspaceTerminalAction, CreateNewSelectWorkspaceTerminalAction.ID, CreateNewSelectWorkspaceTerminalAction.PANEL_LABEL), + this._instantiationService.createInstance(CreateNewTerminalAction, CreateNewTerminalAction.ID, CreateNewTerminalAction.PANEL_LABEL), new Separator(), this._copyContextMenuAction, this._instantiationService.createInstance(TerminalPasteAction, TerminalPasteAction.ID, nls.localize('paste', "Paste")), diff --git a/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts b/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts index 2fb9993bf0a..be088071437 100644 --- a/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts +++ b/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts @@ -78,23 +78,22 @@ suite('Workbench - TerminalConfigHelper', () => { configurationService = new MockConfigurationService({ editor: { fontFamily: 'foo', - fontSize: 1 + fontSize: 9 }, terminal: { integrated: { fontFamily: 'bar', - fontSize: 2 + fontSize: 10 } } }); configHelper = new TerminalConfigHelper(Platform.Linux, configurationService, null, null, null); configHelper.panelContainer = fixture; - assert.equal(configHelper.getFont().fontSize, 2, 'terminal.integrated.fontSize should be selected over editor.fontSize'); + assert.equal(configHelper.getFont().fontSize, 10, 'terminal.integrated.fontSize should be selected over editor.fontSize'); configurationService = new MockConfigurationService({ editor: { - fontFamily: 'foo', - fontSize: 0 + fontFamily: 'foo' }, terminal: { integrated: { @@ -105,23 +104,22 @@ suite('Workbench - TerminalConfigHelper', () => { }); configHelper = new TerminalConfigHelper(Platform.Linux, configurationService, null, null, null); configHelper.panelContainer = fixture; - assert.equal(configHelper.getFont().fontSize, EDITOR_FONT_DEFAULTS.fontSize, 'The default editor font size should be used when editor.fontSize is 0 and terminal.integrated.fontSize not set'); + assert.equal(configHelper.getFont().fontSize, 6, 'The minimum terminal font size should be used when terminal.integrated.fontSize less than it'); configurationService = new MockConfigurationService({ editor: { fontFamily: 'foo', - fontSize: 0 }, terminal: { integrated: { fontFamily: 0, - fontSize: -10 + fontSize: null } } }); configHelper = new TerminalConfigHelper(Platform.Linux, configurationService, null, null, null); configHelper.panelContainer = fixture; - assert.equal(configHelper.getFont().fontSize, EDITOR_FONT_DEFAULTS.fontSize, 'The default editor font size should be used when editor.fontSize is < 0 and terminal.integrated.fontSize not set'); + assert.equal(configHelper.getFont().fontSize, EDITOR_FONT_DEFAULTS.fontSize, 'The default editor font size should be used when terminal.integrated.fontSize is not set'); }); test('TerminalConfigHelper - getFont lineHeight', function () { diff --git a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts index 8acbac70b41..1031a79131b 100644 --- a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts +++ b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts @@ -19,8 +19,8 @@ import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { OpenRecentAction } from 'vs/workbench/electron-browser/actions'; -import { GlobalNewUntitledFileAction, OpenFileAction } from 'vs/workbench/parts/files/browser/fileActions'; -import { OpenFolderAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; +import { GlobalNewUntitledFileAction } from 'vs/workbench/parts/files/browser/fileActions'; +import { OpenFolderAction, OpenFileFolderAction, OpenFileAction } from 'vs/workbench/browser/actions/workspaceActions'; import { ShowAllCommandsAction } from 'vs/workbench/parts/quickopen/browser/commandsHandler'; import { Parts, IPartService } from 'vs/workbench/services/part/common/partService'; import { StartAction } from 'vs/workbench/parts/debug/browser/debugActions'; diff --git a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts index dff17826c3b..72d281c079a 100644 --- a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts +++ b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts @@ -417,7 +417,7 @@ class WelcomePage { extensionId: extensionSuggestion.id, }); this.instantiationService.invokeFunction(getInstalledExtensions).then(extensions => { - const installedExtension = arrays.first(extensions, extension => extension.identifier === extensionSuggestion.id); + const installedExtension = arrays.first(extensions, extension => extension.identifier.id === extensionSuggestion.id); if (installedExtension && installedExtension.globallyEnabled) { /* __GDPR__FRAGMENT__ "WelcomePageInstalled-1" : { @@ -443,7 +443,7 @@ class WelcomePage { return this.extensionManagementService.installFromGallery(extension) .then(() => { // TODO: Do this as part of the install to avoid multiple events. - return this.extensionEnablementService.setEnablement(extensionSuggestion.id, false); + return this.extensionEnablementService.setEnablement({ id: extensionSuggestion.id }, false); }).then(() => { return true; }); @@ -466,7 +466,7 @@ class WelcomePage { return foundAndInstalled.then(found => { messageDelay.cancel(); if (found) { - return this.extensionEnablementService.setEnablement(extensionSuggestion.id, true) + return this.extensionEnablementService.setEnablement({ id: extensionSuggestion.id }, true) .then(() => { /* __GDPR__FRAGMENT__ "WelcomePageInstalled-2" : { diff --git a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts index 65a97a110a8..23420f77df0 100644 --- a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts +++ b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts @@ -19,7 +19,7 @@ import { FileService } from 'vs/workbench/services/files/node/fileService'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { parseArgs } from 'vs/platform/environment/node/argv'; import { RawTextSource } from 'vs/editor/common/model/textSource'; -import { TestContextService, TestTextResourceConfigurationService } from 'vs/workbench/test/workbenchTestServices'; +import { TestContextService, TestTextResourceConfigurationService, getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; @@ -34,7 +34,7 @@ class TestEnvironmentService extends EnvironmentService { get backupWorkspacesPath(): string { return this._backupWorkspacesPath; } } -const parentDir = path.join(os.tmpdir(), 'vsctests', 'service'); +const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice'); const backupHome = path.join(parentDir, 'Backups'); const workspacesJsonPath = path.join(backupHome, 'workspaces.json'); diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index 3e72fc9fe57..033e039225b 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -5,7 +5,7 @@ 'use strict'; import { clone, equals } from 'vs/base/common/objects'; -import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget, IConfigurationModel } from 'vs/platform/configuration/common/configuration'; +import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget, IConfigurationModel, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; import { ConfigurationModel, Configuration as BaseConfiguration, CustomConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, IConfigurationPropertySchema, Extensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; @@ -193,8 +193,36 @@ export class Configuration extends BaseConfiguration { protected folders: StrictResourceMap, memoryConfiguration: ConfigurationModel, memoryConfigurationByResource: StrictResourceMap, - workspace: Workspace) { - super(defaults, user, workspaceConfiguration, folders, memoryConfiguration, memoryConfigurationByResource, workspace); + private readonly _workspace: Workspace) { + super(defaults, user, workspaceConfiguration, folders, memoryConfiguration, memoryConfigurationByResource); + } + + getSection(section: string = '', overrides: IConfigurationOverrides = {}): C { + return super.getSection(section, overrides, this._workspace); + } + + getValue(key: string, overrides: IConfigurationOverrides = {}): any { + return super.getValue(key, overrides, this._workspace); + } + + lookup(key: string, overrides: IConfigurationOverrides = {}): { + default: C, + user: C, + workspace: C, + workspaceFolder: C + memory?: C + value: C, + } { + return super.lookup(key, overrides, this._workspace); + } + + keys(): { + default: string[]; + user: string[]; + workspace: string[]; + workspaceFolder: string[]; + } { + return super.keys(this._workspace); } updateDefaultConfiguration(defaults: ConfigurationModel): void { diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index d2a28dd40b2..5418ca53f42 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -106,9 +106,11 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return this.workspace.getFolder(resource); } - public addFolders(foldersToAdd: URI[]): TPromise { + public addFolders(foldersToAdd: URI[]): TPromise; + public addFolders(foldersToAdd: { uri: URI, name?: string }[]): TPromise; + public addFolders(folders: URI[] | { uri: URI, name?: string }[]): TPromise { assert.ok(this.jsonEditingService, 'Workbench is not initialized yet'); - return this.workspaceEditingQueue.queue(() => this.doAddFolders(foldersToAdd)); + return this.workspaceEditingQueue.queue(() => this.doAddFolders(folders)); } public removeFolders(foldersToRemove: URI[]): TPromise { @@ -130,7 +132,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return false; } - private doAddFolders(foldersToAdd: URI[]): TPromise { + private doAddFolders(foldersToAdd: (URI | { uri: URI, name?: string })[]): TPromise { if (this.getWorkbenchState() !== WorkbenchState.WORKSPACE) { return TPromise.as(void 0); // we need a workspace to begin with } @@ -144,23 +146,40 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat const workspaceConfigFolder = dirname(this.getWorkspace().configuration.fsPath); foldersToAdd.forEach(folderToAdd => { - if (this.contains(currentWorkspaceFolderUris, folderToAdd)) { + let folderResource: URI; + let folderName: string; + if (URI.isUri(folderToAdd)) { + folderResource = folderToAdd; + } else { + folderResource = folderToAdd.uri; + folderName = folderToAdd.name; + } + + if (this.contains(currentWorkspaceFolderUris, folderResource)) { return; // already existing } + let storedFolder: IStoredWorkspaceFolder; + // File resource: use "path" property - if (folderToAdd.scheme === Schemas.file) { - storedFoldersToAdd.push({ - path: massageFolderPathForWorkspace(folderToAdd.fsPath, workspaceConfigFolder, currentStoredFolders) - }); + if (folderResource.scheme === Schemas.file) { + storedFolder = { + path: massageFolderPathForWorkspace(folderResource.fsPath, workspaceConfigFolder, currentStoredFolders) + }; } // Any other resource: use "uri" property else { - storedFoldersToAdd.push({ - uri: folderToAdd.toString(true) - }); + storedFolder = { + uri: folderResource.toString(true) + }; } + + if (folderName) { + storedFolder.name = folderName; + } + + storedFoldersToAdd.push(storedFolder); }); if (storedFoldersToAdd.length > 0) { diff --git a/src/vs/workbench/services/configuration/test/node/configurationService.test.ts b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts index 178de894bdd..22ed364bd6c 100644 --- a/src/vs/workbench/services/configuration/test/node/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts @@ -146,7 +146,7 @@ suite('WorkspaceContextService - Folder', () => { suite('WorkspaceContextService - Workspace', () => { - let parentResource: string, testObject: IWorkspaceContextService; + let parentResource: string, testObject: WorkspaceService; setup(() => { return setUpWorkspace(['a', 'b']) @@ -205,6 +205,22 @@ suite('WorkspaceContextService - Workspace', () => { }); }); + test('add folders (with name)', () => { + const workspaceDir = path.dirname(testObject.getWorkspace().folders[0].uri.fsPath); + return testObject.addFolders([{ uri: URI.file(path.join(workspaceDir, 'd')), name: 'DDD' }, { uri: URI.file(path.join(workspaceDir, 'c')), name: 'CCC' }]) + .then(() => { + const actual = testObject.getWorkspace().folders; + + assert.equal(actual.length, 4); + assert.equal(path.basename(actual[0].uri.fsPath), 'a'); + assert.equal(path.basename(actual[1].uri.fsPath), 'b'); + assert.equal(path.basename(actual[2].uri.fsPath), 'd'); + assert.equal(path.basename(actual[3].uri.fsPath), 'c'); + assert.equal(actual[2].name, 'DDD'); + assert.equal(actual[3].name, 'CCC'); + }); + }); + test('add folders triggers change event', () => { const target = sinon.spy(); testObject.onDidChangeWorkspaceFolders(target); diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index cd004e68f20..5f8fdace5c1 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -5,7 +5,7 @@ 'use strict'; import URI from 'vs/base/common/uri'; -import Event, { Emitter, debounceEvent, any } from 'vs/base/common/event'; +import Event, { Emitter, debounceEvent, anyEvent } from 'vs/base/common/event'; import { IDecorationsService, IDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IDecorationData } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; @@ -14,7 +14,6 @@ import { LinkedList } from 'vs/base/common/linkedList'; import { createStyleSheet, createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom'; import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { IdGenerator } from 'vs/base/common/idGenerator'; -import { listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry'; import { IIterator } from 'vs/base/common/iterator'; class DecorationRule { @@ -52,11 +51,9 @@ class DecorationRule { const { color, letter } = data; // label createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'};`, element); - createCSSRule(`.focused .selected .${this.labelClassName}`, `color: inherit; opacity: inherit;`, element); - // badge + // letter if (letter) { - createCSSRule(`.${this.badgeClassName}`, `background-color: ${theme.getColor(color)}; color: ${theme.getColor(listActiveSelectionForeground)};`, element); - createCSSRule(`.${this.badgeClassName}::before`, `content: "${letter}"`, element); + createCSSRule(`.${this.badgeClassName}::after`, `content: "${letter}"; color: ${theme.getColor(color) || 'inherit'};`, element); } } @@ -64,21 +61,12 @@ class DecorationRule { // label const { color } = data[0]; createCSSRule(`.${this.labelClassName}`, `color: ${theme.getColor(color) || 'inherit'};`, element); - createCSSRule(`.focused .selected .${this.labelClassName}`, `color: inherit; opacity: inherit;`, element); // badge - let letters: string[] = []; - let colors: string[] = []; - for (const deco of data) { - letters.push(deco.letter); - colors.push(`${theme.getColor(deco.color).toString()} ${100 / data.length}%`); + const letters = data.filter(d => Boolean(d)).map(d => d.letter); + if (letters.length) { + createCSSRule(`.${this.badgeClassName}::after`, `content: "${letters.join(', ')}"; color: ${theme.getColor(color) || 'inherit'};`, element); } - createCSSRule(`.${this.badgeClassName}::before`, `content: "${letters.join('\u2002')}"`, element); - createCSSRule( - `.${this.badgeClassName}`, - `background: linear-gradient(90deg, ${colors.join()}); color: ${theme.getColor(listActiveSelectionForeground)};`, - element - ); } removeCSSRules(element: HTMLStyleElement): void { @@ -160,15 +148,11 @@ class DecorationStyles { cleanUp(iter: IIterator): void { // remove every rule for which no more // decoration (data) is kept. this isn't cheap - let usedDecorations = new Set(); + let usedDecorations = new Set(); for (let e = iter.next(); !e.done; e = iter.next()) { - e.value.data.forEach(value => { - if (value instanceof ResourceDecoration) { - if (Array.isArray(value._data)) { - value._data.forEach(data => usedDecorations.add(data)); - } else { - usedDecorations.add(value._data); - } + e.value.data.forEach((value, key) => { + if (!isThenable(value) && value) { + usedDecorations.add(DecorationRule.keyOf(value)); } }); } @@ -176,8 +160,8 @@ class DecorationStyles { const { data } = value; let remove: boolean; if (Array.isArray(data)) { - remove = data.every(data => !usedDecorations.has(data)); - } else if (!usedDecorations.has(data)) { + remove = data.some(data => !usedDecorations.has(DecorationRule.keyOf(data))); + } else if (!usedDecorations.has(DecorationRule.keyOf(data))) { remove = true; } if (remove) { @@ -317,7 +301,7 @@ export class FileDecorationsService implements IDecorationsService { private readonly _decorationStyles: DecorationStyles; private readonly _disposables: IDisposable[]; - readonly onDidChangeDecorations: Event = any( + readonly onDidChangeDecorations: Event = anyEvent( this._onDidChangeDecorations.event, debounceEvent( this._onDidChangeDecorationsDelayed.event, @@ -392,6 +376,7 @@ export class FileDecorationsService implements IDecorationsService { } else if (onlyChildren) { let result = this._decorationStyles.asDecoration(data.sort((a, b) => b.weight - a.weight)[0]); result.badgeClassName = ''; + result.title = ''; return result; } else if (data.length === 1) { return this._decorationStyles.asDecoration(data[0]); diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index 721051fb31a..9ea7fd9c29b 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -111,7 +111,7 @@ suite('DecorationsService', function () { onDidChange: Event.None, provideDecorations(uri: URI) { return uri.path.match(/\.txt/) - ? { title: '.txt' } + ? { title: '.txt', weight: 17 } : undefined; } }); @@ -120,6 +120,7 @@ suite('DecorationsService', function () { let deco = service.getDecoration(childUri, false); assert.equal(deco.title, '.txt'); + assert.equal(deco.weight, 17); deco = service.getDecoration(childUri.with({ path: 'some/path/' }), true); assert.equal(deco, undefined); @@ -131,15 +132,17 @@ suite('DecorationsService', function () { onDidChange: Event.None, provideDecorations(uri: URI) { return uri.path.match(/\.txt/) - ? { title: '.txt.bubble', bubble: true } + ? { title: '.txt.bubble', weight: 71, bubble: true } : undefined; } }); deco = service.getDecoration(childUri, false); assert.equal(deco.title, '.txt.bubble'); + assert.equal(deco.weight, 71); deco = service.getDecoration(childUri.with({ path: 'some/path/' }), true); - assert.equal(deco.title, '.txt.bubble'); + assert.equal(deco.title, ''); + assert.equal(deco.weight, 71); }); }); diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index d4b17a7fbc3..126d98d7cc0 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -25,7 +25,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { generateRandomPipeName, Protocol } from 'vs/base/parts/ipc/node/ipc.net'; import { createServer, Server, Socket } from 'net'; -import Event, { Emitter, debounceEvent, mapEvent, any } from 'vs/base/common/event'; +import Event, { Emitter, debounceEvent, mapEvent, anyEvent } from 'vs/base/common/event'; import { fromEventEmitter } from 'vs/base/node/event'; import { IInitData, IWorkspaceData } from 'vs/workbench/api/node/extHost.protocol'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; @@ -171,7 +171,7 @@ export class ExtensionHostProcessWorker { this._extensionHostProcess.stderr.setEncoding('utf8'); const onStdout = fromEventEmitter(this._extensionHostProcess.stdout, 'data'); const onStderr = fromEventEmitter(this._extensionHostProcess.stderr, 'data'); - const onOutput = any( + const onOutput = anyEvent( mapEvent(onStdout, o => ({ data: `%c${o}`, format: [''] })), mapEvent(onStderr, o => ({ data: `%c${o}`, format: ['color: red'] })) ); diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts b/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts index 60261ce5e0d..7e08926c197 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts @@ -59,7 +59,12 @@ class ExtensionManifestParser extends ExtensionManifestHandler { public parse(): TPromise { return pfs.readFile(this._absoluteManifestPath).then((manifestContents) => { try { - return JSON.parse(manifestContents.toString()); + const manifest = JSON.parse(manifestContents.toString()); + if (manifest.__metadata) { + manifest.uuid = manifest.__metadata.id; + } + delete manifest.__metadata; + return manifest; } catch (e) { this._log.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", this._absoluteManifestPath, getParseErrorMessage(e.message))); } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 46852ac7907..aaff127a4b9 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -295,6 +295,10 @@ export class ExtensionService implements IExtensionService { }); ExtensionService._scanInstalledExtensions(this._environmentService, log).then((installedExtensions) => { + + // Migrate enablement service to use identifiers + this._extensionEnablementService.migrateToIdentifiers(installedExtensions); + const disabledExtensions = [ ...getGloballyDisabledExtensions(this._extensionEnablementService, this._storageService, installedExtensions), ...this._extensionEnablementService.getWorkspaceDisabledExtensions() @@ -314,7 +318,7 @@ export class ExtensionService implements IExtensionService { if (disabledExtensions.length === 0) { return installedExtensions; } - return installedExtensions.filter(e => disabledExtensions.every(id => !areSameExtensions({ id }, e))); + return installedExtensions.filter(e => disabledExtensions.every(disabled => !areSameExtensions(disabled, e))); }).then((extensionDescriptions) => { this._registry = new ExtensionDescriptionRegistry(extensionDescriptions); diff --git a/src/vs/workbench/services/files/test/node/fileService.test.ts b/src/vs/workbench/services/files/test/node/fileService.test.ts index 6559d99dc1e..428474c05b7 100644 --- a/src/vs/workbench/services/files/test/node/fileService.test.ts +++ b/src/vs/workbench/services/files/test/node/fileService.test.ts @@ -19,13 +19,13 @@ import extfs = require('vs/base/node/extfs'); import encodingLib = require('vs/base/node/encoding'); import utils = require('vs/workbench/services/files/test/node/utils'); import { onError } from 'vs/base/test/common/utils'; -import { TestContextService, TestTextResourceConfigurationService } from 'vs/workbench/test/workbenchTestServices'; +import { TestContextService, TestTextResourceConfigurationService, getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; suite('FileService', () => { let service: FileService; - const parentDir = path.join(os.tmpdir(), 'vsctests', 'service'); + const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'fileservice'); let testDir: string; setup(function (done) { diff --git a/src/vs/workbench/services/group/common/groupService.ts b/src/vs/workbench/services/group/common/groupService.ts index 1cdeceef1ff..a04e26bbd89 100644 --- a/src/vs/workbench/services/group/common/groupService.ts +++ b/src/vs/workbench/services/group/common/groupService.ts @@ -56,9 +56,9 @@ export interface IEditorGroupService { onEditorOpenFail: Event; /** - * Emitted when a editors are moved to another position. + * Emitted when an entire editor group is moved to another position. */ - onEditorsMoved: Event; + onEditorGroupMoved: Event; /** * Emitted when the editor group orientation was changed. diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index 96778df112d..b00ba458b71 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -10,10 +10,10 @@ import errors = require('vs/base/common/errors'); import URI from 'vs/base/common/uri'; import { IEditor } from 'vs/editor/common/editorCommon'; import { IEditor as IBaseEditor, IEditorInput, ITextEditorOptions, IResourceInput, ITextEditorSelection, Position as GroupPosition } from 'vs/platform/editor/common/editor'; -import { Extensions as EditorExtensions, EditorInput, IEditorCloseEvent, IEditorGroup, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; +import { Extensions as EditorExtensions, EditorInput, IEditorCloseEvent, IEditorGroup, IEditorInputFactoryRegistry, toResource } from 'vs/workbench/common/editor'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { FileChangesEvent, IFileService, FileChangeType } from 'vs/platform/files/common/files'; +import { FileChangesEvent, IFileService, FileChangeType, FILES_EXCLUDE_CONFIG } from 'vs/platform/files/common/files'; import { Selection } from 'vs/editor/common/core/selection'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; @@ -21,12 +21,12 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; import { once, debounceEvent } from 'vs/base/common/event'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IWindowsService } from 'vs/platform/windows/common/windows'; import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; import { getExcludes, ISearchConfiguration } from 'vs/platform/search/common/search'; -import { parse, IExpression } from 'vs/base/common/glob'; +import { IExpression } from 'vs/base/common/glob'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ResourceGlobMatcher } from 'vs/workbench/common/resources'; @@ -211,7 +211,11 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic this.recentlyClosedFiles = []; this.loaded = false; this.registry = Registry.as(Extensions.Editors); - this.resourceFilter = instantiationService.createInstance(ResourceGlobMatcher, (root: URI) => this.getExcludes(root), (expression: IExpression) => parse(expression)); + this.resourceFilter = instantiationService.createInstance( + ResourceGlobMatcher, + (root: URI) => this.getExcludes(root), + (event: IConfigurationChangeEvent) => event.affectsConfiguration(FILES_EXCLUDE_CONFIG) || event.affectsConfiguration('search.exclude') + ); this.registerListeners(); } @@ -772,12 +776,25 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic }).filter(input => !!input); } - public getLastActiveWorkspaceRoot(): URI { + public getLastActiveWorkspaceRoot(schemeFilter?: string): URI { + + // No Folder: return early const folders = this.contextService.getWorkspace().folders; if (folders.length === 0) { return void 0; } + // Single Folder: return early + if (folders.length === 1) { + const resource = folders[0].uri; + if (!schemeFilter || resource.scheme === schemeFilter) { + return resource; + } + + return void 0; + } + + // Multiple folders: find the last active one const history = this.getHistory(); for (let i = 0; i < history.length; i++) { const input = history[i]; @@ -786,13 +803,44 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic } const resourceInput = input as IResourceInput; + if (schemeFilter && resourceInput.resource.scheme !== schemeFilter) { + continue; + } + const resourceWorkspace = this.contextService.getWorkspaceFolder(resourceInput.resource); if (resourceWorkspace) { return resourceWorkspace.uri; } } - // fallback to first workspace - return folders[0].uri; + // fallback to first workspace matching scheme filter if any + for (let i = 0; i < folders.length; i++) { + const resource = folders[i].uri; + if (!schemeFilter || resource.scheme === schemeFilter) { + return resource; + } + } + + return void 0; + } + + public getLastActiveFile(): URI { + const history = this.getHistory(); + for (let i = 0; i < history.length; i++) { + let resource: URI; + + const input = history[i]; + if (input instanceof EditorInput) { + resource = toResource(input, { filter: 'file' }); + } else { + resource = (input as IResourceInput).resource; + } + + if (resource && resource.scheme === 'file') { + return resource; + } + } + + return void 0; } } diff --git a/src/vs/workbench/services/history/common/history.ts b/src/vs/workbench/services/history/common/history.ts index 823f3f5f073..6760ab1c091 100644 --- a/src/vs/workbench/services/history/common/history.ts +++ b/src/vs/workbench/services/history/common/history.ts @@ -58,6 +58,13 @@ export interface IHistoryService { /** * Looking at the editor history, returns the workspace root of the last file that was * inside the workspace and part of the editor history. + * + * @param schemeFilter optional filter to restrict roots by scheme. */ - getLastActiveWorkspaceRoot(): URI; + getLastActiveWorkspaceRoot(schemeFilter?: string): URI; + + /** + * Looking at the editor history, returns the resource of the last file tht was opened. + */ + getLastActiveFile(): URI; } \ No newline at end of file diff --git a/src/vs/workbench/services/mode/common/workbenchModeService.ts b/src/vs/workbench/services/mode/common/workbenchModeService.ts index ad3c007b72c..62023d035bb 100644 --- a/src/vs/workbench/services/mode/common/workbenchModeService.ts +++ b/src/vs/workbench/services/mode/common/workbenchModeService.ts @@ -9,7 +9,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import * as paths from 'vs/base/common/paths'; import { TPromise } from 'vs/base/common/winjs.base'; import mime = require('vs/base/common/mime'); -import { IFilesConfiguration } from 'vs/platform/files/common/files'; +import { IFilesConfiguration, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IExtensionPointUser, ExtensionMessageCollector, IExtensionPoint, ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; @@ -124,7 +124,7 @@ export class WorkbenchModeServiceImpl extends ModeServiceImpl { }); this._configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('files.associations')) { + if (e.affectsConfiguration(FILES_ASSOCIATIONS_CONFIG)) { this.updateMime(); } }); diff --git a/src/vs/workbench/services/part/common/partService.ts b/src/vs/workbench/services/part/common/partService.ts index 4e41c5df51c..47a45649559 100644 --- a/src/vs/workbench/services/part/common/partService.ts +++ b/src/vs/workbench/services/part/common/partService.ts @@ -19,11 +19,8 @@ export enum Parts { export enum Position { LEFT, - RIGHT -} - -export interface ILayoutOptions { - toggleMaximizedPanel?: boolean; + RIGHT, + BOTTOM } export const IPartService = createDecorator('partService'); @@ -44,7 +41,7 @@ export interface IPartService { /** * Asks the part service to layout all parts. */ - layout(options?: ILayoutOptions): void; + layout(): void; /** * Asks the part service to if all parts have been created. @@ -91,22 +88,16 @@ export interface IPartService { */ setPanelHidden(hidden: boolean): TPromise; - /** - * Maximizes the panel height if the panel is not already maximized. - * Shrinks the panel to the default starting size if the panel is maximized. - */ - toggleMaximizedPanel(): void; - - /** - * Returns true if the panel is maximized. - */ - isPanelMaximized(): boolean; - /** * Gets the current side bar position. Note that the sidebar can be hidden too. */ getSideBarPosition(): Position; + /** + * Gets the current panel position. Note that the panel can be hidden too. + */ + getPanelPosition(): Position; + /** * Returns the identifier of the element that contains the workbench. */ diff --git a/src/vs/workbench/services/search/node/ripgrepFileSearch.ts b/src/vs/workbench/services/search/node/ripgrepFileSearch.ts index caba0ebd233..03ea2338f5c 100644 --- a/src/vs/workbench/services/search/node/ripgrepFileSearch.ts +++ b/src/vs/workbench/services/search/node/ripgrepFileSearch.ts @@ -42,7 +42,9 @@ function getRgArgs(config: IRawSearch, folderQuery: IFolderSearch, includePatter } // Follow symlinks - args.push('--follow'); + if (!config.ignoreSymlinks) { + args.push('--follow'); + } if (config.exists) { args.push('--quiet'); diff --git a/src/vs/workbench/services/search/node/ripgrepTextSearch.ts b/src/vs/workbench/services/search/node/ripgrepTextSearch.ts index da61448ee47..df668d90e57 100644 --- a/src/vs/workbench/services/search/node/ripgrepTextSearch.ts +++ b/src/vs/workbench/services/search/node/ripgrepTextSearch.ts @@ -493,7 +493,9 @@ function getRgArgs(config: IRawSearch): IRgGlobResult { } // Follow symlinks - args.push('--follow'); + if (!config.ignoreSymlinks) { + args.push('--follow'); + } // Set default encoding if only one folder is opened if (config.folderQueries.length === 1 && config.folderQueries[0].fileEncoding && config.folderQueries[0].fileEncoding !== 'utf8') { diff --git a/src/vs/workbench/services/search/node/search.ts b/src/vs/workbench/services/search/node/search.ts index 38c3be3415c..3775f5d9a6e 100644 --- a/src/vs/workbench/services/search/node/search.ts +++ b/src/vs/workbench/services/search/node/search.ts @@ -19,6 +19,7 @@ export interface IFolderSearch { export interface IRawSearch { folderQueries: IFolderSearch[]; + ignoreSymlinks?: boolean; extraFiles?: string[]; filePattern?: string; excludePattern?: IExpression; diff --git a/src/vs/workbench/services/search/node/searchService.ts b/src/vs/workbench/services/search/node/searchService.ts index 85c20bd1f10..09f4f9de0e9 100644 --- a/src/vs/workbench/services/search/node/searchService.ts +++ b/src/vs/workbench/services/search/node/searchService.ts @@ -270,7 +270,8 @@ export class DiskSearch implements ISearchResultProvider { sortByScore: query.sortByScore, cacheKey: query.cacheKey, useRipgrep: query.useRipgrep, - disregardIgnoreFiles: query.disregardIgnoreFiles + disregardIgnoreFiles: query.disregardIgnoreFiles, + ignoreSymlinks: query.ignoreSymlinks }; if (query.folderQueries) { diff --git a/src/vs/workbench/services/search/test/node/search.test.ts b/src/vs/workbench/services/search/test/node/search.test.ts index c2ce634c8d1..acc6ae56808 100644 --- a/src/vs/workbench/services/search/test/node/search.test.ts +++ b/src/vs/workbench/services/search/test/node/search.test.ts @@ -27,9 +27,12 @@ const MULTIROOT_QUERIES: IFolderSearch[] = [ { folder: MORE_FIXTURES } ]; +const testTimeout = 5000; + suite('FileSearchEngine', () => { test('Files: *.js', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.js' @@ -48,6 +51,7 @@ suite('FileSearchEngine', () => { }); test('Files: maxResults', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, maxResults: 1 @@ -66,6 +70,7 @@ suite('FileSearchEngine', () => { }); test('Files: maxResults without Ripgrep', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, maxResults: 1, @@ -85,6 +90,7 @@ suite('FileSearchEngine', () => { }); test('Files: exists', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, includePattern: { '**/file.txt': true }, @@ -105,6 +111,7 @@ suite('FileSearchEngine', () => { }); test('Files: not exists', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, includePattern: { '**/nofile.txt': true }, @@ -125,6 +132,7 @@ suite('FileSearchEngine', () => { }); test('Files: exists without Ripgrep', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, includePattern: { '**/file.txt': true }, @@ -146,6 +154,7 @@ suite('FileSearchEngine', () => { }); test('Files: not exists without Ripgrep', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, includePattern: { '**/nofile.txt': true }, @@ -167,6 +176,7 @@ suite('FileSearchEngine', () => { }); test('Files: examples/com*', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: normalize(join('examples', 'com*'), true) @@ -185,6 +195,7 @@ suite('FileSearchEngine', () => { }); test('Files: examples (fuzzy)', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: 'xl' @@ -203,6 +214,7 @@ suite('FileSearchEngine', () => { }); test('Files: multiroot', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: MULTIROOT_QUERIES, filePattern: 'file' @@ -221,6 +233,7 @@ suite('FileSearchEngine', () => { }); test('Files: multiroot with includePattern and maxResults', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: MULTIROOT_QUERIES, maxResults: 1, @@ -244,6 +257,7 @@ suite('FileSearchEngine', () => { }); test('Files: multiroot with includePattern and exists', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: MULTIROOT_QUERIES, exists: true, @@ -268,6 +282,7 @@ suite('FileSearchEngine', () => { }); test('Files: NPE (CamelCase)', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: 'NullPE' @@ -286,6 +301,7 @@ suite('FileSearchEngine', () => { }); test('Files: *.*', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.*' @@ -304,6 +320,7 @@ suite('FileSearchEngine', () => { }); test('Files: *.as', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.as' @@ -322,6 +339,7 @@ suite('FileSearchEngine', () => { }); test('Files: *.* without derived', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: 'site.*', @@ -344,6 +362,7 @@ suite('FileSearchEngine', () => { }); test('Files: *.* exclude folder without wildcard', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.*', @@ -363,6 +382,7 @@ suite('FileSearchEngine', () => { }); test('Files: *.* exclude folder with leading wildcard', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.*', @@ -382,6 +402,7 @@ suite('FileSearchEngine', () => { }); test('Files: *.* exclude folder with trailing wildcard', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.*', @@ -401,6 +422,7 @@ suite('FileSearchEngine', () => { }); test('Files: *.* exclude with unicode', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.*', @@ -420,6 +442,7 @@ suite('FileSearchEngine', () => { }); test('Files: multiroot with exclude', function (done: () => void) { + this.timeout(testTimeout); const folderQueries: IFolderSearch[] = [ { folder: EXAMPLES_FIXTURES, @@ -453,6 +476,7 @@ suite('FileSearchEngine', () => { }); test('Files: Unicode and Spaces', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '汉语' @@ -474,6 +498,7 @@ suite('FileSearchEngine', () => { }); test('Files: no results', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: 'nofilematch' @@ -492,6 +517,7 @@ suite('FileSearchEngine', () => { }); test('Files: absolute path to file ignores excludes', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: path.normalize(path.join(require.toUrl('./fixtures'), 'site.css')), @@ -514,6 +540,7 @@ suite('FileSearchEngine', () => { }); test('Files: relative path matched once', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: path.normalize(path.join('examples', 'company.js')) @@ -535,6 +562,7 @@ suite('FileSearchEngine', () => { }); test('Files: relative path to file ignores excludes', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: path.normalize(path.join('examples', 'company.js')), @@ -557,6 +585,7 @@ suite('FileSearchEngine', () => { }); test('Files: Include pattern, single files', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, includePattern: { @@ -580,6 +609,7 @@ suite('FileSearchEngine', () => { }); test('Files: extraFiles only', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: [], extraFiles: [ @@ -606,6 +636,7 @@ suite('FileSearchEngine', () => { }); test('Files: extraFiles only (with include)', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: [], extraFiles: [ @@ -633,6 +664,7 @@ suite('FileSearchEngine', () => { }); test('Files: extraFiles only (with exclude)', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: [], extraFiles: [ @@ -657,6 +689,7 @@ suite('FileSearchEngine', () => { }); test('Files: no dupes in nested folders', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: [ { folder: EXAMPLES_FIXTURES }, @@ -681,6 +714,7 @@ suite('FileSearchEngine', () => { suite('FileWalker', () => { test('Find: exclude subfolder', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; @@ -708,6 +742,7 @@ suite('FileWalker', () => { }); test('Find: folder excludes', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; @@ -734,6 +769,7 @@ suite('FileWalker', () => { }); test('Find: exclude multiple folders', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; @@ -764,6 +800,7 @@ suite('FileWalker', () => { }); test('Find: exclude folder path suffix', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; @@ -791,6 +828,7 @@ suite('FileWalker', () => { }); test('Find: exclude subfolder path suffix', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; @@ -818,6 +856,7 @@ suite('FileWalker', () => { }); test('Find: exclude folder path', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; @@ -845,6 +884,7 @@ suite('FileWalker', () => { }); test('Find: exclude combination of paths', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index 27a19245296..c185124e868 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -85,7 +85,7 @@ export abstract class TextFileService implements ITextFileService { const configuration = this.configurationService.getConfiguration(); this.currentFilesAssociationConfig = configuration && configuration.files && configuration.files.associations; - this.onConfigurationChange(configuration); + this.onFilesConfigurationChange(configuration); /* __GDPR__ "autoSave" : { @@ -123,8 +123,12 @@ export abstract class TextFileService implements ITextFileService { this.lifecycleService.onWillShutdown(event => event.veto(this.beforeShutdown(event.reason))); this.lifecycleService.onShutdown(this.dispose, this); - // Configuration changes - this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration()))); + // Files configuration changes + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('files')) { + this.onFilesConfigurationChange(this.configurationService.getConfiguration()); + } + })); } private beforeShutdown(reason: ShutdownReason): boolean | TPromise { @@ -316,7 +320,7 @@ export abstract class TextFileService implements ITextFileService { return this.backupFileService.discardAllWorkspaceBackups(); } - protected onConfigurationChange(configuration: IFilesConfiguration): void { + protected onFilesConfigurationChange(configuration: IFilesConfiguration): void { const wasAutoSaveEnabled = (this.getAutoSaveMode() !== AutoSaveMode.OFF); const autoSaveMode = (configuration && configuration.files && configuration.files.autoSave) || AutoSaveConfiguration.OFF; @@ -635,12 +639,14 @@ export abstract class TextFileService implements ITextFileService { } private suggestFileName(untitledResource: URI): string { - const root = this.historyService.getLastActiveWorkspaceRoot(); - if (root) { - return URI.file(paths.join(root.fsPath, this.untitledEditorService.suggestFileName(untitledResource))).fsPath; + const untitledFileName = this.untitledEditorService.suggestFileName(untitledResource); + + const lastActiveFile = this.historyService.getLastActiveFile(); + if (lastActiveFile) { + return URI.file(paths.join(paths.dirname(lastActiveFile.fsPath), untitledFileName)).fsPath; } - return this.untitledEditorService.suggestFileName(untitledResource); + return untitledFileName; } public revert(resource: URI, options?: IRevertOptions): TPromise { diff --git a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts index efff4d1b7f1..d5823de480d 100644 --- a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts @@ -138,13 +138,11 @@ export class TextFileService extends AbstractTextFileService { } public promptForPath(defaultPath?: string): string { - return this.windowService.showSaveDialog(this.getSaveDialogOptions(defaultPath ? paths.normalize(defaultPath, true) : void 0)); + return this.windowService.showSaveDialog(this.getSaveDialogOptions(defaultPath)); } private getSaveDialogOptions(defaultPath?: string): Electron.SaveDialogOptions { - const options: Electron.SaveDialogOptions = { - defaultPath: defaultPath - }; + const options: Electron.SaveDialogOptions = { defaultPath }; // Filters are only enabled on Windows where they work properly if (!isWindows) { @@ -154,7 +152,7 @@ export class TextFileService extends AbstractTextFileService { interface IFilter { name: string; extensions: string[]; } // Build the file filter by using our known languages - const ext: string = paths.extname(defaultPath); + const ext: string = defaultPath ? paths.extname(defaultPath) : void 0; let matchingFilter: IFilter; const filters: IFilter[] = this.modeService.getRegisteredLanguageNames().map(languageName => { const extensions = this.modeService.getExtensions(languageName); diff --git a/src/vs/workbench/services/textfile/test/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts index 38b5749c179..6416edee36b 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -104,7 +104,7 @@ suite('Files - TextFileService', () => { const service = accessor.textFileService; service.setConfirmResult(ConfirmResult.DONT_SAVE); - service.onConfigurationChange({ files: { hotExit: 'off' } }); + service.onFilesConfigurationChange({ files: { hotExit: 'off' } }); model.load().done(() => { model.textEditorModel.setValue('foo'); @@ -137,7 +137,7 @@ suite('Files - TextFileService', () => { const service = accessor.textFileService; service.setConfirmResult(ConfirmResult.SAVE); - service.onConfigurationChange({ files: { hotExit: 'off' } }); + service.onFilesConfigurationChange({ files: { hotExit: 'off' } }); model.load().done(() => { model.textEditorModel.setValue('foo'); @@ -377,7 +377,7 @@ suite('Files - TextFileService', () => { const service = accessor.textFileService; // Set hot exit config - service.onConfigurationChange({ files: { hotExit: setting } }); + service.onFilesConfigurationChange({ files: { hotExit: setting } }); // Set empty workspace if required if (!workspace) { accessor.contextService.setWorkspace(new Workspace('empty:1508317022751')); diff --git a/src/vs/workbench/services/workspace/common/workspaceEditing.ts b/src/vs/workbench/services/workspace/common/workspaceEditing.ts index 8f5e6cd634d..b5f3bbd56d4 100644 --- a/src/vs/workbench/services/workspace/common/workspaceEditing.ts +++ b/src/vs/workbench/services/workspace/common/workspaceEditing.ts @@ -7,6 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import URI from 'vs/base/common/uri'; export const IWorkspaceEditingService = createDecorator('workspaceEditingService'); @@ -14,6 +15,17 @@ export interface IWorkspaceEditingService { _serviceBrand: ServiceIdentifier; + /** + * Add folders to the existing workspace + */ + addFolders(folders: URI[]): TPromise; + addFolders(folders: { uri: URI, name?: string }[]): TPromise; + + /** + * Remove folders from the existing workspace + */ + removeFolders(folders: URI[]): TPromise; + /** * creates a new workspace with the provided folders and opens it. if path is provided * the workspace will be saved into that location. diff --git a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts index f5711bdfb21..3458f695cdd 100644 --- a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts @@ -7,26 +7,36 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import URI from 'vs/base/common/uri'; +import * as nls from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWindowService, IEnterWorkspaceResult } from 'vs/platform/windows/common/windows'; -import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; +import { IJSONEditingService, JSONEditingError, JSONEditingErrorCode } from 'vs/workbench/services/configuration/common/jsonEditing'; import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; import { migrateStorageToMultiRootWorkspace } from 'vs/platform/storage/common/migration'; -import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { StorageService } from 'vs/platform/storage/common/storageService'; import { ConfigurationScope, IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; +import { IChoiceService, Severity, IMessageService } from 'vs/platform/message/common/message'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { distinct } from 'vs/base/common/arrays'; +import { isLinux } from 'vs/base/common/platform'; +import { isEqual } from 'vs/base/common/resources'; +import { Action } from 'vs/base/common/actions'; +import product from 'vs/platform/node/product'; export class WorkspaceEditingService implements IWorkspaceEditingService { public _serviceBrand: any; + private static INFO_MESSAGE_KEY = 'enterWorkspace.message'; + constructor( @IJSONEditingService private jsonEditingService: IJSONEditingService, @IWorkspaceContextService private contextService: WorkspaceService, @@ -34,10 +44,60 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { @IWorkspaceConfigurationService private workspaceConfigurationService: IWorkspaceConfigurationService, @IStorageService private storageService: IStorageService, @IExtensionService private extensionService: IExtensionService, - @IBackupFileService private backupFileService: IBackupFileService + @IBackupFileService private backupFileService: IBackupFileService, + @IChoiceService private choiceService: IChoiceService, + @IMessageService private messageService: IMessageService, + @ICommandService private commandService: ICommandService ) { } + public addFolders(foldersToAdd: URI[]): TPromise; + public addFolders(foldersToAdd: { uri: URI, name?: string }[]): TPromise; + public addFolders(foldersToAdd: any[]): TPromise { + const state = this.contextService.getWorkbenchState(); + + // If we are in no-workspace or single-folder workspace, adding folders has to + // enter a workspace. + if (state !== WorkbenchState.WORKSPACE) { + const newWorkspaceFolders = distinct([ + ...this.contextService.getWorkspace().folders.map(folder => folder.uri), + ...foldersToAdd.map(folder => { + if (URI.isUri(folder)) { + return folder; + } + + return folder.uri; + }) + ].map(folder => folder.fsPath), folder => isLinux ? folder : folder.toLowerCase()); + + if (state === WorkbenchState.EMPTY && newWorkspaceFolders.length === 0 || state === WorkbenchState.FOLDER && newWorkspaceFolders.length === 1) { + return TPromise.as(void 0); // return if the operation is a no-op for the current state + } + + return this.createAndEnterWorkspace(newWorkspaceFolders); + } + + // Delegate addition of folders to workspace service otherwise + return this.contextService.addFolders(foldersToAdd) + .then(() => null, error => this.handleWorkspaceConfigurationEditingError(error)); + } + + public removeFolders(foldersToRemove: URI[]): TPromise { + + // If we are in single-folder state and the opened folder is to be removed, + // we close the workspace and enter the empty workspace state for the window. + if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { + const workspaceFolder = this.contextService.getWorkspace().folders[0]; + if (foldersToRemove.some(folder => isEqual(folder, workspaceFolder.uri, !isLinux))) { + return this.windowService.closeWorkspace(); + } + } + + // Delegate removal of folders to workspace service otherwise + return this.contextService.removeFolders(foldersToRemove) + .then(() => null, error => this.handleWorkspaceConfigurationEditingError(error)); + } + public createAndEnterWorkspace(folderPaths?: string[], path?: string): TPromise { return this.doEnterWorkspace(() => this.windowService.createAndEnterWorkspace(folderPaths, path)); } @@ -46,17 +106,55 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { return this.doEnterWorkspace(() => this.windowService.saveAndEnterWorkspace(path)); } + private handleWorkspaceConfigurationEditingError(error: JSONEditingError): TPromise { + switch (error.code) { + case JSONEditingErrorCode.ERROR_INVALID_FILE: + return this.onInvalidWorkspaceConfigurationFileError(); + case JSONEditingErrorCode.ERROR_FILE_DIRTY: + return this.onWorkspaceConfigurationFileDirtyError(); + } + this.messageService.show(Severity.Error, error.message); + return TPromise.as(void 0); + } + + private onInvalidWorkspaceConfigurationFileError(): TPromise { + const message = nls.localize('errorInvalidTaskConfiguration', "Unable to write into workspace configuration file. Please open the file to correct errors/warnings in it and try again."); + return this.askToOpenWorkspaceConfigurationFile(message); + } + + private onWorkspaceConfigurationFileDirtyError(): TPromise { + const message = nls.localize('errorWorkspaceConfigurationFileDirty', "Unable to write into workspace configuration file because the file is dirty. Please save it and try again."); + return this.askToOpenWorkspaceConfigurationFile(message); + } + + private askToOpenWorkspaceConfigurationFile(message: string): TPromise { + return this.choiceService.choose(Severity.Error, message, [nls.localize('openWorkspaceConfigurationFile', "Open Workspace Configuration File"), nls.localize('close', "Close")], 1) + .then(option => { + switch (option) { + case 0: + this.commandService.executeCommand('workbench.action.openWorkspaceConfigFile'); + break; + } + }); + } + private doEnterWorkspace(mainSidePromise: () => TPromise): TPromise { // Stop the extension host first to give extensions most time to shutdown this.extensionService.stopExtensionHost(); - return mainSidePromise().then(result => { - let enterWorkspacePromise: TPromise = TPromise.as(void 0); - if (result) { + const startExtensionHost = () => { + this.extensionService.startExtensionHost(); + }; - // Migrate storage and settings - enterWorkspacePromise = this.migrate(result.workspace).then(() => { + return mainSidePromise().then(result => { + + // Migrate storage and settings if we are to enter a workspace + if (result) { + return this.migrate(result.workspace).then(() => { + + // Show message to user (once) + this.informUserOnce(); // TODO@Ben remove me after a couple of releases // Reinitialize backup service const backupFileService = this.backupFileService as BackupFileService; // TODO@Ben ugly cast @@ -68,8 +166,58 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { }); } - // Finally bring the extension host back online - return enterWorkspacePromise.then(() => this.extensionService.startExtensionHost()); + return TPromise.as(void 0); + }).then(startExtensionHost, error => { + startExtensionHost(); // in any case start the extension host again! + + return TPromise.wrapError(error); + }); + } + + private informUserOnce(): void { + if (product.quality !== 'stable') { + return; // only for stable + } + + if (this.storageService.getBoolean(WorkspaceEditingService.INFO_MESSAGE_KEY)) { + return; // user does not want to see it again + } + + const okAction = new Action( + 'enterWorkspace.ok', + nls.localize('integrity.ok', "OK"), + null, + true, + () => TPromise.as(true) + ); + + const dontShowAgainAction = new Action( + 'enterWorkspace.dontShowAgain', + nls.localize('enterWorkspace.dontShowAgain', "Don't Show Again"), + null, + true, + () => { + this.storageService.store(WorkspaceEditingService.INFO_MESSAGE_KEY, true, StorageScope.GLOBAL); + + return TPromise.as(true); + } + ); + const moreInfoAction = new Action( + 'enterWorkspace.moreInfo', + nls.localize('enterWorkspace.moreInfo', "More Information"), + null, + true, + () => { + const uri = URI.parse(product.documentationUrl); + window.open(uri.toString(true)); + + return TPromise.as(true); + } + ); + + this.messageService.show(Severity.Info, { + message: nls.localize('enterWorkspace.prompt', "The opened workspace changed into a multi-root workspace."), + actions: [okAction, moreInfoAction, dontShowAgainAction] }); } diff --git a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts index ee457705998..73399a9bd37 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts @@ -212,6 +212,17 @@ suite('ExtHostWorkspace', function () { sub.dispose(); }); + test('`vscode.workspace.getWorkspaceFolder(file)` don\'t return workspace folder when file open from command line. #36221', function () { + let ws = new ExtHostWorkspace(new TestThreadService(), { + id: 'foo', name: 'Test', folders: [ + aWorkspaceFolderData(URI.file('c:/Users/marek/Desktop/vsc_test/'), 0) + ] + }); + + assert.ok(ws.getWorkspaceFolder(URI.file('c:/Users/marek/Desktop/vsc_test/a.txt'))); + assert.ok(ws.getWorkspaceFolder(URI.file('C:/Users/marek/Desktop/vsc_test/b.txt'))); + }); + function aWorkspaceFolderData(uri: URI, index: number, name: string = ''): IWorkspaceFolderData { return { uri, diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts index 7b783062321..7fd5cb0883e 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts @@ -49,7 +49,7 @@ suite('MainThreadDocumentsAndEditors', () => { }; const editorGroupService = new class extends mock() { onEditorsChanged = Event.None; - onEditorsMoved = Event.None; + onEditorGroupMoved = Event.None; }; documentAndEditor = new MainThreadDocumentsAndEditors( diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts index cef45043b6b..b470742526b 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts @@ -49,7 +49,7 @@ suite('MainThreadEditors', () => { }; const editorGroupService = new class extends mock() { onEditorsChanged = Event.None; - onEditorsMoved = Event.None; + onEditorGroupMoved = Event.None; }; const testThreadService = new TestThreadService(true); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 6c20a16bf44..6b3a39d6b6c 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -118,14 +118,6 @@ export class TestContextService implements IWorkspaceContextService { return this.workspace; } - public addFolders(foldersToAdd: URI[]): TPromise { - return TPromise.as(void 0); - } - - public removeFolders(foldersToRemove: URI[]): TPromise { - return TPromise.as(void 0); - } - public getWorkspaceFolder(resource: URI): IWorkspaceFolder { return this.isInsideWorkspace(resource) ? this.workspace.folders[0] : null; } @@ -234,8 +226,8 @@ export class TestTextFileService extends TextFileService { return this.confirmResult; } - public onConfigurationChange(configuration: any): void { - super.onConfigurationChange(configuration); + public onFilesConfigurationChange(configuration: any): void { + super.onFilesConfigurationChange(configuration); } protected cleanupBackupsBeforeShutdown(): TPromise { @@ -307,9 +299,13 @@ export class TestHistoryService implements IHistoryService { return []; } - public getLastActiveWorkspaceRoot(): URI { + public getLastActiveWorkspaceRoot(schemeFilter?: string): URI { return this.root; } + + public getLastActiveFile(): URI { + return void 0; + } } export class TestMessageService implements IMessageService { @@ -422,6 +418,10 @@ export class TestPartService implements IPartService { return 0; } + public getPanelPosition() { + return 0; + } + public addClass(clazz: string): void { } public removeClass(clazz: string): void { } public getWorkbenchElementId(): string { return ''; } @@ -514,7 +514,7 @@ export class TestEditorGroupService implements IEditorGroupService { return this._onEditorOpenFail.event; } - public get onEditorsMoved(): Event { + public get onEditorGroupMoved(): Event { return this._onEditorsMoved.event; } @@ -908,6 +908,10 @@ export class TestWindowService implements IWindowService { return TPromise.as(void 0); } + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise { + return TPromise.as(void 0); + } + reloadWindow(): TPromise { return TPromise.as(void 0); } @@ -924,10 +928,6 @@ export class TestWindowService implements IWindowService { return TPromise.as(void 0); } - openWorkspace(): TPromise { - return TPromise.as(void 0); - } - createAndEnterWorkspace(folderPaths?: string[], path?: string): TPromise { return TPromise.as(void 0); } @@ -1060,6 +1060,10 @@ export class TestWindowsService implements IWindowsService { return TPromise.as(void 0); } + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise { + return TPromise.as(void 0); + } + reloadWindow(windowId: number): TPromise { return TPromise.as(void 0); } @@ -1076,10 +1080,6 @@ export class TestWindowsService implements IWindowsService { return TPromise.as(void 0); } - openWorkspace(windowId: number): TPromise { - return TPromise.as(void 0); - } - createAndEnterWorkspace(windowId: number, folderPaths?: string[], path?: string): TPromise { return TPromise.as(void 0); } @@ -1246,4 +1246,8 @@ export class TestHashService implements IHashService { createSHA1(content: string): string { return content; } +} + +export function getRandomTestPath(tmpdir: string, ...segments: string[]): string { + return paths.join(tmpdir, ...segments, generateUuid()); } \ No newline at end of file diff --git a/test/mocha.opts b/test/mocha.opts index a89ace4fc9d..d6b09ce6e07 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -2,4 +2,3 @@ --ui tdd --timeout 10000 test/all.js -extensions/*/server/out/test/*.test.js