ccls/src/messages/textDocument_hover.cc

112 lines
2.9 KiB
C++
Raw Normal View History

2018-08-21 05:27:52 +00:00
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "message_handler.hh"
2018-11-27 06:29:28 +00:00
#include "query.hh"
2017-12-06 03:32:33 +00:00
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);
2017-12-23 16:01:43 +00:00
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
}
}
2018-04-16 19:36:02 +00:00
// 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;
2018-08-09 17:08:14 +00:00
WithEntity(db, sym, [&](const auto &entity) {
std::remove_reference_t<decltype(entity.def[0])> *def = nullptr;
for (auto &d : entity.def) {
if (d.spell) {
comments = d.comments[0] ? d.comments : nullptr;
def = &d;
if (d.spell->file_id == file_id)
break;
}
}
2018-09-06 07:22:40 +00:00
if (!def && entity.def.size()) {
def = &entity.def[0];
if (def->comments[0])
comments = def->comments;
}
if (def) {
MarkedString m;
2018-05-05 03:40:52 +00:00
m.language = LanguageIdentifier(lang);
if (def->hover[0]) {
2018-04-16 19:36:02 +00:00
m.value = def->hover;
hover = m;
} else if (def->detailed_name[0]) {
2018-04-16 19:36:02 +00:00
m.value = def->detailed_name;
hover = m;
}
if (comments)
ls_comments = MarkedString{std::nullopt, comments};
}
2018-04-16 19:36:02 +00:00
});
return {hover, ls_comments};
}
} // namespace
void MessageHandler::textDocument_hover(TextDocumentPositionParam &param,
ReplyOnce &reply) {
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
if (!wf) {
reply.NotReady(file);
return;
}
2017-12-06 03:32:33 +00:00
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;
2017-12-06 03:32:33 +00:00
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;
2017-12-06 03:32:33 +00:00
}
}
reply(result);
}
} // namespace ccls