<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 'vs/css!./parameterHints';
import nls = require('vs/nls');
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
import { TPromise } from 'vs/base/common/winjs.base';
import * as dom from 'vs/base/browser/dom';
import aria = require('vs/base/browser/ui/aria/aria');
import { SignatureHelp, SignatureInformation, SignatureHelpProviderRegistry } from 'vs/editor/common/modes';
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
import { RunOnceScheduler } from 'vs/base/common/async';
import { onUnexpectedError } from 'vs/base/common/errors';
import Event, { Emitter, chain } from 'vs/base/common/event';
import { domEvent, stop } from 'vs/base/browser/event';
import { ICommonCodeEditor } from 'vs/editor/common/editorCommon';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { Context, provideSignatureHelp } from '../common/parameterHints';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { CharacterSet } from 'vs/editor/common/core/characterClassifier';
import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
import { registerThemingParticipant, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService';
import { editorHoverBackground, editorHoverBorder } from 'vs/platform/theme/common/colorRegistry';

const $ = dom.$;

export interface IHintEvent {
	hints: SignatureHelp;
}

export class ParameterHintsModel extends Disposable {

	static DELAY = 120; // ms

	private _onHint = this._register(new Emitter<IHintEvent>());
	onHint: Event<IHintEvent> = this._onHint.event;

	private _onCancel = this._register(new Emitter<void>());
	onCancel: Event<void> = this._onCancel.event;

	private editor: ICommonCodeEditor;
	private enabled: boolean;
	private triggerCharactersListeners: IDisposable[];
	private active: boolean;
	private throttledDelayer: RunOnceScheduler;

	constructor(editor: ICommonCodeEditor) {
		super();

		this.editor = editor;
		this.enabled = false;
		this.triggerCharactersListeners = [];

		this.throttledDelayer = new RunOnceScheduler(() => this.doTrigger(), ParameterHintsModel.DELAY);

		this.active = false;

		this._register(this.editor.onDidChangeConfiguration(() => this.onEditorConfigurationChange()));
		this._register(this.editor.onDidChangeModel(e => this.onModelChanged()));
		this._register(this.editor.onDidChangeModelLanguage(_ => this.onModelChanged()));
		this._register(this.editor.onDidChangeCursorSelection(e => this.onCursorChange(e)));
		this._register(SignatureHelpProviderRegistry.onDidChange(this.onModelChanged, this));

		this.onEditorConfigurationChange();
		this.onModelChanged();
	}

	cancel(silent: boolean = false): void {
		this.active = false;

		this.throttledDelayer.cancel();

		if (!silent) {
			this._onCancel.fire(void 0);
		}
	}

	trigger(delay = ParameterHintsModel.DELAY): void {
		if (!this.enabled || !SignatureHelpProviderRegistry.has(this.editor.getModel())) {
			return;
		}

		this.cancel(true);
		return this.throttledDelayer.schedule(delay);
	}

	private doTrigger(): void {
		provideSignatureHelp(this.editor.getModel(), this.editor.getPosition())
			.then<SignatureHelp>(null, onUnexpectedError)
			.then(result => {
				if (!result || !result.signatures || result.signatures.length === 0) {
					this.cancel();
					this._onCancel.fire(void 0);
					return false;
				}

				this.active = true;

				const event: IHintEvent = { hints: result };
				this._onHint.fire(event);
				return true;
			});
	}

	isTriggered(): boolean {
		return this.active || this.throttledDelayer.isScheduled();
	}

	private onModelChanged(): void {
		if (this.active) {
			this.cancel();
		}
		this.triggerCharactersListeners = dispose(this.triggerCharactersListeners);

		const model = this.editor.getModel();
		if (!model) {
			return;
		}

		const triggerChars = new CharacterSet();
		for (const support of SignatureHelpProviderRegistry.ordered(model)) {
			if (Array.isArray(support.signatureHelpTriggerCharacters)) {
				for (const ch of support.signatureHelpTriggerCharacters) {
					triggerChars.add(ch.charCodeAt(0));
				}
			}
		}

		this.triggerCharactersListeners.push(this.editor.onDidType((text: string) => {
			let lastCharCode = text.charCodeAt(text.length - 1);
			if (triggerChars.has(lastCharCode)) {
				this.trigger();
			}
		}));
	}

	private onCursorChange(e: ICursorSelectionChangedEvent): void {
		if (e.source === 'mouse') {
			this.cancel();
		} else if (this.isTriggered()) {
			this.trigger();
		}
	}

	private onEditorConfigurationChange(): void {<commit_msg>fixes #28393<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 'vs/css!./parameterHints';
import nls = require('vs/nls');
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
import { TPromise } from 'vs/base/common/winjs.base';
import * as dom from 'vs/base/browser/dom';
import aria = require('vs/base/browser/ui/aria/aria');
import { SignatureHelp, SignatureInformation, SignatureHelpProviderRegistry } from 'vs/editor/common/modes';
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
import { RunOnceScheduler } from 'vs/base/common/async';
import { onUnexpectedError } from 'vs/base/common/errors';
import Event, { Emitter, chain } from 'vs/base/common/event';
import { domEvent, stop } from 'vs/base/browser/event';
import { ICommonCodeEditor } from 'vs/editor/common/editorCommon';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { Context, provideSignatureHelp } from '../common/parameterHints';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { CharacterSet } from 'vs/editor/common/core/characterClassifier';
import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
import { registerThemingParticipant, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService';
import { editorHoverBackground, editorHoverBorder } from 'vs/platform/theme/common/colorRegistry';

const $ = dom.$;

export interface IHintEvent {
	hints: SignatureHelp;
}

export class ParameterHintsModel extends Disposable {

	static DELAY = 120; // ms

	private _onHint = this._register(new Emitter<IHintEvent>());
	onHint: Event<IHintEvent> = this._onHint.event;

	private _onCancel = this._register(new Emitter<void>());
	onCancel: Event<void> = this._onCancel.event;

	private editor: ICommonCodeEditor;
	private enabled: boolean;
	private triggerCharactersListeners: IDisposable[];
	private active: boolean;
	private throttledDelayer: RunOnceScheduler;

	constructor(editor: ICommonCodeEditor) {
		super();

		this.editor = editor;
		this.enabled = false;
		this.triggerCharactersListeners = [];

		this.throttledDelayer = new RunOnceScheduler(() => this.doTrigger(), ParameterHintsModel.DELAY);

		this.active = false;

		this._register(this.editor.onDidChangeConfiguration(() => this.onEditorConfigurationChange()));
		this._register(this.editor.onDidChangeModel(e => this.onModelChanged()));
		this._register(this.editor.onDidChangeModelLanguage(_ => this.onModelChanged()));
		this._register(this.editor.onDidChangeCursorSelection(e => this.onCursorChange(e)));
		this._register(SignatureHelpProviderRegistry.onDidChange(this.onModelChanged, this));

		this.onEditorConfigurationChange();
		this.onModelChanged();
	}

	cancel(silent: boolean = false): void {
		this.active = false;

		this.throttledDelayer.cancel();

		if (!silent) {
			this._onCancel.fire(void 0);
		}
	}

	trigger(delay = ParameterHintsModel.DELAY): void {
		if (!SignatureHelpProviderRegistry.has(this.editor.getModel())) {
			return;
		}

		this.cancel(true);
		return this.throttledDelayer.schedule(delay);
	}

	private doTrigger(): void {
		provideSignatureHelp(this.editor.getModel(), this.editor.getPosition())
			.then<SignatureHelp>(null, onUnexpectedError)
			.then(result => {
				if (!result || !result.signatures || result.signatures.length === 0) {
					this.cancel();
					this._onCancel.fire(void 0);
					return false;
				}

				this.active = true;

				const event: IHintEvent = { hints: result };
				this._onHint.fire(event);
				return true;
			});
	}

	isTriggered(): boolean {
		return this.active || this.throttledDelayer.isScheduled();
	}

	private onModelChanged(): void {
		if (this.active) {
			this.cancel();
		}
		this.triggerCharactersListeners = dispose(this.triggerCharactersListeners);

		const model = this.editor.getModel();
		if (!model) {
			return;
		}

		const triggerChars = new CharacterSet();
		for (const support of SignatureHelpProviderRegistry.ordered(model)) {
			if (Array.isArray(support.signatureHelpTriggerCharacters)) {
				for (const ch of support.signatureHelpTriggerCharacters) {
					triggerChars.add(ch.charCodeAt(0));
				}
			}
		}

		this.triggerCharactersListeners.push(this.editor.onDidType((text: string) => {
			if (!this.enabled) {
				return;
			}

			if (triggerChars.has(text.charCodeAt(text.length - 1))) {
				this.trigger();
			}
		}));
	}

	private onCursorChange(e: ICursorSelectionChangedEvent): void {
		if (e.source === 'mouse') {
			this.cancel();
		} else if (this.isTriggered()) {
			this.trigger();
		}
	}

	private onEditorConfigurationChange(): void {
{'fraction_non_alphanumeric': 0.16233514352211018, 'fraction_numerical': 0.0020364623739332816, 'mean_word_length': 4.067813267813268, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 27, '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': '6036344', 'n_tokens_mistral': 3304, 'n_tokens_neox': 2986, 'n_words': 600}