forked from MaskRay/ccls
-
Notifications
You must be signed in to change notification settings - Fork 0
/
textDocument_hover.cc
109 lines (100 loc) · 2.98 KB
/
textDocument_hover.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "message_handler.hh"
#include "query.hh"
namespace ccls {
namespace {
struct MarkedString {
std::optional<std::string> language;
std::string value;
};
struct Hover {
std::vector<MarkedString> contents;
std::optional<lsRange> range;
};
void reflect(JsonWriter &vis, MarkedString &v) {
// If there is a language, emit a `{language:string, value:string}` object. If
// not, emit a string.
if (v.language) {
vis.startObject();
REFLECT_MEMBER(language);
REFLECT_MEMBER(value);
vis.endObject();
} else {
reflect(vis, v.value);
}
}
REFLECT_STRUCT(Hover, contents, range);
const char *languageIdentifier(LanguageId lang) {
switch (lang) {
// clang-format off
case LanguageId::C: return "c";
case LanguageId::Cpp: return "cpp";
case LanguageId::ObjC: return "objective-c";
case LanguageId::ObjCpp: return "objective-cpp";
default: return "";
// clang-format on
}
}
// Returns the hover or detailed name for `sym`, if any.
std::pair<std::optional<MarkedString>, std::optional<MarkedString>>
getHover(DB *db, LanguageId lang, SymbolRef sym, int file_id) {
const char *comments = nullptr;
std::optional<MarkedString> ls_comments, hover;
withEntity(db, sym, [&](const auto &entity) {
for (auto &d : entity.def) {
if (!comments && d.comments[0])
comments = d.comments;
if (d.spell) {
if (d.comments[0])
comments = d.comments;
if (const char *s =
d.hover[0] ? d.hover
: d.detailed_name[0] ? d.detailed_name : nullptr) {
if (!hover)
hover = {languageIdentifier(lang), s};
else if (strlen(s) > hover->value.size())
hover->value = s;
}
if (d.spell->file_id == file_id)
break;
}
}
if (!hover && entity.def.size()) {
auto &d = entity.def[0];
hover = {languageIdentifier(lang)};
if (d.hover[0])
hover->value = d.hover;
else if (d.detailed_name[0])
hover->value = d.detailed_name;
}
if (comments)
ls_comments = MarkedString{std::nullopt, comments};
});
return {hover, ls_comments};
}
} // namespace
void MessageHandler::textDocument_hover(TextDocumentPositionParam ¶m,
ReplyOnce &reply) {
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf)
return;
Hover result;
for (SymbolRef sym : findSymbolsAtLocation(wf, file, param.position)) {
std::optional<lsRange> ls_range =
getLsRange(wfiles->getFile(file->def->path), sym.range);
if (!ls_range)
continue;
auto [hover, comments] = getHover(db, file->def->language, sym, file->id);
if (comments || hover) {
result.range = *ls_range;
if (comments)
result.contents.push_back(*comments);
if (hover)
result.contents.push_back(*hover);
break;
}
}
reply(result);
}
} // namespace ccls