<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

import { getLeadingWhitespace } from 'vs/base/common/strings';
import { ICommonCodeEditor, IModel, IModelDecorationOptions, TrackedRangeStickiness, IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { TextmateSnippet, Placeholder, SnippetParser } from '../common/snippetParser';
import { Selection } from 'vs/editor/common/core/selection';
import { Range } from 'vs/editor/common/core/range';
import { IPosition } from 'vs/editor/common/core/position';
import { dispose } from 'vs/base/common/lifecycle';

class OneSnippet {

	private readonly _editor: ICommonCodeEditor;
	private readonly _snippet: TextmateSnippet;
	private readonly _offset: number;

	private _placeholderDecorations: Map<Placeholder, string>;
	private _placeholderGroups: Placeholder[][];
	private _placeholderGroupsIdx: number;

	private static readonly _growingDecoration: IModelDecorationOptions = { stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges };
	private static readonly _fixedDecoration: IModelDecorationOptions = { stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges };

	constructor(editor: ICommonCodeEditor, snippet: TextmateSnippet, offset: number) {
		this._editor = editor;
		this._snippet = snippet;
		this._offset = offset;
	}

	dispose(): void {
		if (this._placeholderDecorations) {
			this._editor.changeDecorations(accessor => this._placeholderDecorations.forEach(handle => accessor.removeDecoration(handle)));
		}
	}

	private _init(): void {

		if (this._placeholderDecorations) {
			// already initialized
			return;
		}

		this._placeholderDecorations = new Map<Placeholder, string>();
		const model = this._editor.getModel();

		// create a decoration (tracked range) for each placeholder
		this._editor.changeDecorations(accessor => {

			let lastRange: Range;

			for (const placeholder of this._snippet.getPlaceholders()) {
				const placeholderOffset = this._snippet.offset(placeholder);
				const placeholderLen = this._snippet.len(placeholder);
				const start = model.getPositionAt(this._offset + placeholderOffset);
				const end = model.getPositionAt(this._offset + placeholderOffset + placeholderLen);
				const range = new Range(start.lineNumber, start.column, end.lineNumber, end.column);

				const handle = accessor.addDecoration(range, OneSnippet._fixedDecoration);
				this._placeholderDecorations.set(placeholder, handle);

				lastRange = range;
			}
		});

		this._placeholderGroupsIdx = -1;
		this._placeholderGroups = [];
		let lastBucket: Placeholder[];
		this._snippet.getPlaceholders().sort(Placeholder.compare).forEach(a => {
			if (!lastBucket || lastBucket[0].name !== a.name) {
				lastBucket = [a];
				this._placeholderGroups.push(lastBucket);
			} else {
				lastBucket.push(a);
			}
		});
	}

	move(fwd: boolean): Selection[] {

		this._init();

		const prevGroupsIdx = this._placeholderGroupsIdx;

		if (fwd && this._placeholderGroupsIdx < this._placeholderGroups.length - 1) {
			this._placeholderGroupsIdx += 1;

		} else if (!fwd && this._placeholderGroupsIdx > 0) {
			this._placeholderGroupsIdx -= 1;

		} else {
			return [];
		}

		return this._editor.getModel().changeDecorations(accessor => {

			// change stickness to never grow when typing at its edges
			// so that in-active tabstops never grow
			if (prevGroupsIdx !== -1) {
				for (const placeholder of this._placeholderGroups[prevGroupsIdx]) {
					const id = this._placeholderDecorations.get(placeholder);
					accessor.changeDecorationOptions(id, OneSnippet._fixedDecoration);
				}
			}

			// change stickiness to always grow when typing at its edges
			// because these decorations represent the currently active
			// tabstop. Special case: reaching the final tab stop
			const selections: Selection[] = [];
			for (const placeholder of this._placeholderGroups[this._placeholderGroupsIdx]) {
				const id = this._placeholderDecorations.get(placeholder);
				const range = this._editor.getModel().getDecorationRange(id);
				selections.push(new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn));

				accessor.changeDecorationOptions(id, placeholder.isFinalTabstop ? OneSnippet._fixedDecoration : OneSnippet._growingDecoration);
			}
			return selections;
		});
	}

	get isAtFinalPlaceholder() {
		if (this._placeholderGroupsIdx < 0) {
			return false;
		} else {
			return this._placeholderGroups[this._placeholderGroupsIdx][0].isFinalTabstop;
		}
	}
}
<commit_msg>properly spelled out decoration options<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

import { getLeadingWhitespace } from 'vs/base/common/strings';
import { ICommonCodeEditor, IModel, IModelDecorationOptions, TrackedRangeStickiness, IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { TextmateSnippet, Placeholder, SnippetParser } from '../common/snippetParser';
import { Selection } from 'vs/editor/common/core/selection';
import { Range } from 'vs/editor/common/core/range';
import { IPosition } from 'vs/editor/common/core/position';
import { dispose } from 'vs/base/common/lifecycle';

class OneSnippet {

	private readonly _editor: ICommonCodeEditor;
	private readonly _snippet: TextmateSnippet;
	private readonly _offset: number;

	private _placeholderDecorations: Map<Placeholder, string>;
	private _placeholderGroups: Placeholder[][];
	private _placeholderGroupsIdx: number;

	private static readonly _decorations = {
		active: <IModelDecorationOptions>{ stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges },
		activeFinal: <IModelDecorationOptions>{ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges },
		inActive: <IModelDecorationOptions>{ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges },
	};

	constructor(editor: ICommonCodeEditor, snippet: TextmateSnippet, offset: number) {
		this._editor = editor;
		this._snippet = snippet;
		this._offset = offset;
	}

	dispose(): void {
		if (this._placeholderDecorations) {
			this._editor.changeDecorations(accessor => this._placeholderDecorations.forEach(handle => accessor.removeDecoration(handle)));
		}
	}

	private _init(): void {

		if (this._placeholderDecorations) {
			// already initialized
			return;
		}

		this._placeholderDecorations = new Map<Placeholder, string>();
		const model = this._editor.getModel();

		// create a decoration (tracked range) for each placeholder
		this._editor.changeDecorations(accessor => {

			let lastRange: Range;

			for (const placeholder of this._snippet.getPlaceholders()) {
				const placeholderOffset = this._snippet.offset(placeholder);
				const placeholderLen = this._snippet.len(placeholder);
				const start = model.getPositionAt(this._offset + placeholderOffset);
				const end = model.getPositionAt(this._offset + placeholderOffset + placeholderLen);
				const range = new Range(start.lineNumber, start.column, end.lineNumber, end.column);

				const handle = accessor.addDecoration(range, OneSnippet._decorations.inActive);
				this._placeholderDecorations.set(placeholder, handle);

				lastRange = range;
			}
		});

		this._placeholderGroupsIdx = -1;
		this._placeholderGroups = [];
		let lastBucket: Placeholder[];
		this._snippet.getPlaceholders().sort(Placeholder.compare).forEach(a => {
			if (!lastBucket || lastBucket[0].name !== a.name) {
				lastBucket = [a];
				this._placeholderGroups.push(lastBucket);
			} else {
				lastBucket.push(a);
			}
		});
	}

	move(fwd: boolean): Selection[] {

		this._init();

		const prevGroupsIdx = this._placeholderGroupsIdx;

		if (fwd && this._placeholderGroupsIdx < this._placeholderGroups.length - 1) {
			this._placeholderGroupsIdx += 1;

		} else if (!fwd && this._placeholderGroupsIdx > 0) {
			this._placeholderGroupsIdx -= 1;

		} else {
			return [];
		}

		return this._editor.getModel().changeDecorations(accessor => {

			// change stickness to never grow when typing at its edges
			// so that in-active tabstops never grow
			if (prevGroupsIdx !== -1) {
				for (const placeholder of this._placeholderGroups[prevGroupsIdx]) {
					const id = this._placeholderDecorations.get(placeholder);
					accessor.changeDecorationOptions(id, OneSnippet._decorations.inActive);
				}
			}

			// change stickiness to always grow when typing at its edges
			// because these decorations represent the currently active
			// tabstop. Special case: reaching the final tab stop
			const selections: Selection[] = [];
			for (const placeholder of this._placeholderGroups[this._placeholderGroupsIdx]) {
				const id = this._placeholderDecorations.get(placeholder);
				const range = this._editor.getModel().getDecorationRange(id);
				selections.push(new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn));

				accessor.changeDecorationOptions(id, placeholder.isFinalTabstop ? OneSnippet._decorations.activeFinal : OneSnippet._decorations.active);
			}
			return selections;
		});
	}

	get isAtFinalPlaceholder() {
		if (this._placeholderGroupsIdx < 0) {
			return false;
		} else {
			return this._placeholderGroups[this._placeholderGroupsIdx][0].isFinalTabstop;
		}
	}
}

{'fraction_non_alphanumeric': 0.14132289471042858, 'fraction_numerical': 0.0018066847335140017, 'mean_word_length': 3.865234375, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2365481', 'n_tokens_mistral': 3063, 'n_tokens_neox': 2710, 'n_words': 628}