mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 13:00:58 +00:00
Merge branch 'master' into yarn
This commit is contained in:
commit
5e5ebf5c1f
|
@ -210,8 +210,7 @@ function uglifyWithCopyrights() {
|
|||
return stream.pipe(minify({
|
||||
output: {
|
||||
comments: preserveComments(f),
|
||||
// linux tfs build agent is crashing, does this help?§
|
||||
max_line_len: 3200000
|
||||
max_line_len: 1024
|
||||
}
|
||||
}));
|
||||
}));
|
||||
|
|
|
@ -285,8 +285,7 @@ function uglifyWithCopyrights(): NodeJS.ReadWriteStream {
|
|||
return stream.pipe(minify({
|
||||
output: {
|
||||
comments: preserveComments(<FileWithCopyright>f),
|
||||
// linux tfs build agent is crashing, does this help?§
|
||||
max_line_len: 3200000
|
||||
max_line_len: 1024
|
||||
}
|
||||
}));
|
||||
}));
|
||||
|
|
|
@ -11,47 +11,5 @@
|
|||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Microsoft/vscode/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/minimist": "1.2.0",
|
||||
"@types/mocha": "2.2.39",
|
||||
"@types/semver": "5.3.30",
|
||||
"@types/sinon": "1.16.34",
|
||||
"debounce": "^1.0.0",
|
||||
"eslint": "^3.4.0",
|
||||
"event-stream": "^3.1.7",
|
||||
"ghooks": "1.0.3",
|
||||
"glob": "^5.0.13",
|
||||
"gulp": "^3.8.9",
|
||||
"gulp-bom": "^1.0.0",
|
||||
"gulp-concat": "^2.6.0",
|
||||
"gulp-cssnano": "^2.1.0",
|
||||
"gulp-filter": "^3.0.0",
|
||||
"gulp-flatmap": "^1.0.0",
|
||||
"gulp-rename": "^1.2.0",
|
||||
"gulp-sourcemaps": "^1.11.0",
|
||||
"gulp-tsb": "^2.0.3",
|
||||
"gulp-tslint": "^7.0.1",
|
||||
"gulp-uglify": "^2.0.0",
|
||||
"gulp-util": "^3.0.6",
|
||||
"gulp-watch": "^4.3.9",
|
||||
"is": "^3.1.0",
|
||||
"istanbul": "^0.3.17",
|
||||
"jsdom-no-contextify": "^3.1.0",
|
||||
"lazy.js": "^0.4.2",
|
||||
"minimatch": "^2.0.10",
|
||||
"mocha": "^2.2.5",
|
||||
"object-assign": "^4.0.1",
|
||||
"pump": "^1.0.1",
|
||||
"remap-istanbul": "^0.6.4",
|
||||
"rimraf": "^2.2.8",
|
||||
"sinon": "^1.17.2",
|
||||
"source-map": "^0.4.4",
|
||||
"tslint": "^4.3.1",
|
||||
"typescript": "2.6.1",
|
||||
"typescript-formatter": "4.0.1",
|
||||
"underscore": "^1.8.2",
|
||||
"vinyl": "^0.4.5",
|
||||
"vscode-nls-dev": "^2.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3266,7 +3266,6 @@
|
|||
<string>(?x:
|
||||
(\!\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\])
|
||||
# Match the link text.
|
||||
([ ])? # Space not allowed
|
||||
(\() # Opening paren for url
|
||||
(<?)(\S+?)(>?) # The url
|
||||
[ \t]* # Optional whitespace
|
||||
|
@ -3578,7 +3577,6 @@
|
|||
<string>(?x:
|
||||
(\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\])
|
||||
# Match the link text.
|
||||
([ ])? # Space not allowed
|
||||
(\() # Opening paren for url
|
||||
(<?)(.*?)(>?) # The url
|
||||
[ \t]* # Optional whitespace
|
||||
|
|
|
@ -756,7 +756,6 @@
|
|||
<string>(?x:
|
||||
(\!\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\])
|
||||
# Match the link text.
|
||||
([ ])? # Space not allowed
|
||||
(\() # Opening paren for url
|
||||
(<?)(\S+?)(>?) # The url
|
||||
[ \t]* # Optional whitespace
|
||||
|
@ -1068,7 +1067,6 @@
|
|||
<string>(?x:
|
||||
(\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\])
|
||||
# Match the link text.
|
||||
([ ])? # Space not allowed
|
||||
(\() # Opening paren for url
|
||||
(<?)(.*?)(>?) # The url
|
||||
[ \t]* # Optional whitespace
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"contributes": {
|
||||
"languages": [{
|
||||
"id": "shellscript",
|
||||
"aliases": ["Shell Script (Bash)", "shellscript", "bash", "sh", "zsh"],
|
||||
"aliases": ["Shell Script", "shellscript", "bash", "sh", "zsh"],
|
||||
"extensions": [".sh", ".bash", ".bashrc", ".bash_aliases", ".bash_profile", ".bash_login", ".ebuild", ".install", ".profile", ".bash_logout", ".zsh", ".zshrc", ".zprofile", ".zlogin", ".zlogout", ".zshenv", ".zsh-theme"],
|
||||
"filenames": ["PKGBUILD"],
|
||||
"firstLine": "^#!.*\\b(bash|zsh|sh|tcsh).*|^#\\s*-\\*-[^*]*mode:\\s*shell-script[^*]*-\\*-",
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
"postinstall": "node build/npm/postinstall.js",
|
||||
"compile": "gulp compile --max_old_space_size=4096",
|
||||
"watch": "gulp watch --max_old_space_size=4096",
|
||||
"monaco-editor-setup": "node scripts/monaco-editor-setup.js",
|
||||
"monaco-editor-test": "mocha --only-monaco-editor",
|
||||
"precommit": "node build/gulpfile.hygiene.js",
|
||||
"gulp": "gulp --max_old_space_size=4096",
|
||||
|
|
|
@ -1,38 +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';
|
||||
|
||||
var fs = require('fs');
|
||||
var cp = require('child_process');
|
||||
var path = require('path');
|
||||
|
||||
var ROOT = path.join(__dirname, '..');
|
||||
var ROOT_NODE_MODULES_PATH = path.join(ROOT, 'node_modules');
|
||||
var EDITOR_ROOT = path.join(ROOT, 'build/monaco')
|
||||
var EDITOR_NODE_MODULES_PATH = path.join(EDITOR_ROOT, 'node_modules')
|
||||
|
||||
var cmd = `npm install`;
|
||||
cp.execSync(cmd, {
|
||||
cwd: EDITOR_ROOT,
|
||||
stdio:[0,1,2]
|
||||
});
|
||||
|
||||
if (!fs.existsSync(ROOT_NODE_MODULES_PATH)) {
|
||||
fs.mkdirSync(ROOT_NODE_MODULES_PATH);
|
||||
}
|
||||
|
||||
// Move deps over
|
||||
var modules = fs.readdirSync(EDITOR_NODE_MODULES_PATH);
|
||||
modules.forEach(function(module) {
|
||||
var src = path.join(EDITOR_NODE_MODULES_PATH, module);
|
||||
var dst = path.join(ROOT_NODE_MODULES_PATH, module);
|
||||
if (!fs.existsSync(dst)) {
|
||||
console.log('Moving ' + module + '...');
|
||||
fs.renameSync(src, dst);
|
||||
} else {
|
||||
console.log('Skipping moving ' + module + '.');
|
||||
}
|
||||
});
|
|
@ -13,9 +13,9 @@ fi
|
|||
cd $ROOT
|
||||
|
||||
# Integration Tests
|
||||
#./scripts/code.sh $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
||||
./scripts/code.sh $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
||||
./scripts/code.sh $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
||||
#./scripts/test-int-mocha.sh
|
||||
#./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
||||
./scripts/test-int-mocha.sh
|
||||
./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
|
||||
|
||||
rm -r $VSCODEUSERDATADIR
|
||||
|
|
|
@ -25,6 +25,7 @@ import { PartFingerprints, PartFingerprint, ViewPart } from 'vs/editor/browser/v
|
|||
import { Margin } from 'vs/editor/browser/viewParts/margin/margin';
|
||||
import { LineNumbersOverlay } from 'vs/editor/browser/viewParts/lineNumbers/lineNumbers';
|
||||
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
|
||||
import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
export interface ITextAreaHandlerHelper {
|
||||
visibleRangeForPositionRelativeToEditor(lineNumber: number, column: number): HorizontalRange;
|
||||
|
@ -481,7 +482,7 @@ export class TextAreaHandler extends ViewPart {
|
|||
if (this._context.configuration.editor.viewInfo.glyphMargin) {
|
||||
tac.setClassName('monaco-editor-background textAreaCover ' + Margin.CLASS_NAME);
|
||||
} else {
|
||||
if (this._context.configuration.editor.viewInfo.renderLineNumbers) {
|
||||
if (this._context.configuration.editor.viewInfo.renderLineNumbers !== RenderLineNumbersType.Off) {
|
||||
tac.setClassName('monaco-editor-background textAreaCover ' + LineNumbersOverlay.CLASS_NAME);
|
||||
} else {
|
||||
tac.setClassName('monaco-editor-background textAreaCover');
|
||||
|
|
|
@ -14,6 +14,7 @@ import { ViewContext } from 'vs/editor/common/view/viewContext';
|
|||
import { RenderingContext } from 'vs/editor/common/view/renderingContext';
|
||||
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
export class LineNumbersOverlay extends DynamicViewOverlay {
|
||||
|
||||
|
@ -22,12 +23,10 @@ export class LineNumbersOverlay extends DynamicViewOverlay {
|
|||
private _context: ViewContext;
|
||||
|
||||
private _lineHeight: number;
|
||||
private _renderLineNumbers: boolean;
|
||||
private _renderLineNumbers: RenderLineNumbersType;
|
||||
private _renderCustomLineNumbers: (lineNumber: number) => string;
|
||||
private _renderRelativeLineNumbers: boolean;
|
||||
private _lineNumbersLeft: number;
|
||||
private _lineNumbersWidth: number;
|
||||
|
||||
private _lastCursorModelPosition: Position;
|
||||
private _renderResult: string[];
|
||||
|
||||
|
@ -47,7 +46,6 @@ export class LineNumbersOverlay extends DynamicViewOverlay {
|
|||
this._lineHeight = config.lineHeight;
|
||||
this._renderLineNumbers = config.viewInfo.renderLineNumbers;
|
||||
this._renderCustomLineNumbers = config.viewInfo.renderCustomLineNumbers;
|
||||
this._renderRelativeLineNumbers = config.viewInfo.renderRelativeLineNumbers;
|
||||
this._lineNumbersLeft = config.layoutInfo.lineNumbersLeft;
|
||||
this._lineNumbersWidth = config.layoutInfo.lineNumbersWidth;
|
||||
}
|
||||
|
@ -69,7 +67,7 @@ export class LineNumbersOverlay extends DynamicViewOverlay {
|
|||
const primaryViewPosition = e.selections[0].getPosition();
|
||||
this._lastCursorModelPosition = this._context.model.coordinatesConverter.convertViewPositionToModelPosition(primaryViewPosition);
|
||||
|
||||
if (this._renderRelativeLineNumbers) {
|
||||
if (this._renderLineNumbers === RenderLineNumbersType.Relative || this._renderLineNumbers === RenderLineNumbersType.Interval) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -106,7 +104,7 @@ export class LineNumbersOverlay extends DynamicViewOverlay {
|
|||
return this._renderCustomLineNumbers(modelLineNumber);
|
||||
}
|
||||
|
||||
if (this._renderRelativeLineNumbers) {
|
||||
if (this._renderLineNumbers === RenderLineNumbersType.Relative) {
|
||||
let diff = Math.abs(this._lastCursorModelPosition.lineNumber - modelLineNumber);
|
||||
if (diff === 0) {
|
||||
return '<span class="relative-current-line-number">' + modelLineNumber + '</span>';
|
||||
|
@ -114,11 +112,21 @@ export class LineNumbersOverlay extends DynamicViewOverlay {
|
|||
return String(diff);
|
||||
}
|
||||
|
||||
if (this._renderLineNumbers === RenderLineNumbersType.Interval) {
|
||||
if (this._lastCursorModelPosition.lineNumber === modelLineNumber) {
|
||||
return String(modelLineNumber);
|
||||
}
|
||||
if (modelLineNumber % 10 === 0) {
|
||||
return String(modelLineNumber);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
return String(modelLineNumber);
|
||||
}
|
||||
|
||||
public prepareRender(ctx: RenderingContext): void {
|
||||
if (!this._renderLineNumbers) {
|
||||
if (this._renderLineNumbers === RenderLineNumbersType.Off) {
|
||||
this._renderResult = null;
|
||||
return;
|
||||
}
|
||||
|
@ -133,6 +141,7 @@ export class LineNumbersOverlay extends DynamicViewOverlay {
|
|||
let lineIndex = lineNumber - visibleStartLineNumber;
|
||||
|
||||
let renderLineNumber = this._getLineRenderLineNumber(lineNumber);
|
||||
|
||||
if (renderLineNumber) {
|
||||
output[lineIndex] = (
|
||||
common
|
||||
|
@ -166,4 +175,4 @@ registerThemingParticipant((theme, collector) => {
|
|||
if (lineNumbers) {
|
||||
collector.addRule(`.monaco-editor .line-numbers { color: ${lineNumbers}; }`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -203,9 +203,15 @@ const editorConfiguration: IConfigurationNode = {
|
|||
},
|
||||
'editor.lineNumbers': {
|
||||
'type': 'string',
|
||||
'enum': ['off', 'on', 'relative'],
|
||||
'enum': ['off', 'on', 'relative', 'interval'],
|
||||
'enumDescriptions': [
|
||||
nls.localize('lineNumbers.off', "Line numbers are not rendered."),
|
||||
nls.localize('lineNumbers.on', "Line numbers are rendered as absolute number."),
|
||||
nls.localize('lineNumbers.relative', "Line numbers are rendered as distance in lines to cursor position."),
|
||||
nls.localize('lineNumbers.interval', "Line numbers are rendered every 10 lines.")
|
||||
],
|
||||
'default': 'on',
|
||||
'description': nls.localize('lineNumbers', "Controls the display of line numbers. Possible values are 'on', 'off', and 'relative'. 'relative' shows the line count from the current cursor position.")
|
||||
'description': nls.localize('lineNumbers', "Controls the display of line numbers. Possible values are 'on', 'off', and 'relative'.")
|
||||
},
|
||||
'editor.rulers': {
|
||||
'type': 'array',
|
||||
|
|
|
@ -160,7 +160,7 @@ export interface IEditorOptions {
|
|||
* Otherwise, line numbers will not be rendered.
|
||||
* Defaults to true.
|
||||
*/
|
||||
lineNumbers?: 'on' | 'off' | 'relative' | ((lineNumber: number) => string);
|
||||
lineNumbers?: 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string);
|
||||
/**
|
||||
* Should the corresponding line be selected when clicking on the line number?
|
||||
* Defaults to true.
|
||||
|
@ -753,14 +753,21 @@ export interface EditorWrappingInfo {
|
|||
readonly wordWrapBreakObtrusiveCharacters: string;
|
||||
}
|
||||
|
||||
export const enum RenderLineNumbersType {
|
||||
Off = 0,
|
||||
On = 1,
|
||||
Relative = 2,
|
||||
Interval = 3,
|
||||
Custom = 4
|
||||
}
|
||||
|
||||
export interface InternalEditorViewOptions {
|
||||
readonly extraEditorClassName: string;
|
||||
readonly disableMonospaceOptimizations: boolean;
|
||||
readonly rulers: number[];
|
||||
readonly ariaLabel: string;
|
||||
readonly renderLineNumbers: boolean;
|
||||
readonly renderLineNumbers: RenderLineNumbersType;
|
||||
readonly renderCustomLineNumbers: (lineNumber: number) => string;
|
||||
readonly renderRelativeLineNumbers: boolean;
|
||||
readonly selectOnLineNumbers: boolean;
|
||||
readonly glyphMargin: boolean;
|
||||
readonly revealHorizontalRightPadding: number;
|
||||
|
@ -1029,7 +1036,6 @@ export class InternalEditorOptions {
|
|||
&& a.ariaLabel === b.ariaLabel
|
||||
&& a.renderLineNumbers === b.renderLineNumbers
|
||||
&& a.renderCustomLineNumbers === b.renderCustomLineNumbers
|
||||
&& a.renderRelativeLineNumbers === b.renderRelativeLineNumbers
|
||||
&& a.selectOnLineNumbers === b.selectOnLineNumbers
|
||||
&& a.glyphMargin === b.glyphMargin
|
||||
&& a.revealHorizontalRightPadding === b.revealHorizontalRightPadding
|
||||
|
@ -1558,9 +1564,8 @@ export class EditorOptionsValidator {
|
|||
rulers.sort();
|
||||
}
|
||||
|
||||
let renderLineNumbers: boolean = defaults.renderLineNumbers;
|
||||
let renderLineNumbers: RenderLineNumbersType = defaults.renderLineNumbers;
|
||||
let renderCustomLineNumbers: (lineNumber: number) => string = defaults.renderCustomLineNumbers;
|
||||
let renderRelativeLineNumbers: boolean = defaults.renderRelativeLineNumbers;
|
||||
|
||||
if (typeof opts.lineNumbers !== 'undefined') {
|
||||
let lineNumbers = opts.lineNumbers;
|
||||
|
@ -1573,21 +1578,16 @@ export class EditorOptionsValidator {
|
|||
}
|
||||
|
||||
if (typeof lineNumbers === 'function') {
|
||||
renderLineNumbers = true;
|
||||
renderLineNumbers = RenderLineNumbersType.Custom;
|
||||
renderCustomLineNumbers = lineNumbers;
|
||||
renderRelativeLineNumbers = false;
|
||||
} else if (lineNumbers === 'interval') {
|
||||
renderLineNumbers = RenderLineNumbersType.Interval;
|
||||
} else if (lineNumbers === 'relative') {
|
||||
renderLineNumbers = true;
|
||||
renderCustomLineNumbers = null;
|
||||
renderRelativeLineNumbers = true;
|
||||
renderLineNumbers = RenderLineNumbersType.Relative;
|
||||
} else if (lineNumbers === 'on') {
|
||||
renderLineNumbers = true;
|
||||
renderCustomLineNumbers = null;
|
||||
renderRelativeLineNumbers = false;
|
||||
renderLineNumbers = RenderLineNumbersType.On;
|
||||
} else {
|
||||
renderLineNumbers = false;
|
||||
renderCustomLineNumbers = null;
|
||||
renderRelativeLineNumbers = false;
|
||||
renderLineNumbers = RenderLineNumbersType.Off;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1627,7 +1627,6 @@ export class EditorOptionsValidator {
|
|||
ariaLabel: _string(opts.ariaLabel, defaults.ariaLabel),
|
||||
renderLineNumbers: renderLineNumbers,
|
||||
renderCustomLineNumbers: renderCustomLineNumbers,
|
||||
renderRelativeLineNumbers: renderRelativeLineNumbers,
|
||||
selectOnLineNumbers: _boolean(opts.selectOnLineNumbers, defaults.selectOnLineNumbers),
|
||||
glyphMargin: _boolean(opts.glyphMargin, defaults.glyphMargin),
|
||||
revealHorizontalRightPadding: _clampedInt(opts.revealHorizontalRightPadding, defaults.revealHorizontalRightPadding, 0, 1000),
|
||||
|
@ -1730,7 +1729,6 @@ export class InternalEditorOptionsFactory {
|
|||
ariaLabel: (accessibilityIsOff ? nls.localize('accessibilityOffAriaLabel', "The editor is not accessible at this time. Press Alt+F1 for options.") : opts.viewInfo.ariaLabel),
|
||||
renderLineNumbers: opts.viewInfo.renderLineNumbers,
|
||||
renderCustomLineNumbers: opts.viewInfo.renderCustomLineNumbers,
|
||||
renderRelativeLineNumbers: opts.viewInfo.renderRelativeLineNumbers,
|
||||
selectOnLineNumbers: opts.viewInfo.selectOnLineNumbers,
|
||||
glyphMargin: opts.viewInfo.glyphMargin,
|
||||
revealHorizontalRightPadding: opts.viewInfo.revealHorizontalRightPadding,
|
||||
|
@ -1822,7 +1820,7 @@ export class InternalEditorOptionsFactory {
|
|||
outerHeight: env.outerHeight,
|
||||
showGlyphMargin: opts.viewInfo.glyphMargin,
|
||||
lineHeight: env.fontInfo.lineHeight,
|
||||
showLineNumbers: opts.viewInfo.renderLineNumbers,
|
||||
showLineNumbers: (opts.viewInfo.renderLineNumbers !== RenderLineNumbersType.Off),
|
||||
lineNumbersMinChars: opts.lineNumbersMinChars,
|
||||
lineNumbersDigitCount: env.lineNumbersDigitCount,
|
||||
lineDecorationsWidth: lineDecorationsWidth,
|
||||
|
@ -2152,9 +2150,8 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = {
|
|||
disableMonospaceOptimizations: false,
|
||||
rulers: [],
|
||||
ariaLabel: nls.localize('editorViewAccessibleLabel', "Editor content"),
|
||||
renderLineNumbers: true,
|
||||
renderLineNumbers: RenderLineNumbersType.On,
|
||||
renderCustomLineNumbers: null,
|
||||
renderRelativeLineNumbers: false,
|
||||
selectOnLineNumbers: true,
|
||||
glyphMargin: true,
|
||||
revealHorizontalRightPadding: 30,
|
||||
|
|
|
@ -401,39 +401,46 @@ suite('Folding Model', () => {
|
|||
/* 10*/ ' return;',
|
||||
/* 11*/ ' }',
|
||||
/* 12*/ ' }',
|
||||
/* 13*/ '}'];
|
||||
/* 13*/ ' //#region',
|
||||
/* 14*/ ' const bar = 9;',
|
||||
/* 15*/ ' //#endregion',
|
||||
/* 16*/ '}'];
|
||||
|
||||
let textModel = Model.createFromString(lines.join('\n'));
|
||||
try {
|
||||
let foldingModel = new FoldingModel(textModel, new TestDecorationProvider(textModel));
|
||||
|
||||
let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ });
|
||||
let ranges = computeRanges(textModel, false, { start: /^\s*\/\/#region$/, end: /^\s*\/\/#endregion$/ });
|
||||
foldingModel.update(ranges);
|
||||
|
||||
let r1 = r(1, 2, false);
|
||||
let r2 = r(3, 12, false);
|
||||
let r2 = r(3, 15, false);
|
||||
let r3 = r(4, 11, false);
|
||||
let r4 = r(5, 6, false);
|
||||
let r5 = r(9, 10, false);
|
||||
assertRanges(foldingModel, [r1, r2, r3, r4, r5]);
|
||||
let r6 = r(13, 15, false);
|
||||
assertRanges(foldingModel, [r1, r2, r3, r4, r5, r6]);
|
||||
|
||||
setCollapseStateAtLevel(foldingModel, 1, true, []);
|
||||
assertFoldedRanges(foldingModel, [r1, r2], '1');
|
||||
|
||||
setCollapseStateAtLevel(foldingModel, 1, false, [5]);
|
||||
assertFoldedRanges(foldingModel, [r2], '1');
|
||||
assertFoldedRanges(foldingModel, [r2], '2');
|
||||
|
||||
setCollapseStateAtLevel(foldingModel, 1, false, [1]);
|
||||
assertFoldedRanges(foldingModel, [], '1');
|
||||
assertFoldedRanges(foldingModel, [], '3');
|
||||
|
||||
setCollapseStateAtLevel(foldingModel, 2, true, []);
|
||||
assertFoldedRanges(foldingModel, [r3], '1');
|
||||
assertFoldedRanges(foldingModel, [r3, r6], '4');
|
||||
|
||||
setCollapseStateAtLevel(foldingModel, 2, false, [5, 6]);
|
||||
assertFoldedRanges(foldingModel, [r3], '5');
|
||||
|
||||
setCollapseStateAtLevel(foldingModel, 3, true, [4, 9]);
|
||||
assertFoldedRanges(foldingModel, [r3, r4], '1');
|
||||
assertFoldedRanges(foldingModel, [r3, r4], '6');
|
||||
|
||||
setCollapseStateAtLevel(foldingModel, 3, false, [4, 9]);
|
||||
assertFoldedRanges(foldingModel, [r3], '1');
|
||||
assertFoldedRanges(foldingModel, [r3], '7');
|
||||
} finally {
|
||||
textModel.dispose();
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ class MoveLinesDownAction extends AbstractMoveLinesAction {
|
|||
}
|
||||
}
|
||||
|
||||
abstract class AbstractSortLinesAction extends EditorAction {
|
||||
export abstract class AbstractSortLinesAction extends EditorAction {
|
||||
private descending: boolean;
|
||||
|
||||
constructor(descending: boolean, opts: IActionOptions) {
|
||||
|
@ -149,16 +149,18 @@ abstract class AbstractSortLinesAction extends EditorAction {
|
|||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
const selections = editor.getSelections();
|
||||
|
||||
if (!SortLinesCommand.canRun(editor.getModel(), editor.getSelection(), this.descending)) {
|
||||
return;
|
||||
for (let i = 0, len = selections.length; i < len; i++) {
|
||||
const selection = selections[i];
|
||||
if (!SortLinesCommand.canRun(editor.getModel(), selection, this.descending)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var commands: ICommand[] = [];
|
||||
var selections = editor.getSelections();
|
||||
|
||||
for (var i = 0; i < selections.length; i++) {
|
||||
commands.push(new SortLinesCommand(selections[i], this.descending));
|
||||
let commands: ICommand[] = [];
|
||||
for (let i = 0, len = selections.length; i < len; i++) {
|
||||
commands[i] = new SortLinesCommand(selections[i], this.descending);
|
||||
}
|
||||
|
||||
editor.pushUndoStop();
|
||||
|
@ -167,7 +169,7 @@ abstract class AbstractSortLinesAction extends EditorAction {
|
|||
}
|
||||
}
|
||||
|
||||
class SortLinesAscendingAction extends AbstractSortLinesAction {
|
||||
export class SortLinesAscendingAction extends AbstractSortLinesAction {
|
||||
constructor() {
|
||||
super(false, {
|
||||
id: 'editor.action.sortLinesAscending',
|
||||
|
@ -178,7 +180,7 @@ class SortLinesAscendingAction extends AbstractSortLinesAction {
|
|||
}
|
||||
}
|
||||
|
||||
class SortLinesDescendingAction extends AbstractSortLinesAction {
|
||||
export class SortLinesDescendingAction extends AbstractSortLinesAction {
|
||||
constructor() {
|
||||
super(true, {
|
||||
id: 'editor.action.sortLinesDescending',
|
||||
|
|
|
@ -9,12 +9,129 @@ import { Selection } from 'vs/editor/common/core/selection';
|
|||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Handler, IModel, DefaultEndOfLine } from 'vs/editor/common/editorCommon';
|
||||
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
|
||||
import { DeleteAllLeftAction, JoinLinesAction, TransposeAction, UpperCaseAction, LowerCaseAction, DeleteAllRightAction, InsertLineBeforeAction, InsertLineAfterAction, IndentLinesAction } from 'vs/editor/contrib/linesOperations/linesOperations';
|
||||
import { DeleteAllLeftAction, JoinLinesAction, TransposeAction, UpperCaseAction, LowerCaseAction, DeleteAllRightAction, InsertLineBeforeAction, InsertLineAfterAction, IndentLinesAction, SortLinesAscendingAction, SortLinesDescendingAction } from 'vs/editor/contrib/linesOperations/linesOperations';
|
||||
import { Cursor } from 'vs/editor/common/controller/cursor';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
import { CoreEditingCommands } from 'vs/editor/browser/controller/coreCommands';
|
||||
|
||||
suite('Editor Contrib - Line Operations', () => {
|
||||
suite('SortLinesAscendingAction', () => {
|
||||
test('should sort selected lines in ascending order', function () {
|
||||
withTestCodeEditor(
|
||||
[
|
||||
'omicron',
|
||||
'beta',
|
||||
'alpha'
|
||||
], {}, (editor, cursor) => {
|
||||
let model = editor.getModel();
|
||||
let sortLinesAscendingAction = new SortLinesAscendingAction();
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 3, 5));
|
||||
sortLinesAscendingAction.run(null, editor);
|
||||
assert.deepEqual(model.getLinesContent(), [
|
||||
'alpha',
|
||||
'beta',
|
||||
'omicron'
|
||||
]);
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(1, 1, 3, 7).toString());
|
||||
});
|
||||
});
|
||||
|
||||
test('should sort multiple selections in ascending order', function () {
|
||||
withTestCodeEditor(
|
||||
[
|
||||
'omicron',
|
||||
'beta',
|
||||
'alpha',
|
||||
'',
|
||||
'omicron',
|
||||
'beta',
|
||||
'alpha'
|
||||
], {}, (editor, cursor) => {
|
||||
let model = editor.getModel();
|
||||
let sortLinesAscendingAction = new SortLinesAscendingAction();
|
||||
|
||||
editor.setSelections([new Selection(1, 1, 3, 5), new Selection(5, 1, 7, 5)]);
|
||||
sortLinesAscendingAction.run(null, editor);
|
||||
assert.deepEqual(model.getLinesContent(), [
|
||||
'alpha',
|
||||
'beta',
|
||||
'omicron',
|
||||
'',
|
||||
'alpha',
|
||||
'beta',
|
||||
'omicron'
|
||||
]);
|
||||
let expectedSelections = [
|
||||
new Selection(1, 1, 3, 7),
|
||||
new Selection(5, 1, 7, 7)
|
||||
];
|
||||
editor.getSelections().forEach((actualSelection, index) => {
|
||||
assert.deepEqual(actualSelection.toString(), expectedSelections[index].toString());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('SortLinesDescendingAction', () => {
|
||||
test('should sort selected lines in descending order', function () {
|
||||
withTestCodeEditor(
|
||||
[
|
||||
'alpha',
|
||||
'beta',
|
||||
'omicron'
|
||||
], {}, (editor, cursor) => {
|
||||
let model = editor.getModel();
|
||||
let sortLinesDescendingAction = new SortLinesDescendingAction();
|
||||
|
||||
editor.setSelection(new Selection(1, 1, 3, 7));
|
||||
sortLinesDescendingAction.run(null, editor);
|
||||
assert.deepEqual(model.getLinesContent(), [
|
||||
'omicron',
|
||||
'beta',
|
||||
'alpha'
|
||||
]);
|
||||
assert.deepEqual(editor.getSelection().toString(), new Selection(1, 1, 3, 5).toString());
|
||||
});
|
||||
});
|
||||
|
||||
test('should sort multiple selections in descending order', function () {
|
||||
withTestCodeEditor(
|
||||
[
|
||||
'alpha',
|
||||
'beta',
|
||||
'omicron',
|
||||
'',
|
||||
'alpha',
|
||||
'beta',
|
||||
'omicron'
|
||||
], {}, (editor, cursor) => {
|
||||
let model = editor.getModel();
|
||||
let sortLinesDescendingAction = new SortLinesDescendingAction();
|
||||
|
||||
editor.setSelections([new Selection(1, 1, 3, 7), new Selection(5, 1, 7, 7)]);
|
||||
sortLinesDescendingAction.run(null, editor);
|
||||
assert.deepEqual(model.getLinesContent(), [
|
||||
'omicron',
|
||||
'beta',
|
||||
'alpha',
|
||||
'',
|
||||
'omicron',
|
||||
'beta',
|
||||
'alpha'
|
||||
]);
|
||||
let expectedSelections = [
|
||||
new Selection(1, 1, 3, 5),
|
||||
new Selection(5, 1, 7, 5)
|
||||
];
|
||||
editor.getSelections().forEach((actualSelection, index) => {
|
||||
assert.deepEqual(actualSelection.toString(), expectedSelections[index].toString());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
suite('DeleteAllLeftAction', () => {
|
||||
test('should delete to the left of the cursor', function () {
|
||||
withTestCodeEditor(
|
||||
|
|
|
@ -123,7 +123,7 @@ suite('Editor Contrib - Sort Lines Command', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('sorting first 4 lines desscending', function () {
|
||||
test('sorting first 4 lines descending', function () {
|
||||
testSortLinesDescendingCommand(
|
||||
[
|
||||
'first',
|
||||
|
|
|
@ -338,6 +338,21 @@ enum ScrollType {
|
|||
Immediate = 1,
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* --------------------------------------------
|
||||
* This is repeated here so it can be exported
|
||||
* because TS inlines const enums
|
||||
* --------------------------------------------
|
||||
*/
|
||||
enum RenderLineNumbersType {
|
||||
Off = 0,
|
||||
On = 1,
|
||||
Relative = 2,
|
||||
Interval = 3,
|
||||
Custom = 4
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -384,6 +399,7 @@ export function createMonacoEditorAPI(): typeof monaco.editor {
|
|||
OverlayWidgetPositionPreference: OverlayWidgetPositionPreference,
|
||||
RenderMinimap: editorOptions.RenderMinimap,
|
||||
ScrollType: <any>ScrollType,
|
||||
RenderLineNumbersType: <any>RenderLineNumbersType,
|
||||
|
||||
// classes
|
||||
InternalEditorOptions: <any>editorOptions.InternalEditorOptions,
|
||||
|
|
13
src/vs/monaco.d.ts
vendored
13
src/vs/monaco.d.ts
vendored
|
@ -2498,7 +2498,7 @@ declare module monaco.editor {
|
|||
* Otherwise, line numbers will not be rendered.
|
||||
* Defaults to true.
|
||||
*/
|
||||
lineNumbers?: 'on' | 'off' | 'relative' | ((lineNumber: number) => string);
|
||||
lineNumbers?: 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string);
|
||||
/**
|
||||
* Should the corresponding line be selected when clicking on the line number?
|
||||
* Defaults to true.
|
||||
|
@ -3024,14 +3024,21 @@ declare module monaco.editor {
|
|||
readonly wordWrapBreakObtrusiveCharacters: string;
|
||||
}
|
||||
|
||||
export const enum RenderLineNumbersType {
|
||||
Off = 0,
|
||||
On = 1,
|
||||
Relative = 2,
|
||||
Interval = 3,
|
||||
Custom = 4,
|
||||
}
|
||||
|
||||
export interface InternalEditorViewOptions {
|
||||
readonly extraEditorClassName: string;
|
||||
readonly disableMonospaceOptimizations: boolean;
|
||||
readonly rulers: number[];
|
||||
readonly ariaLabel: string;
|
||||
readonly renderLineNumbers: boolean;
|
||||
readonly renderLineNumbers: RenderLineNumbersType;
|
||||
readonly renderCustomLineNumbers: (lineNumber: number) => string;
|
||||
readonly renderRelativeLineNumbers: boolean;
|
||||
readonly selectOnLineNumbers: boolean;
|
||||
readonly glyphMargin: boolean;
|
||||
readonly revealHorizontalRightPadding: number;
|
||||
|
|
|
@ -20,6 +20,7 @@ import { IWorkspaceIdentifier, IWorkspacesMainService, getWorkspaceLabel, ISingl
|
|||
import { IHistoryMainService, IRecentlyOpened } from 'vs/platform/history/common/history';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { isEqual } from 'vs/base/common/paths';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
|
||||
export interface ILegacyRecentlyOpened extends IRecentlyOpened {
|
||||
folders: string[]; // TODO@Ben migration
|
||||
|
@ -28,6 +29,7 @@ export interface ILegacyRecentlyOpened extends IRecentlyOpened {
|
|||
export class HistoryMainService implements IHistoryMainService {
|
||||
|
||||
private static MAX_TOTAL_RECENT_ENTRIES = 100;
|
||||
private static MAX_MACOS_DOCK_RECENT_ENTRIES = 10;
|
||||
|
||||
private static recentlyOpenedStorageKey = 'openedPathsList';
|
||||
|
||||
|
@ -36,12 +38,16 @@ export class HistoryMainService implements IHistoryMainService {
|
|||
private _onRecentlyOpenedChange = new Emitter<void>();
|
||||
onRecentlyOpenedChange: CommonEvent<void> = this._onRecentlyOpenedChange.event;
|
||||
|
||||
private macOSRecentDocumentsUpdater: RunOnceScheduler;
|
||||
|
||||
constructor(
|
||||
@IStorageService private storageService: IStorageService,
|
||||
@ILogService private logService: ILogService,
|
||||
@IWorkspacesMainService private workspacesService: IWorkspacesMainService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
) {
|
||||
this.macOSRecentDocumentsUpdater = new RunOnceScheduler(() => this.updateMacOSRecentDocuments(), 800);
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
|
@ -69,10 +75,8 @@ export class HistoryMainService implements IHistoryMainService {
|
|||
mru.workspaces.unshift(workspace);
|
||||
mru.workspaces = arrays.distinct(mru.workspaces, workspace => this.distinctFn(workspace));
|
||||
|
||||
// Add to recent documents (macOS only, Windows can show workspaces separately)
|
||||
if (isMacintosh) {
|
||||
app.addRecentDocument(isSingleFolderWorkspaceIdentifier(workspace) ? workspace : workspace.configPath);
|
||||
}
|
||||
// We do not add to recent documents here because on Windows we do this from a custom
|
||||
// JumpList and on macOS we fill the recent documents in one go from all our data later.
|
||||
});
|
||||
|
||||
// Files
|
||||
|
@ -80,8 +84,8 @@ export class HistoryMainService implements IHistoryMainService {
|
|||
mru.files.unshift(path);
|
||||
mru.files = arrays.distinct(mru.files, file => this.distinctFn(file));
|
||||
|
||||
// Add to recent documents (Windows/macOS only)
|
||||
if (isMacintosh || isWindows) {
|
||||
// Add to recent documents (Windows only, macOS later)
|
||||
if (isWindows) {
|
||||
app.addRecentDocument(path);
|
||||
}
|
||||
});
|
||||
|
@ -92,6 +96,11 @@ export class HistoryMainService implements IHistoryMainService {
|
|||
|
||||
this.saveRecentlyOpened(mru);
|
||||
this._onRecentlyOpenedChange.fire();
|
||||
|
||||
// Schedule update to recent documents on macOS dock
|
||||
if (isMacintosh) {
|
||||
this.macOSRecentDocumentsUpdater.schedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,6 +128,41 @@ export class HistoryMainService implements IHistoryMainService {
|
|||
if (update) {
|
||||
this.saveRecentlyOpened(mru);
|
||||
this._onRecentlyOpenedChange.fire();
|
||||
|
||||
// Schedule update to recent documents on macOS dock
|
||||
if (isMacintosh) {
|
||||
this.macOSRecentDocumentsUpdater.schedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private updateMacOSRecentDocuments(): void {
|
||||
if (!isMacintosh) {
|
||||
return;
|
||||
}
|
||||
|
||||
// macOS recent documents in the dock are behaving strangely. the entries seem to get
|
||||
// out of sync quickly over time. the attempted fix is to always set the list fresh
|
||||
// from our MRU history data. So we clear the documents first and then set the documents
|
||||
// again.
|
||||
|
||||
app.clearRecentDocuments();
|
||||
|
||||
const mru = this.getRecentlyOpened();
|
||||
|
||||
let maxEntries = HistoryMainService.MAX_MACOS_DOCK_RECENT_ENTRIES;
|
||||
|
||||
// Take up to maxEntries/2 workspaces
|
||||
for (let i = 0; i < mru.workspaces.length && i < HistoryMainService.MAX_MACOS_DOCK_RECENT_ENTRIES / 2; i++) {
|
||||
const workspace = mru.workspaces[i];
|
||||
app.addRecentDocument(isSingleFolderWorkspaceIdentifier(workspace) ? workspace : workspace.configPath);
|
||||
maxEntries--;
|
||||
}
|
||||
|
||||
// Take up to maxEntries files
|
||||
for (let i = 0; i < mru.files.length && i < maxEntries; i++) {
|
||||
const file = mru.files[i];
|
||||
app.addRecentDocument(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import { Range, IRange } from 'vs/editor/common/core/range';
|
|||
import { Selection, ISelection } from 'vs/editor/common/core/selection';
|
||||
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
|
||||
import { EndOfLine, TextEditorLineNumbersStyle } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { TextEditorCursorStyle, cursorStyleToString } from 'vs/editor/common/config/editorOptions';
|
||||
import { TextEditorCursorStyle, cursorStyleToString, RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
|
||||
import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { IResolvedTextEditorConfiguration, ISelectionChangeEvent, ITextEditorConfigurationUpdate, TextEditorRevealType, IApplyEditsOptions, IUndoStopOptions } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
|
@ -290,12 +290,16 @@ export class MainThreadTextEditor {
|
|||
let codeEditorOpts = codeEditor.getConfiguration();
|
||||
cursorStyle = codeEditorOpts.viewInfo.cursorStyle;
|
||||
|
||||
if (codeEditorOpts.viewInfo.renderRelativeLineNumbers) {
|
||||
lineNumbers = TextEditorLineNumbersStyle.Relative;
|
||||
} else if (codeEditorOpts.viewInfo.renderLineNumbers) {
|
||||
lineNumbers = TextEditorLineNumbersStyle.On;
|
||||
} else {
|
||||
lineNumbers = TextEditorLineNumbersStyle.Off;
|
||||
switch (codeEditorOpts.viewInfo.renderLineNumbers) {
|
||||
case RenderLineNumbersType.Off:
|
||||
lineNumbers = TextEditorLineNumbersStyle.Off;
|
||||
break;
|
||||
case RenderLineNumbersType.Relative:
|
||||
lineNumbers = TextEditorLineNumbersStyle.Relative;
|
||||
break;
|
||||
default:
|
||||
lineNumbers = TextEditorLineNumbersStyle.On;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ import { RunOnceScheduler } from 'vs/base/common/async';
|
|||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ConfigurationTarget, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
|
||||
import { LifecyclePhase, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces';
|
||||
|
||||
const TextInputActions: IAction[] = [
|
||||
new Action('undo', nls.localize('undo', "Undo"), null, true, () => document.execCommand('undo') && TPromise.as(true)),
|
||||
|
@ -68,6 +69,9 @@ export class ElectronWindow extends Themable {
|
|||
|
||||
private previousConfiguredZoomLevel: number;
|
||||
|
||||
private addFoldersScheduler: RunOnceScheduler;
|
||||
private pendingFoldersToAdd: IAddFoldersRequest[];
|
||||
|
||||
constructor(
|
||||
shellContainer: HTMLElement,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
|
@ -96,6 +100,10 @@ export class ElectronWindow extends Themable {
|
|||
this.touchBarUpdater = new RunOnceScheduler(() => this.doSetupTouchbar(), 300);
|
||||
this.toUnbind.push(this.touchBarUpdater);
|
||||
|
||||
this.pendingFoldersToAdd = [];
|
||||
this.addFoldersScheduler = new RunOnceScheduler(() => this.doAddFolders(), 100);
|
||||
this.toUnbind.push(this.addFoldersScheduler);
|
||||
|
||||
this.registerListeners();
|
||||
this.create();
|
||||
}
|
||||
|
@ -180,7 +188,7 @@ export class ElectronWindow extends Themable {
|
|||
ipc.on('vscode:openFiles', (_event: any, request: IOpenFileRequest) => this.onOpenFiles(request));
|
||||
|
||||
// Support addFolders event if we have a workspace opened
|
||||
ipc.on('vscode:addFolders', (_event: any, request: IAddFoldersRequest) => this.onAddFolders(request));
|
||||
ipc.on('vscode:addFolders', (_event: any, request: IAddFoldersRequest) => this.onAddFoldersRequest(request));
|
||||
|
||||
// Message support
|
||||
ipc.on('vscode:showInfoMessage', (_event: any, message: string) => {
|
||||
|
@ -234,8 +242,13 @@ export class ElectronWindow extends Themable {
|
|||
browser.setAccessibilitySupport(accessibilitySupportEnabled ? platform.AccessibilitySupport.Enabled : platform.AccessibilitySupport.Disabled);
|
||||
});
|
||||
|
||||
// Configuration changes
|
||||
this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onDidUpdateConfiguration(e)));
|
||||
// Zoom level changes
|
||||
this.updateWindowZoomLevel();
|
||||
this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('window.zoomLevel')) {
|
||||
this.updateWindowZoomLevel();
|
||||
}
|
||||
}));
|
||||
|
||||
// Context menu support in input/textarea
|
||||
window.document.addEventListener('contextmenu', e => this.onContextMenu(e));
|
||||
|
@ -256,10 +269,7 @@ export class ElectronWindow extends Themable {
|
|||
}
|
||||
}
|
||||
|
||||
private onDidUpdateConfiguration(event: IConfigurationChangeEvent): void {
|
||||
if (!event.affectsConfiguration('window.zoomLevel')) {
|
||||
return;
|
||||
}
|
||||
private updateWindowZoomLevel(): void {
|
||||
|
||||
const windowConfig: IWindowsConfiguration = this.configurationService.getValue<IWindowsConfiguration>();
|
||||
|
||||
|
@ -394,8 +404,25 @@ export class ElectronWindow extends Themable {
|
|||
});
|
||||
}
|
||||
|
||||
private onAddFolders(request: IAddFoldersRequest): void {
|
||||
const foldersToAdd = request.foldersToAdd.map(folderToAdd => ({ uri: URI.file(folderToAdd.filePath) }));
|
||||
private onAddFoldersRequest(request: IAddFoldersRequest): void {
|
||||
|
||||
// Buffer all pending requests
|
||||
this.pendingFoldersToAdd.push(request);
|
||||
|
||||
// Delay the adding of folders a bit to buffer in case more requests are coming
|
||||
if (!this.addFoldersScheduler.isScheduled()) {
|
||||
this.addFoldersScheduler.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
private doAddFolders(): void {
|
||||
const foldersToAdd: IWorkspaceFolderCreationData[] = [];
|
||||
|
||||
this.pendingFoldersToAdd.forEach(request => {
|
||||
foldersToAdd.push(...request.foldersToAdd.map(folderToAdd => ({ uri: URI.file(folderToAdd.filePath) })));
|
||||
});
|
||||
|
||||
this.pendingFoldersToAdd = [];
|
||||
|
||||
this.workspaceEditingService.addFolders(foldersToAdd).done(null, errors.onUnexpectedError);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ import { Widget } from 'vs/base/browser/ui/widget';
|
|||
import { IPreferencesRenderer, DefaultSettingsRenderer, UserSettingsRenderer, WorkspaceSettingsRenderer, FolderSettingsRenderer } from 'vs/workbench/parts/preferences/browser/preferencesRenderers';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { getCodeEditor } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||
import { FoldingController } from 'vs/editor/contrib/folding/folding';
|
||||
import { FindController } from 'vs/editor/contrib/find/findController';
|
||||
|
@ -697,77 +696,6 @@ class SideBySidePreferencesWidget extends Widget {
|
|||
}
|
||||
}
|
||||
|
||||
export class EditableSettingsEditor extends BaseTextEditor {
|
||||
|
||||
public static ID: string = 'workbench.editor.settingsEditor';
|
||||
|
||||
private modelDisposables: IDisposable[] = [];
|
||||
private saveDelayer: Delayer<void>;
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@ITextResourceConfigurationService configurationService: ITextResourceConfigurationService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IPreferencesService private preferencesService: IPreferencesService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IEditorGroupService editorGroupService: IEditorGroupService
|
||||
) {
|
||||
super(EditableSettingsEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorGroupService);
|
||||
this._register({ dispose: () => dispose(this.modelDisposables) });
|
||||
this.saveDelayer = new Delayer<void>(1000);
|
||||
}
|
||||
|
||||
protected createEditor(parent: Builder): void {
|
||||
super.createEditor(parent);
|
||||
|
||||
const codeEditor = getCodeEditor(this);
|
||||
if (codeEditor) {
|
||||
this._register(codeEditor.onDidChangeModel(() => this.onDidModelChange()));
|
||||
}
|
||||
}
|
||||
|
||||
protected getAriaLabel(): string {
|
||||
const input = this.input;
|
||||
const inputName = input && input.getName();
|
||||
|
||||
let ariaLabel: string;
|
||||
if (inputName) {
|
||||
ariaLabel = nls.localize('fileEditorWithInputAriaLabel', "{0}. Text file editor.", inputName);
|
||||
} else {
|
||||
ariaLabel = nls.localize('fileEditorAriaLabel', "Text file editor.");
|
||||
}
|
||||
|
||||
return ariaLabel;
|
||||
}
|
||||
|
||||
setInput(input: EditorInput, options: EditorOptions): TPromise<void> {
|
||||
return super.setInput(input, options)
|
||||
.then(() => this.input.resolve()
|
||||
.then(editorModel => editorModel.load())
|
||||
.then(editorModel => this.getControl().setModel((<ResourceEditorModel>editorModel).textEditorModel)));
|
||||
}
|
||||
|
||||
clearInput(): void {
|
||||
this.modelDisposables = dispose(this.modelDisposables);
|
||||
super.clearInput();
|
||||
}
|
||||
|
||||
private onDidModelChange(): void {
|
||||
this.modelDisposables = dispose(this.modelDisposables);
|
||||
const model = getCodeEditor(this).getModel();
|
||||
if (model) {
|
||||
this.preferencesService.createPreferencesEditorModel(model.uri)
|
||||
.then(preferencesEditorModel => {
|
||||
const settingsEditorModel = <SettingsEditorModel>preferencesEditorModel;
|
||||
this.modelDisposables.push(settingsEditorModel);
|
||||
this.modelDisposables.push(model.onDidChangeContent(() => this.saveDelayer.trigger(() => settingsEditorModel.save())));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class DefaultPreferencesEditor extends BaseTextEditor {
|
||||
|
||||
public static ID: string = 'workbench.editor.defaultPreferences';
|
||||
|
|
|
@ -270,14 +270,12 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR
|
|||
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));
|
||||
const parenthesisHidingRenderer = this._register(instantiationService.createInstance(StaticContentHidingRenderer, editor, preferencesModel));
|
||||
this.hiddenAreasRenderer = this._register(instantiationService.createInstance(HiddenAreasRenderer, editor, [this.settingsGroupTitleRenderer, this.filteredMatchesRenderer, parenthesisHidingRenderer]));
|
||||
|
||||
this._register(this.editSettingActionRenderer.onUpdateSetting(e => this._onUpdatePreference.fire(e)));
|
||||
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._register(preferencesModel.onDidChangeGroups(() => this.render()));
|
||||
|
||||
this.onTriggeredFuzzy = this.settingsHeaderRenderer.onClick;
|
||||
}
|
||||
|
@ -295,7 +293,6 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR
|
|||
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(0);
|
||||
this.hiddenAreasRenderer.render();
|
||||
|
@ -379,7 +376,7 @@ export interface HiddenAreasProvider {
|
|||
|
||||
export class StaticContentHidingRenderer extends Disposable implements HiddenAreasProvider {
|
||||
|
||||
constructor(private editor: ICodeEditor, private settingsGroups: ISettingsGroup[]
|
||||
constructor(private editor: ICodeEditor, private settingsEditorModel: ISettingsEditorModel
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
@ -388,7 +385,8 @@ export class StaticContentHidingRenderer extends Disposable implements HiddenAre
|
|||
const model = this.editor.getModel();
|
||||
|
||||
// Hide extra chars for "search results" and "commonly used" groups
|
||||
const lastGroup = tail(this.settingsGroups);
|
||||
const settingsGroups = this.settingsEditorModel.settingsGroups;
|
||||
const lastGroup = tail(settingsGroups);
|
||||
return [
|
||||
{
|
||||
startLineNumber: 1,
|
||||
|
@ -397,10 +395,10 @@ export class StaticContentHidingRenderer extends Disposable implements HiddenAre
|
|||
endColumn: model.getLineMaxColumn(2)
|
||||
},
|
||||
{
|
||||
startLineNumber: this.settingsGroups[0].range.endLineNumber + 1,
|
||||
startColumn: model.getLineMinColumn(this.settingsGroups[0].range.endLineNumber + 1),
|
||||
endLineNumber: this.settingsGroups[0].range.endLineNumber + 4,
|
||||
endColumn: model.getLineMaxColumn(this.settingsGroups[0].range.endLineNumber + 4)
|
||||
startLineNumber: settingsGroups[0].range.endLineNumber + 1,
|
||||
startColumn: model.getLineMinColumn(settingsGroups[0].range.endLineNumber + 1),
|
||||
endLineNumber: settingsGroups[0].range.endLineNumber + 4,
|
||||
endColumn: model.getLineMaxColumn(settingsGroups[0].range.endLineNumber + 4)
|
||||
},
|
||||
{
|
||||
startLineNumber: lastGroup.range.endLineNumber + 1,
|
||||
|
|
|
@ -21,11 +21,10 @@ import { IModel } from 'vs/editor/common/editorCommon';
|
|||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
||||
import { IMessageService, Severity } from 'vs/platform/message/common/message';
|
||||
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, DefaultSettingsModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels';
|
||||
import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, DefaultSettings, WorkspaceConfigurationEditorModel } 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';
|
||||
|
@ -53,9 +52,9 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
|||
private _onDispose: Emitter<void> = new Emitter<void>();
|
||||
|
||||
private _defaultSettingsUriCounter = 0;
|
||||
private _defaultSettingsContentModel: DefaultSettingsModel;
|
||||
private _defaultSettingsContentModel: DefaultSettings;
|
||||
private _defaultResourceSettingsUriCounter = 0;
|
||||
private _defaultResourceSettingsContentModel: DefaultSettingsModel;
|
||||
private _defaultResourceSettingsContentModel: DefaultSettings;
|
||||
|
||||
constructor(
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
|
@ -68,7 +67,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
|||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService,
|
||||
@ITextModelService private textModelResolverService: ITextModelService,
|
||||
@IExtensionService private extensionService: IExtensionService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IModelService private modelService: IModelService,
|
||||
@IJSONEditingService private jsonEditingService: IJSONEditingService,
|
||||
|
@ -110,14 +108,31 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
|||
|
||||
resolveModel(uri: URI): TPromise<IModel> {
|
||||
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;
|
||||
});
|
||||
|
||||
const scope = this.isDefaultSettingsResource(uri) ? ConfigurationScope.WINDOW : ConfigurationScope.RESOURCE;
|
||||
const mode = this.modeService.getOrCreateMode('json');
|
||||
const model = this._register(this.modelService.createModel('', mode, uri));
|
||||
|
||||
let defaultSettings: DefaultSettings;
|
||||
this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.source === ConfigurationTarget.DEFAULT) {
|
||||
const model = this.modelService.getModel(uri);
|
||||
if (!model) {
|
||||
// model has not been given out => nothing to do
|
||||
return;
|
||||
}
|
||||
defaultSettings = this.getDefaultSettings(scope);
|
||||
this.modelService.updateModel(model, defaultSettings.parse());
|
||||
}
|
||||
});
|
||||
|
||||
// Check if Default settings is already created and updated in above promise
|
||||
if (!defaultSettings) {
|
||||
defaultSettings = this.getDefaultSettings(scope);
|
||||
this.modelService.updateModel(model, defaultSettings.parse());
|
||||
}
|
||||
|
||||
return TPromise.as(model);
|
||||
}
|
||||
|
||||
if (this.defaultKeybindingsResource.toString() === uri.toString()) {
|
||||
|
@ -288,20 +303,20 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
|||
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);
|
||||
return this.instantiationService.createInstance(DefaultSettingsEditorModel, defaultSettingsUri, reference, scope, this.getDefaultSettings(scope));
|
||||
});
|
||||
}
|
||||
|
||||
private getDefaultSettingsModel(scope: ConfigurationScope): DefaultSettingsModel {
|
||||
private getDefaultSettings(scope: ConfigurationScope): DefaultSettings {
|
||||
switch (scope) {
|
||||
case ConfigurationScope.WINDOW:
|
||||
if (!this._defaultSettingsContentModel) {
|
||||
this._defaultSettingsContentModel = new DefaultSettingsModel(this.getMostCommonlyUsedSettings(), scope);
|
||||
this._defaultSettingsContentModel = new DefaultSettings(this.getMostCommonlyUsedSettings(), scope);
|
||||
}
|
||||
return this._defaultSettingsContentModel;
|
||||
case ConfigurationScope.RESOURCE:
|
||||
if (!this._defaultResourceSettingsContentModel) {
|
||||
this._defaultResourceSettingsContentModel = new DefaultSettingsModel(this.getMostCommonlyUsedSettings(), scope);
|
||||
this._defaultResourceSettingsContentModel = new DefaultSettings(this.getMostCommonlyUsedSettings(), scope);
|
||||
}
|
||||
return this._defaultResourceSettingsContentModel;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import { assign } from 'vs/base/common/objects';
|
|||
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 Event, { Emitter } 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';
|
||||
|
@ -499,7 +499,8 @@ export class WorkspaceConfigModel extends SettingsEditorModel implements ISettin
|
|||
}
|
||||
}
|
||||
|
||||
export class DefaultSettingsModel {
|
||||
export class DefaultSettings {
|
||||
|
||||
|
||||
private _allSettingsGroups: ISettingsGroup[];
|
||||
private _content: string;
|
||||
|
@ -525,13 +526,14 @@ export class DefaultSettingsModel {
|
|||
return this._allSettingsGroups;
|
||||
}
|
||||
|
||||
private parse() {
|
||||
parse(): string {
|
||||
const configurations = Registry.as<IConfigurationRegistry>(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);
|
||||
return this._content;
|
||||
}
|
||||
|
||||
private initAllSettingsMap(allSettingsGroups: ISettingsGroup[]): void {
|
||||
|
@ -678,15 +680,26 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements
|
|||
private _settingsByName: Map<string, ISetting>;
|
||||
private _mostRelevantLineOffset: number;
|
||||
|
||||
private _settingsGroups: ISettingsGroup[];
|
||||
|
||||
private _onDidChangeGroups: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChangeGroups: Event<void> = this._onDidChangeGroups.event;
|
||||
|
||||
constructor(
|
||||
private _uri: URI,
|
||||
reference: IReference<ITextEditorModel>,
|
||||
readonly configurationScope: ConfigurationScope,
|
||||
readonly settingsGroups: ISettingsGroup[]
|
||||
defaultSettings: DefaultSettings
|
||||
) {
|
||||
super();
|
||||
this._settingsGroups = defaultSettings.settingsGroups;
|
||||
|
||||
this._model = reference.object.textEditorModel;
|
||||
this._register(this.onDispose(() => reference.dispose()));
|
||||
this._register(this._model.onDidChangeContent(() => {
|
||||
this._settingsGroups = defaultSettings.settingsGroups;
|
||||
this._onDidChangeGroups.fire();
|
||||
}));
|
||||
|
||||
this.initAllSettingsMap();
|
||||
this._mostRelevantLineOffset = tail(this.settingsGroups).range.endLineNumber + 2;
|
||||
|
@ -696,6 +709,10 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements
|
|||
return this._uri;
|
||||
}
|
||||
|
||||
public get settingsGroups(): ISettingsGroup[] {
|
||||
return this._settingsGroups;
|
||||
}
|
||||
|
||||
public filterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter, mostRelevantSettings?: string[]): IFilterResult {
|
||||
if (mostRelevantSettings) {
|
||||
const mostRelevantGroup = this.renderMostRelevantSettings(mostRelevantSettings);
|
||||
|
|
|
@ -20,7 +20,7 @@ import { getCodeEditor } from 'vs/editor/browser/services/codeEditorService';
|
|||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { overviewRulerRangeHighlight } from 'vs/editor/common/view/editorColorRegistry';
|
||||
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { IEditorOptions, RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
export const GOTO_LINE_PREFIX = ':';
|
||||
|
||||
|
@ -43,7 +43,7 @@ export class GotoLineAction extends QuickOpenAction {
|
|||
|
||||
if (editor) {
|
||||
const config = editor.getConfiguration();
|
||||
if (config.viewInfo.renderLineNumbers && config.viewInfo.renderRelativeLineNumbers) {
|
||||
if (config.viewInfo.renderLineNumbers === RenderLineNumbersType.Relative) {
|
||||
editor.updateOptions({
|
||||
lineNumbers: 'on'
|
||||
});
|
||||
|
|
|
@ -70,6 +70,33 @@ function etag(arg1: any, arg2?: any): string {
|
|||
return `"${crypto.createHash('sha1').update(String(size) + String(mtime)).digest('hex')}"`;
|
||||
}
|
||||
|
||||
class BufferPool {
|
||||
|
||||
static _64K = new BufferPool(64 * 1024, 5);
|
||||
|
||||
constructor(
|
||||
readonly bufferSize: number,
|
||||
private readonly _capacity: number,
|
||||
private readonly _free: Buffer[] = [],
|
||||
) {
|
||||
//
|
||||
}
|
||||
|
||||
acquire(): Buffer {
|
||||
if (this._free.length === 0) {
|
||||
return Buffer.allocUnsafe(this.bufferSize);
|
||||
} else {
|
||||
return this._free.shift();
|
||||
}
|
||||
}
|
||||
|
||||
release(buf: Buffer): void {
|
||||
if (this._free.length <= this._capacity) {
|
||||
this._free.push(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class FileService implements IFileService {
|
||||
|
||||
public _serviceBrand: any;
|
||||
|
@ -324,10 +351,11 @@ export class FileService implements IFileService {
|
|||
|
||||
//#region data stream
|
||||
|
||||
private static chunkSize = 64 * 1024;
|
||||
private static chunkBuffer = Buffer.allocUnsafe(FileService.chunkSize);
|
||||
|
||||
private resolveFileData(resource: uri, options: IResolveContentOptions, token: CancellationToken): Thenable<IContentData> {
|
||||
|
||||
const chunkBuffer = BufferPool._64K.acquire();
|
||||
|
||||
const result: IContentData = {
|
||||
encoding: undefined,
|
||||
stream: undefined,
|
||||
|
@ -371,10 +399,14 @@ export class FileService implements IFileService {
|
|||
if (decoder) {
|
||||
decoder.end();
|
||||
}
|
||||
|
||||
// return the shared buffer
|
||||
BufferPool._64K.release(chunkBuffer);
|
||||
|
||||
if (fd) {
|
||||
fs.close(fd, err => {
|
||||
if (err) {
|
||||
this.options.errorLogger(err.toString());
|
||||
this.options.errorLogger(`resolveFileData#close(): ${err.toString()}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -382,21 +414,22 @@ export class FileService implements IFileService {
|
|||
|
||||
const handleChunk = (bytesRead) => {
|
||||
if (token.isCancellationRequested) {
|
||||
// cancellation
|
||||
// cancellation -> finish
|
||||
finish(new Error('cancelled'));
|
||||
|
||||
} else if (bytesRead < FileService.chunkSize) {
|
||||
// done, write rest, end
|
||||
decoder.write(FileService.chunkBuffer.slice(0, bytesRead), finish);
|
||||
|
||||
} else if (bytesRead === 0) {
|
||||
// no more data -> finish
|
||||
finish();
|
||||
} else if (bytesRead < chunkBuffer.length) {
|
||||
// write the sub-part of data we received -> repeat
|
||||
decoder.write(chunkBuffer.slice(0, bytesRead), readChunk);
|
||||
} else {
|
||||
// read, write, repeat
|
||||
decoder.write(FileService.chunkBuffer, readChunk);
|
||||
// write all data we received -> repeat
|
||||
decoder.write(chunkBuffer, readChunk);
|
||||
}
|
||||
};
|
||||
|
||||
const readChunk = () => {
|
||||
fs.read(fd, FileService.chunkBuffer, 0, FileService.chunkSize, null, (err, bytesRead) => {
|
||||
fs.read(fd, chunkBuffer, 0, chunkBuffer.length, null, (err, bytesRead) => {
|
||||
totalBytesRead += bytesRead;
|
||||
|
||||
if (totalBytesRead > MAX_FILE_SIZE) {
|
||||
|
@ -417,7 +450,7 @@ export class FileService implements IFileService {
|
|||
// when receiving the first chunk of data we need to create the
|
||||
// decoding stream which is then used to drive the string stream.
|
||||
Promise.resolve(detectMimeAndEncodingFromBuffer(
|
||||
{ buffer: FileService.chunkBuffer, bytesRead },
|
||||
{ buffer: chunkBuffer, bytesRead },
|
||||
options && options.autoGuessEncoding || this.configuredAutoGuessEncoding(resource)
|
||||
)).then(value => {
|
||||
|
||||
|
|
|
@ -635,6 +635,23 @@ suite('FileService', () => {
|
|||
}, error => onError(error, done));
|
||||
});
|
||||
|
||||
test('Files are intermingled #38331', function () {
|
||||
let resource1 = uri.file(path.join(testDir, 'lorem.txt'));
|
||||
let resource2 = uri.file(path.join(testDir, 'some_utf16le.css'));
|
||||
let value1: string;
|
||||
let value2: string;
|
||||
// load in sequence and keep data
|
||||
return service.resolveContent(resource1).then(c => value1 = c.value).then(() => {
|
||||
return service.resolveContent(resource2).then(c => value2 = c.value);
|
||||
}).then(() => {
|
||||
// load in parallel in expect the same result
|
||||
return TPromise.join([
|
||||
service.resolveContent(resource1).then(c => assert.equal(c.value, value1)),
|
||||
service.resolveContent(resource2).then(c => assert.equal(c.value, value2))
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test('resolveContent - FILE_IS_BINARY', function (done: () => void) {
|
||||
const resource = uri.file(path.join(testDir, 'binary.txt'));
|
||||
|
||||
|
|
|
@ -581,7 +581,7 @@ if (OS === OperatingSystem.Macintosh || OS === OperatingSystem.Linux) {
|
|||
'type': 'string',
|
||||
'enum': ['code', 'keyCode'],
|
||||
'default': 'code',
|
||||
'description': nls.localize('dispatch', "Controls the dispatching logic for key presses to use either `keydown.code` (recommended) or `keydown.keyCode`.")
|
||||
'description': nls.localize('dispatch', "Controls the dispatching logic for key presses to use either `code` (recommended) or `keyCode`.")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -162,7 +162,7 @@ export abstract class TextFileService implements ITextFileService {
|
|||
return this.confirmBeforeShutdown();
|
||||
}, errors => {
|
||||
const firstError = errors[0];
|
||||
this.messageService.show(Severity.Error, nls.localize('files.backup.failSave', "Files could not be backed up (Error: {0}), try saving your files to exit.", firstError.message));
|
||||
this.messageService.show(Severity.Error, nls.localize('files.backup.failSave', "Files that are dirty could not be written to the backup location (Error: {0}). Try saving your files first and then exit.", firstError.message));
|
||||
|
||||
return true; // veto, the backups failed
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue