Merge from vscode 27ada910e121e23a6d95ecca9cae595fb98ab568

This commit is contained in:
ADS Merger
2020-04-30 00:53:43 +00:00
parent 87e5239713
commit 93f35ca321
413 changed files with 7190 additions and 8756 deletions

View File

@@ -103,14 +103,14 @@ export class ShiftCommand implements ICommand {
const { tabSize, indentSize, insertSpaces } = this._opts;
const shouldIndentEmptyLines = (startLine === endLine);
// if indenting or outdenting on a whitespace only line
if (this._selection.isEmpty()) {
if (/^\s*$/.test(model.getLineContent(startLine))) {
this._useLastEditRangeForCursorEndPosition = true;
}
}
if (this._opts.useTabStops) {
// if indenting or outdenting on a whitespace only line
if (this._selection.isEmpty()) {
if (/^\s*$/.test(model.getLineContent(startLine))) {
this._useLastEditRangeForCursorEndPosition = true;
}
}
// keep track of previous line's "miss-alignment"
let previousLineExtraSpaces = 0, extraSpaces = 0;
for (let lineNumber = startLine; lineNumber <= endLine; lineNumber++, previousLineExtraSpaces = extraSpaces) {
@@ -188,6 +188,11 @@ export class ShiftCommand implements ICommand {
}
} else {
// if indenting or outdenting on a whitespace only line
if (!this._opts.isUnshift && this._selection.isEmpty() && model.getLineLength(startLine) === 0) {
this._useLastEditRangeForCursorEndPosition = true;
}
const oneIndent = (insertSpaces ? cachedStringRepeat(' ', indentSize) : '\t');
for (let lineNumber = startLine; lineNumber <= endLine; lineNumber++) {

View File

@@ -34,7 +34,6 @@ import { withUndefinedAsNull } from 'vs/base/common/types';
import { VSBufferReadableStream, VSBuffer } from 'vs/base/common/buffer';
import { TokensStore, MultilineTokens, countEOL, MultilineTokens2, TokensStore2 } from 'vs/editor/common/model/tokensStore';
import { Color } from 'vs/base/common/color';
import { Constants } from 'vs/base/common/uint';
import { EditorTheme } from 'vs/editor/common/view/viewContext';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { TextChange } from 'vs/editor/common/model/textChange';
@@ -172,6 +171,21 @@ const enum StringOffsetValidationType {
SurrogatePairs = 1,
}
type ContinueBracketSearchPredicate = null | (() => boolean);
class BracketSearchCanceled {
public static INSTANCE = new BracketSearchCanceled();
_searchCanceledBrand = undefined;
private constructor() { }
}
function stripBracketSearchCanceled<T>(result: T | null | BracketSearchCanceled): T | null {
if (result instanceof BracketSearchCanceled) {
return null;
}
return result;
}
export class TextModel extends Disposable implements model.ITextModel {
private static readonly MODEL_SYNC_LIMIT = 50 * 1024 * 1024; // 50 MB
@@ -2014,7 +2028,7 @@ export class TextModel extends Disposable implements model.ITextModel {
return null;
}
return this._findMatchingBracketUp(data, position);
return stripBracketSearchCanceled(this._findMatchingBracketUp(data, position, null));
}
public matchBracket(position: IPosition): [Range, Range] | null {
@@ -2062,8 +2076,11 @@ export class TextModel extends Disposable implements model.ITextModel {
// check that we didn't hit a bracket too far away from position
if (foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {
const foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1).toLowerCase();
const r = this._matchFoundBracket(foundBracket, currentModeBrackets.textIsBracket[foundBracketText], currentModeBrackets.textIsOpenBracket[foundBracketText]);
const r = this._matchFoundBracket(foundBracket, currentModeBrackets.textIsBracket[foundBracketText], currentModeBrackets.textIsOpenBracket[foundBracketText], null);
if (r) {
if (r instanceof BracketSearchCanceled) {
return null;
}
bestResult = r;
}
}
@@ -2100,8 +2117,11 @@ export class TextModel extends Disposable implements model.ITextModel {
// check that we didn't hit a bracket too far away from position
if (foundBracket && foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {
const foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1).toLowerCase();
const r = this._matchFoundBracket(foundBracket, prevModeBrackets.textIsBracket[foundBracketText], prevModeBrackets.textIsOpenBracket[foundBracketText]);
const r = this._matchFoundBracket(foundBracket, prevModeBrackets.textIsBracket[foundBracketText], prevModeBrackets.textIsOpenBracket[foundBracketText], null);
if (r) {
if (r instanceof BracketSearchCanceled) {
return null;
}
return r;
}
}
@@ -2111,35 +2131,41 @@ export class TextModel extends Disposable implements model.ITextModel {
return null;
}
private _matchFoundBracket(foundBracket: Range, data: RichEditBracket, isOpen: boolean): [Range, Range] | null {
private _matchFoundBracket(foundBracket: Range, data: RichEditBracket, isOpen: boolean, continueSearchPredicate: ContinueBracketSearchPredicate): [Range, Range] | null | BracketSearchCanceled {
if (!data) {
return null;
}
if (isOpen) {
let matched = this._findMatchingBracketDown(data, foundBracket.getEndPosition());
if (matched) {
return [foundBracket, matched];
}
} else {
let matched = this._findMatchingBracketUp(data, foundBracket.getStartPosition());
if (matched) {
return [foundBracket, matched];
}
const matched = (
isOpen
? this._findMatchingBracketDown(data, foundBracket.getEndPosition(), continueSearchPredicate)
: this._findMatchingBracketUp(data, foundBracket.getStartPosition(), continueSearchPredicate)
);
if (!matched) {
return null;
}
return null;
if (matched instanceof BracketSearchCanceled) {
return matched;
}
return [foundBracket, matched];
}
private _findMatchingBracketUp(bracket: RichEditBracket, position: Position): Range | null {
private _findMatchingBracketUp(bracket: RichEditBracket, position: Position, continueSearchPredicate: ContinueBracketSearchPredicate): Range | null | BracketSearchCanceled {
// console.log('_findMatchingBracketUp: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));
const languageId = bracket.languageIdentifier.id;
const reversedBracketRegex = bracket.reversedRegex;
let count = -1;
const searchPrevMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null => {
let totalCallCount = 0;
const searchPrevMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null | BracketSearchCanceled => {
while (true) {
if (continueSearchPredicate && (++totalCallCount) % 100 === 0 && !continueSearchPredicate()) {
return BracketSearchCanceled.INSTANCE;
}
const r = BracketsUtils.findPrevBracketInRange(reversedBracketRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);
if (!r) {
break;
@@ -2214,15 +2240,19 @@ export class TextModel extends Disposable implements model.ITextModel {
return null;
}
private _findMatchingBracketDown(bracket: RichEditBracket, position: Position): Range | null {
private _findMatchingBracketDown(bracket: RichEditBracket, position: Position, continueSearchPredicate: ContinueBracketSearchPredicate): Range | null | BracketSearchCanceled {
// console.log('_findMatchingBracketDown: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));
const languageId = bracket.languageIdentifier.id;
const bracketRegex = bracket.forwardRegex;
let count = 1;
const searchNextMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null => {
let totalCallCount = 0;
const searchNextMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null | BracketSearchCanceled => {
while (true) {
if (continueSearchPredicate && (++totalCallCount) % 100 === 0 && !continueSearchPredicate()) {
return BracketSearchCanceled.INSTANCE;
}
const r = BracketsUtils.findNextBracketInRange(bracketRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);
if (!r) {
break;
@@ -2452,7 +2482,16 @@ export class TextModel extends Disposable implements model.ITextModel {
return null;
}
public findEnclosingBrackets(_position: IPosition, maxDuration = Constants.MAX_SAFE_SMALL_INTEGER): [Range, Range] | null {
public findEnclosingBrackets(_position: IPosition, maxDuration?: number): [Range, Range] | null {
let continueSearchPredicate: ContinueBracketSearchPredicate;
if (typeof maxDuration === 'undefined') {
continueSearchPredicate = null;
} else {
const startTime = Date.now();
continueSearchPredicate = () => {
return (Date.now() - startTime <= maxDuration);
};
}
const position = this.validatePosition(_position);
const lineCount = this.getLineCount();
const savedCounts = new Map<number, number[]>();
@@ -2468,8 +2507,13 @@ export class TextModel extends Disposable implements model.ITextModel {
}
counts = savedCounts.get(languageId)!;
};
const searchInRange = (modeBrackets: RichEditBrackets, lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): [Range, Range] | null => {
let totalCallCount = 0;
const searchInRange = (modeBrackets: RichEditBrackets, lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): [Range, Range] | null | BracketSearchCanceled => {
while (true) {
if (continueSearchPredicate && (++totalCallCount) % 100 === 0 && !continueSearchPredicate()) {
return BracketSearchCanceled.INSTANCE;
}
const r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);
if (!r) {
break;
@@ -2485,7 +2529,7 @@ export class TextModel extends Disposable implements model.ITextModel {
}
if (counts[bracket.index] === -1) {
return this._matchFoundBracket(r, bracket, false);
return this._matchFoundBracket(r, bracket, false, continueSearchPredicate);
}
}
@@ -2496,12 +2540,7 @@ export class TextModel extends Disposable implements model.ITextModel {
let languageId: LanguageId = -1;
let modeBrackets: RichEditBrackets | null = null;
const startTime = Date.now();
for (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) {
const elapsedTime = Date.now() - startTime;
if (elapsedTime > maxDuration) {
return null;
}
const lineTokens = this._getLineTokens(lineNumber);
const tokenCount = lineTokens.getCount();
const lineText = this._buffer.getLineContent(lineNumber);
@@ -2530,7 +2569,7 @@ export class TextModel extends Disposable implements model.ITextModel {
if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {
const r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset);
if (r) {
return r;
return stripBracketSearchCanceled(r);
}
prevSearchInToken = false;
}
@@ -2555,7 +2594,7 @@ export class TextModel extends Disposable implements model.ITextModel {
if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {
const r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset);
if (r) {
return r;
return stripBracketSearchCanceled(r);
}
}
}
@@ -2566,7 +2605,7 @@ export class TextModel extends Disposable implements model.ITextModel {
if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {
const r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset);
if (r) {
return r;
return stripBracketSearchCanceled(r);
}
}
}

View File

@@ -1034,10 +1034,12 @@ export class TokensStore2 {
aIndex++;
}
if (aIndex < aLen && aTokens.getEndOffset(aIndex) === bEndCharacter) {
// `a` ends exactly at the same spot as `b`!
emitToken(aTokens.getEndOffset(aIndex), (aTokens.getMetadata(aIndex) & aMask) | (bMetadata & bMask));
aIndex++;
if (aIndex < aLen) {
emitToken(bEndCharacter, (aTokens.getMetadata(aIndex) & aMask) | (bMetadata & bMask));
if (aTokens.getEndOffset(aIndex) === bEndCharacter) {
// `a` ends exactly at the same spot as `b`!
aIndex++;
}
} else {
const aMergeIndex = Math.min(Math.max(0, aIndex - 1), aLen - 1);

View File

@@ -94,13 +94,15 @@ export function getWordAtText(column: number, wordDefinition: RegExp, text: stri
// should stop so that subsequent search don't repeat previous searches
const regexIndex = pos - config.windowSize * i;
wordDefinition.lastIndex = Math.max(0, regexIndex);
match = _findRegexMatchEnclosingPosition(wordDefinition, text, pos, prevRegexIndex);
const thisMatch = _findRegexMatchEnclosingPosition(wordDefinition, text, pos, prevRegexIndex);
// stop: found something
if (match) {
if (!thisMatch && match) {
// stop: we have something
break;
}
match = thisMatch;
// stop: searched at start
if (regexIndex <= 0) {
break;
@@ -112,7 +114,7 @@ export function getWordAtText(column: number, wordDefinition: RegExp, text: stri
let result = {
word: match[0],
startColumn: textOffset + 1 + match.index!,
endColumn: textOffset + 1 + wordDefinition.lastIndex
endColumn: textOffset + 1 + match.index! + match[0].length
};
wordDefinition.lastIndex = 0;
return result;

View File

@@ -1531,6 +1531,21 @@ export interface CommentReaction {
readonly canEdit?: boolean;
}
/**
* @internal
*/
export interface CommentOptions {
/**
* An optional string to show on the comment input box when it's collapsed.
*/
prompt?: string;
/**
* An optional string to show as placeholder in the comment input box when it's focused.
*/
placeHolder?: string;
}
/**
* @internal
*/

View File

@@ -9,6 +9,7 @@ import { LanguageId, LanguageIdentifier } from 'vs/editor/common/modes';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { ILanguageExtensionPoint } from 'vs/editor/common/services/modeService';
import { Registry } from 'vs/platform/registry/common/platform';
import { IDisposable } from 'vs/base/common/lifecycle';
// Define extension point ids
export const Extensions = {
@@ -30,9 +31,19 @@ export class EditorModesRegistry {
// --- languages
public registerLanguage(def: ILanguageExtensionPoint): void {
public registerLanguage(def: ILanguageExtensionPoint): IDisposable {
this._languages.push(def);
this._onDidChangeLanguages.fire(undefined);
return {
dispose: () => {
for (let i = 0, len = this._languages.length; i < len; i++) {
if (this._languages[i] === def) {
this._languages.splice(i, 1);
return;
}
}
}
};
}
public setDynamicLanguages(def: ILanguageExtensionPoint[]): void {
this._dynamicLanguages = def;

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, IDisposable, DisposableStore, dispose } from 'vs/base/common/lifecycle';
import * as platform from 'vs/base/common/platform';
@@ -28,13 +27,9 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IUndoRedoService, IUndoRedoElement, IPastFutureElements } from 'vs/platform/undoRedo/common/undoRedo';
import { StringSHA1 } from 'vs/base/common/hash';
import { SingleModelEditStackElement, MultiModelEditStackElement, EditStackElement } from 'vs/editor/common/model/editStack';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { Schemas } from 'vs/base/common/network';
import Severity from 'vs/base/common/severity';
import { SemanticTokensProviderStyling, toMultilineTokens2 } from 'vs/editor/common/services/semanticTokensProviderStyling';
export const MAINTAIN_UNDO_REDO_STACK = true;
export interface IEditorSemanticHighlightingOptions {
enabled?: boolean;
}
@@ -143,6 +138,8 @@ function isEditStackElements(elements: IUndoRedoElement[]): elements is EditStac
class DisposedModelInfo {
constructor(
public readonly uri: URI,
public readonly time: number,
public readonly heapSize: number,
public readonly sha1: string,
public readonly versionId: number,
public readonly alternativeVersionId: number,
@@ -151,8 +148,6 @@ class DisposedModelInfo {
export class ModelServiceImpl extends Disposable implements IModelService {
private static _PROMPT_UNDO_REDO_SIZE_LIMIT = 10 * 1024 * 1024; // 10MB
public _serviceBrand: undefined;
private readonly _onModelAdded: Emitter<ITextModel> = this._register(new Emitter<ITextModel>());
@@ -171,6 +166,7 @@ export class ModelServiceImpl extends Disposable implements IModelService {
*/
private readonly _models: { [modelId: string]: ModelData; };
private readonly _disposedModels: Map<string, DisposedModelInfo>;
private _disposedModelsHeapSize: number;
private readonly _semanticStyling: SemanticStyling;
constructor(
@@ -179,12 +175,12 @@ export class ModelServiceImpl extends Disposable implements IModelService {
@IThemeService private readonly _themeService: IThemeService,
@ILogService private readonly _logService: ILogService,
@IUndoRedoService private readonly _undoRedoService: IUndoRedoService,
@IDialogService private readonly _dialogService: IDialogService,
) {
super();
this._modelCreationOptionsByLanguageAndResource = Object.create(null);
this._models = {};
this._disposedModels = new Map<string, DisposedModelInfo>();
this._disposedModelsHeapSize = 0;
this._semanticStyling = this._register(new SemanticStyling(this._themeService, this._logService));
this._register(this._configurationService.onDidChangeConfiguration(() => this._updateModelOptions()));
@@ -267,6 +263,14 @@ export class ModelServiceImpl extends Disposable implements IModelService {
return platform.OS === platform.OperatingSystem.Linux || platform.OS === platform.OperatingSystem.Macintosh ? '\n' : '\r\n';
}
private _getMaxMemoryForClosedFilesUndoStack(): number {
const result = this._configurationService.getValue<number>('files.maxMemoryForClosedFilesUndoStackMB');
if (typeof result === 'number') {
return result * 1024 * 1024;
}
return 20 * 1024 * 1024;
}
public getCreationOptions(language: string, resource: URI | undefined, isForSimpleWidget: boolean): ITextModelCreationOptions {
let creationOptions = this._modelCreationOptionsByLanguageAndResource[language + resource];
if (!creationOptions) {
@@ -328,13 +332,40 @@ export class ModelServiceImpl extends Disposable implements IModelService {
// --- begin IModelService
private _insertDisposedModel(disposedModelData: DisposedModelInfo): void {
this._disposedModels.set(MODEL_ID(disposedModelData.uri), disposedModelData);
this._disposedModelsHeapSize += disposedModelData.heapSize;
}
private _removeDisposedModel(resource: URI): DisposedModelInfo | undefined {
const disposedModelData = this._disposedModels.get(MODEL_ID(resource));
if (disposedModelData) {
this._disposedModelsHeapSize -= disposedModelData.heapSize;
}
this._disposedModels.delete(MODEL_ID(resource));
return disposedModelData;
}
private _ensureDisposedModelsHeapSize(maxModelsHeapSize: number): void {
if (this._disposedModelsHeapSize > maxModelsHeapSize) {
// we must remove some old undo stack elements to free up some memory
const disposedModels: DisposedModelInfo[] = [];
this._disposedModels.forEach(entry => disposedModels.push(entry));
disposedModels.sort((a, b) => a.time - b.time);
while (disposedModels.length > 0 && this._disposedModelsHeapSize > maxModelsHeapSize) {
const disposedModel = disposedModels.shift()!;
this._removeDisposedModel(disposedModel.uri);
this._undoRedoService.removeElements(disposedModel.uri);
}
}
}
private _createModelData(value: string | ITextBufferFactory, languageIdentifier: LanguageIdentifier, resource: URI | undefined, isForSimpleWidget: boolean): ModelData {
// create & save the model
const options = this.getCreationOptions(languageIdentifier.language, resource, isForSimpleWidget);
const model: TextModel = new TextModel(value, options, languageIdentifier, resource, this._undoRedoService);
if (resource && this._disposedModels.has(MODEL_ID(resource))) {
const disposedModelData = this._disposedModels.get(MODEL_ID(resource))!;
this._disposedModels.delete(MODEL_ID(resource));
const disposedModelData = this._removeDisposedModel(resource)!;
const elements = this._undoRedoService.getElements(resource);
if (computeModelSha1(model) === disposedModelData.sha1 && isEditStackPastFutureElements(elements)) {
for (const element of elements.past) {
@@ -473,7 +504,7 @@ export class ModelServiceImpl extends Disposable implements IModelService {
const model = modelData.model;
let maintainUndoRedoStack = false;
let heapSize = 0;
if (MAINTAIN_UNDO_REDO_STACK && (resource.scheme === Schemas.file || resource.scheme === Schemas.vscodeRemote || resource.scheme === Schemas.userData)) {
if (resource.scheme === Schemas.file || resource.scheme === Schemas.vscodeRemote || resource.scheme === Schemas.userData) {
const elements = this._undoRedoService.getElements(resource);
if ((elements.past.length > 0 || elements.future.length > 0) && isEditStackPastFutureElements(elements)) {
maintainUndoRedoStack = true;
@@ -490,37 +521,27 @@ export class ModelServiceImpl extends Disposable implements IModelService {
}
}
if (maintainUndoRedoStack) {
// We only invalidate the elements, but they remain in the undo-redo service.
this._undoRedoService.setElementsIsValid(resource, false);
this._disposedModels.set(MODEL_ID(resource), new DisposedModelInfo(resource, computeModelSha1(model), model.getVersionId(), model.getAlternativeVersionId()));
} else {
if (!maintainUndoRedoStack) {
this._undoRedoService.removeElements(resource);
modelData.model.dispose();
return;
}
const maxMemory = this._getMaxMemoryForClosedFilesUndoStack();
if (heapSize > maxMemory) {
// the undo stack for this file would never fit in the configured memory, so don't bother with it.
this._undoRedoService.removeElements(resource);
modelData.model.dispose();
return;
}
this._ensureDisposedModelsHeapSize(maxMemory - heapSize);
// We only invalidate the elements, but they remain in the undo-redo service.
this._undoRedoService.setElementsIsValid(resource, false);
this._insertDisposedModel(new DisposedModelInfo(resource, Date.now(), heapSize, computeModelSha1(model), model.getVersionId(), model.getAlternativeVersionId()));
modelData.model.dispose();
// After disposing the model, prompt and ask if we should keep the undo-redo stack
if (maintainUndoRedoStack && heapSize > ModelServiceImpl._PROMPT_UNDO_REDO_SIZE_LIMIT) {
const mbSize = (heapSize / 1024 / 1024).toFixed(1);
this._dialogService.show(
Severity.Info,
nls.localize('undoRedoConfirm', "Keep the undo-redo stack for {0} in memory ({1} MB)?", (resource.scheme === Schemas.file ? resource.fsPath : resource.path), mbSize),
[
nls.localize('nok', "Discard"),
nls.localize('ok', "Keep"),
],
{
cancelId: 2
}
).then((result) => {
const discard = (result.choice === 2 || result.choice === 0);
if (discard) {
this._disposedModels.delete(MODEL_ID(resource));
this._undoRedoService.removeElements(resource);
}
});
}
}
public getModels(): ITextModel[] {

View File

@@ -36,6 +36,7 @@ export const editorBracketMatchBackground = registerColor('editorBracketMatch.ba
export const editorBracketMatchBorder = registerColor('editorBracketMatch.border', { dark: '#888', light: '#B9B9B9', hc: contrastBorder }, nls.localize('editorBracketMatchBorder', 'Color for matching brackets boxes'));
export const editorOverviewRulerBorder = registerColor('editorOverviewRuler.border', { dark: '#7f7f7f4d', light: '#7f7f7f4d', hc: '#7f7f7f4d' }, nls.localize('editorOverviewRulerBorder', 'Color of the overview ruler border.'));
export const editorOverviewRulerBackground = registerColor('editorOverviewRuler.background', null, nls.localize('editorOverviewRulerBackground', 'Background color of the editor overview ruler. Only used when the minimap is enabled and placed on the right side of the editor.'));
export const editorGutter = registerColor('editorGutter.background', { dark: editorBackground, light: editorBackground, hc: editorBackground }, nls.localize('editorGutter', 'Background color of the editor gutter. The gutter contains the glyph margins and the line numbers.'));

View File

@@ -119,6 +119,8 @@ function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterCla
let breakingOffsets: number[] = arrPool1;
let breakingOffsetsVisibleColumn: number[] = arrPool2;
let breakingOffsetsCount: number = 0;
let lastBreakingOffset = 0;
let lastBreakingOffsetVisibleColumn = 0;
let breakingColumn = firstLineBreakColumn;
const prevLen = prevBreakingOffsets.length;
@@ -138,8 +140,12 @@ function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterCla
while (prevIndex < prevLen) {
// Allow for prevIndex to be -1 (for the case where we hit a tab when walking backwards from the first break)
const prevBreakOffset = prevIndex < 0 ? 0 : prevBreakingOffsets[prevIndex];
const prevBreakoffsetVisibleColumn = prevIndex < 0 ? 0 : prevBreakingOffsetsVisibleColumn[prevIndex];
let prevBreakOffset = prevIndex < 0 ? 0 : prevBreakingOffsets[prevIndex];
let prevBreakOffsetVisibleColumn = prevIndex < 0 ? 0 : prevBreakingOffsetsVisibleColumn[prevIndex];
if (lastBreakingOffset > prevBreakOffset) {
prevBreakOffset = lastBreakingOffset;
prevBreakOffsetVisibleColumn = lastBreakingOffsetVisibleColumn;
}
let breakOffset = 0;
let breakOffsetVisibleColumn = 0;
@@ -148,10 +154,10 @@ function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterCla
let forcedBreakOffsetVisibleColumn = 0;
// initially, we search as much as possible to the right (if it fits)
if (prevBreakoffsetVisibleColumn <= breakingColumn) {
let visibleColumn = prevBreakoffsetVisibleColumn;
let prevCharCode = lineText.charCodeAt(prevBreakOffset - 1);
let prevCharCodeClass = classifier.get(prevCharCode);
if (prevBreakOffsetVisibleColumn <= breakingColumn) {
let visibleColumn = prevBreakOffsetVisibleColumn;
let prevCharCode = prevBreakOffset === 0 ? CharCode.Null : lineText.charCodeAt(prevBreakOffset - 1);
let prevCharCodeClass = prevBreakOffset === 0 ? CharacterClass.NONE : classifier.get(prevCharCode);
let entireLineFits = true;
for (let i = prevBreakOffset; i < len; i++) {
const charStartOffset = i;
@@ -169,7 +175,7 @@ function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterCla
charWidth = computeCharWidth(charCode, visibleColumn, tabSize, columnsForFullWidthChar);
}
if (canBreak(prevCharCode, prevCharCodeClass, charCode, charCodeClass)) {
if (charStartOffset > lastBreakingOffset && canBreak(prevCharCode, prevCharCodeClass, charCode, charCodeClass)) {
breakOffset = charStartOffset;
breakOffsetVisibleColumn = visibleColumn;
}
@@ -179,8 +185,14 @@ function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterCla
// check if adding character at `i` will go over the breaking column
if (visibleColumn > breakingColumn) {
// We need to break at least before character at `i`:
forcedBreakOffset = charStartOffset;
forcedBreakOffsetVisibleColumn = visibleColumn - charWidth;
if (charStartOffset > lastBreakingOffset) {
forcedBreakOffset = charStartOffset;
forcedBreakOffsetVisibleColumn = visibleColumn - charWidth;
} else {
// we need to advance at least by one character
forcedBreakOffset = i + 1;
forcedBreakOffsetVisibleColumn = visibleColumn;
}
if (visibleColumn - breakOffsetVisibleColumn > wrappedLineBreakColumn) {
// Cannot break at `breakOffset` => reset it if it was set
@@ -198,7 +210,7 @@ function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterCla
if (entireLineFits) {
// there is no more need to break => stop the outer loop!
if (breakingOffsetsCount > 0) {
// Add last segment
// Add last segment, no need to assign to `lastBreakingOffset` and `lastBreakingOffsetVisibleColumn`
breakingOffsets[breakingOffsetsCount] = prevBreakingOffsets[prevBreakingOffsets.length - 1];
breakingOffsetsVisibleColumn[breakingOffsetsCount] = prevBreakingOffsetsVisibleColumn[prevBreakingOffsets.length - 1];
breakingOffsetsCount++;
@@ -209,11 +221,11 @@ function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterCla
if (breakOffset === 0) {
// must search left
let visibleColumn = prevBreakoffsetVisibleColumn;
let visibleColumn = prevBreakOffsetVisibleColumn;
let charCode = lineText.charCodeAt(prevBreakOffset);
let charCodeClass = classifier.get(charCode);
let hitATabCharacter = false;
for (let i = prevBreakOffset - 1; i >= 0; i--) {
for (let i = prevBreakOffset - 1; i >= lastBreakingOffset; i--) {
const charStartOffset = i + 1;
const prevCharCode = lineText.charCodeAt(i);
@@ -290,7 +302,9 @@ function createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterCla
breakOffsetVisibleColumn = forcedBreakOffsetVisibleColumn;
}
lastBreakingOffset = breakOffset;
breakingOffsets[breakingOffsetsCount] = breakOffset;
lastBreakingOffsetVisibleColumn = breakOffsetVisibleColumn;
breakingOffsetsVisibleColumn[breakingOffsetsCount] = breakOffsetVisibleColumn;
breakingOffsetsCount++;
breakingColumn = breakOffsetVisibleColumn + wrappedLineBreakColumn;