src/vs/workbench/contrib/debug/browser/debugHover.ts/DebugHoverWidget/showAt
class DebugHoverWidget:	async showAt(range: Range, focus: boolean): Promise<void> {
		this.showCancellationSource?.cancel();
		const cancellationSource = this.showCancellationSource = new CancellationTokenSource();
		const session = this.debugService.getViewModel().focusedSession;

		if (!session || !this.editor.hasModel()) {
			return Promise.resolve(this.hide());
		}

		const model = this.editor.getModel();
		const pos = range.getStartPosition();

		let rng: IRange | undefined = undefined;
		let matchingExpression: string | undefined;

		if (EvaluatableExpressionProviderRegistry.has(model)) {
			const supports = EvaluatableExpressionProviderRegistry.ordered(model);

			const promises = supports.map(support => {
				return Promise.resolve(support.provideEvaluatableExpression(model, pos, cancellationSource.token)).then(expression => {
					return expression;
				}, err => {
					//onUnexpectedExternalError(err);
					return undefined;
				});
			});

			const results = await Promise.all(promises).then(coalesce);
			if (results.length > 0) {
				matchingExpression = results[0].expression;
				rng = results[0].range;

				if (!matchingExpression) {
					const lineContent = model.getLineContent(pos.lineNumber);
					matchingExpression = lineContent.substring(rng.startColumn - 1, rng.endColumn - 1);
				}
			}

		} else {	// old one-size-fits-all strategy
			const lineContent = model.getLineContent(pos.lineNumber);
			const { start, end } = getExactExpressionStartAndEnd(lineContent, range.startColumn, range.endColumn);

			// use regex to extract the sub-expression #9821
			matchingExpression = lineContent.substring(start - 1, end);
			rng = new Range(pos.lineNumber, start, pos.lineNumber, start + matchingExpression.length);
		}

		if (!matchingExpression) {
			return Promise.resolve(this.hide());
		}

		let expression;
		if (session.capabilities.supportsEvaluateForHovers) {
			expression = new Expression(matchingExpression);
			await expression.evaluate(session, this.debugService.getViewModel().focusedStackFrame, 'hover');
		} else {
			const focusedStackFrame = this.debugService.getViewModel().focusedStackFrame;
			if (focusedStackFrame) {
				expression = await findExpressionInStackFrame(focusedStackFrame, coalesce(matchingExpression.split('.').map(word => word.trim())));
			}
		}

		if (cancellationSource.token.isCancellationRequested || !expression || (expression instanceof Expression && !expression.available)) {
			this.hide();
			return;
		}

		if (rng) {
			this.highlightDecorations = this.editor.deltaDecorations(this.highlightDecorations, [{
				range: rng,
				options: DebugHoverWidget._HOVER_HIGHLIGHT_DECORATION_OPTIONS
			}]);
		}

		return this.doShow(pos, expression, focus);
	}