blob: 1129e9bd0e1d5e08acbfb95c99c8061a92fb45f6 [file] [log] [blame]
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/lsp_protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/computer/computer_hover.dart';
import 'package:analysis_server/src/lsp/client_capabilities.dart';
import 'package:analysis_server/src/lsp/dartdoc.dart';
import 'package:analysis_server/src/lsp/error_or.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
import 'package:analysis_server/src/lsp/mapping.dart';
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/source/line_info.dart';
typedef StaticOptions = Either2<bool, HoverOptions>;
class HoverHandler
extends SharedMessageHandler<TextDocumentPositionParams, Hover?> {
HoverHandler(super.server);
@override
Method get handlesMessage => Method.textDocument_hover;
@override
LspJsonHandler<TextDocumentPositionParams> get jsonHandler =>
TextDocumentPositionParams.jsonHandler;
@override
bool get requiresTrustedCaller => false;
@override
Future<ErrorOr<Hover?>> handle(
TextDocumentPositionParams params,
MessageInfo message,
CancellationToken token,
) async {
if (!isDartDocument(params.textDocument)) {
return success(null);
}
var clientCapabilities = message.clientCapabilities;
if (clientCapabilities == null) {
return serverNotInitializedError;
}
var pos = params.position;
var path = pathOfDoc(params.textDocument);
var unit = await path.mapResult(requireResolvedUnit);
var offset = unit.mapResultSync((unit) => toOffset(unit.lineInfo, pos));
return (
success(clientCapabilities),
unit,
offset,
).mapResultsSync(_getHover);
}
Hover? toHover(
LspClientCapabilities clientCapabilities,
LineInfo lineInfo,
HoverInformation? hover,
) {
if (hover == null) {
return null;
}
var content = StringBuffer();
const divider = '---';
// Description + Types.
var elementDescription = hover.elementDescription;
var staticType = hover.staticType;
var isDeprecated = hover.isDeprecated ?? false;
if (elementDescription != null) {
content.writeln('```dart');
if (isDeprecated) {
content.write('(deprecated) ');
}
content
..writeln(elementDescription)
..writeln('```');
}
if (staticType != null) {
content
..writeln('Type: `$staticType`')
..writeln();
}
// Source library.
var containingLibraryName = hover.containingLibraryName;
if (containingLibraryName != null && containingLibraryName.isNotEmpty) {
content
..writeln('*$containingLibraryName*')
..writeln();
}
// Doc comments.
if (hover.dartdoc != null) {
if (content.length != 0) {
content.writeln(divider);
}
content.writeln(cleanDartdoc(hover.dartdoc));
}
var formats = clientCapabilities.hoverContentFormats;
return Hover(
contents: asMarkupContentOrString(
formats,
content.toString().trimRight(),
),
range: toRange(lineInfo, hover.offset, hover.length),
);
}
ErrorOr<Hover?> _getHover(
LspClientCapabilities clientCapabilities,
ResolvedUnitResult unit,
int offset,
) {
var compilationUnit = unit.unit;
var computer = DartUnitHoverComputer(
server.getDartdocDirectiveInfoFor(unit),
compilationUnit,
offset,
documentationPreference:
server.lspClientConfiguration.global.preferredDocumentation,
);
var hover = computer.compute();
return success(toHover(clientCapabilities, unit.lineInfo, hover));
}
}
class HoverRegistrations extends FeatureRegistration
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
HoverRegistrations(super.info);
@override
ToJsonable? get options =>
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes);
@override
Method get registrationMethod => Method.textDocument_hover;
@override
StaticOptions get staticOptions => Either2.t1(true);
@override
bool get supportsDynamic => clientDynamic.hover;
}