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

import { CancelablePromise, createCancelablePromise, TimeoutTimer } from 'vs/base/common/async';
import { Emitter, Event } from 'vs/base/common/event';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { CodeAction, CodeActionProviderRegistry } from 'vs/editor/common/modes';
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { IProgressService } from 'vs/platform/progress/common/progress';
import { getCodeActions } from './codeAction';
import { CodeActionTrigger } from './codeActionTrigger';

export const SUPPORTED_CODE_ACTIONS = new RawContextKey<string>('supportedCodeAction', '');

export class CodeActionOracle {

	private _disposables: IDisposable[] = [];
	private readonly _autoTriggerTimer = new TimeoutTimer();

	constructor(
		private _editor: ICodeEditor,
		private readonly _markerService: IMarkerService,
		private _signalChange: (e: CodeActionsComputeEvent) => any,
		private readonly _delay: number = 250,
		private readonly _progressService?: IProgressService,
	) {
		this._disposables.push(
			this._markerService.onMarkerChanged(e => this._onMarkerChanges(e)),
			this._editor.onDidChangeCursorPosition(() => this._onCursorChange()),
		);
	}

	dispose(): void {
		this._disposables = dispose(this._disposables);
		this._autoTriggerTimer.cancel();
	}

	trigger(trigger: CodeActionTrigger) {
		const selection = this._getRangeOfSelectionUnlessWhitespaceEnclosed(trigger);
		return this._createEventAndSignalChange(trigger, selection);
	}

	private _onMarkerChanges(resources: URI[]): void {
		const model = this._editor.getModel();
		if (!model) {
			return;
		}

		if (resources.some(resource => resource.toString() === model.uri.toString())) {
			this._autoTriggerTimer.cancelAndSet(() => {
				this.trigger({ type: 'auto' });
			}, this._delay);
		}
	}

	private _onCursorChange(): void {
		this._autoTriggerTimer.cancelAndSet(() => {
			this.trigger({ type: 'auto' });
		}, this._delay);
	}

	private _getRangeOfMarker(selection: Selection): Range | undefined {
		const model = this._editor.getModel();
		if (!model) {
			return undefined;
		}
		for (const marker of this._markerService.read({ resource: model.uri })) {
			if (Range.intersectRanges(marker, selection)) {
				return Range.lift(marker);
			}
		}
		return undefined;
	}

	private _getRangeOfSelectionUnlessWhitespaceEnclosed(trigger: CodeActionTrigger): Selection | undefined {
		if (!this._editor.hasModel()) {
			return undefined;
		}
		const model = this._editor.getModel();
		const selection = this._editor.getSelection();
		if (selection.isEmpty() && !(trigger.filter && trigger.filter.includeSourceActions)) {
			const { lineNumber, column } = selection.getPosition();
			const line = model.getLineContent(lineNumber);
			if (line.length === 0) {
				// empty line
				return undefined;
			} else if (column === 1) {
				// look only right<commit_msg>Don't disable manual code action requests on blank lines<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { CancelablePromise, createCancelablePromise, TimeoutTimer } from 'vs/base/common/async';
import { Emitter, Event } from 'vs/base/common/event';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { CodeAction, CodeActionProviderRegistry } from 'vs/editor/common/modes';
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { IProgressService } from 'vs/platform/progress/common/progress';
import { getCodeActions } from './codeAction';
import { CodeActionTrigger } from './codeActionTrigger';

export const SUPPORTED_CODE_ACTIONS = new RawContextKey<string>('supportedCodeAction', '');

export class CodeActionOracle {

	private _disposables: IDisposable[] = [];
	private readonly _autoTriggerTimer = new TimeoutTimer();

	constructor(
		private _editor: ICodeEditor,
		private readonly _markerService: IMarkerService,
		private _signalChange: (e: CodeActionsComputeEvent) => any,
		private readonly _delay: number = 250,
		private readonly _progressService?: IProgressService,
	) {
		this._disposables.push(
			this._markerService.onMarkerChanged(e => this._onMarkerChanges(e)),
			this._editor.onDidChangeCursorPosition(() => this._onCursorChange()),
		);
	}

	dispose(): void {
		this._disposables = dispose(this._disposables);
		this._autoTriggerTimer.cancel();
	}

	trigger(trigger: CodeActionTrigger) {
		const selection = this._getRangeOfSelectionUnlessWhitespaceEnclosed(trigger);
		return this._createEventAndSignalChange(trigger, selection);
	}

	private _onMarkerChanges(resources: URI[]): void {
		const model = this._editor.getModel();
		if (!model) {
			return;
		}

		if (resources.some(resource => resource.toString() === model.uri.toString())) {
			this._autoTriggerTimer.cancelAndSet(() => {
				this.trigger({ type: 'auto' });
			}, this._delay);
		}
	}

	private _onCursorChange(): void {
		this._autoTriggerTimer.cancelAndSet(() => {
			this.trigger({ type: 'auto' });
		}, this._delay);
	}

	private _getRangeOfMarker(selection: Selection): Range | undefined {
		const model = this._editor.getModel();
		if (!model) {
			return undefined;
		}
		for (const marker of this._markerService.read({ resource: model.uri })) {
			if (Range.intersectRanges(marker, selection)) {
				return Range.lift(marker);
			}
		}
		return undefined;
	}

	private _getRangeOfSelectionUnlessWhitespaceEnclosed(trigger: CodeActionTrigger): Selection | undefined {
		if (!this._editor.hasModel()) {
			return undefined;
		}
		const model = this._editor.getModel();
		const selection = this._editor.getSelection();
		if (selection.isEmpty() && trigger.type === 'auto') {
			const { lineNumber, column } = selection.getPosition();
			const line = model.getLineContent(lineNumber);
			if (line.length === 0) {
				// empty line
				return undefined;
			} else if (column === 1) {
				// look only right
{'fraction_non_alphanumeric': 0.17378800328677074, 'fraction_numerical': 0.001369487811558477, 'mean_word_length': 3.678411274823831, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 17, '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': '821329', 'n_tokens_mistral': 2203, 'n_tokens_neox': 2014, 'n_words': 475}