mirror of
https://github.com/MaskRay/ccls.git
synced 2025-04-10 19:02:14 +00:00
104 lines
3.3 KiB
C++
104 lines
3.3 KiB
C++
// Copyright 2017-2018 ccls Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
#include "message_handler.hh"
|
|
#include "pipeline.hh"
|
|
#include "working_files.hh"
|
|
|
|
#include <clang/Format/Format.h>
|
|
#include <clang/Tooling/Core/Replacement.h>
|
|
|
|
namespace ccls {
|
|
using namespace clang;
|
|
|
|
namespace {
|
|
llvm::Expected<tooling::Replacements> formatCode(StringRef code, StringRef file,
|
|
tooling::Range range) {
|
|
auto style = format::getStyle("file", file, "LLVM", code, nullptr);
|
|
if (!style)
|
|
return style.takeError();
|
|
tooling::Replacements includeReplaces =
|
|
format::sortIncludes(*style, code, {range}, file);
|
|
auto changed = tooling::applyAllReplacements(code, includeReplaces);
|
|
if (!changed)
|
|
return changed.takeError();
|
|
return includeReplaces.merge(format::reformat(
|
|
*style, *changed,
|
|
tooling::calculateRangesAfterReplacements(includeReplaces, {range}),
|
|
file));
|
|
}
|
|
|
|
std::vector<TextEdit> replacementsToEdits(std::string_view code,
|
|
const tooling::Replacements &repls) {
|
|
std::vector<TextEdit> ret;
|
|
int i = 0, line = 0, col = 0;
|
|
auto move = [&](unsigned p) {
|
|
for (; i < (int)p; i++)
|
|
if (code[i] == '\n')
|
|
line++, col = 0;
|
|
else {
|
|
if ((uint8_t)code[i] >= 128) {
|
|
while (128 <= (uint8_t)code[++i] && (uint8_t)code[i] < 192)
|
|
;
|
|
i--;
|
|
}
|
|
col++;
|
|
}
|
|
};
|
|
for (const auto &r : repls) {
|
|
move(r.getOffset());
|
|
int l = line, c = col;
|
|
move(r.getOffset() + r.getLength());
|
|
ret.push_back({{{l, c}, {line, col}}, r.getReplacementText().str()});
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void format(ReplyOnce &reply, WorkingFile *wfile, tooling::Range range) {
|
|
std::string_view code = wfile->buffer_content;
|
|
auto replsOrErr = formatCode(
|
|
StringRef(code.data(), code.size()),
|
|
StringRef(wfile->filename.data(), wfile->filename.size()), range);
|
|
if (replsOrErr)
|
|
reply(replacementsToEdits(code, *replsOrErr));
|
|
else
|
|
reply.error(ErrorCode::UnknownErrorCode,
|
|
llvm::toString(replsOrErr.takeError()));
|
|
}
|
|
} // namespace
|
|
|
|
void MessageHandler::textDocument_formatting(DocumentFormattingParam ¶m,
|
|
ReplyOnce &reply) {
|
|
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
|
|
if (!wf)
|
|
return;
|
|
format(reply, wf, {0, (unsigned)wf->buffer_content.size()});
|
|
}
|
|
|
|
void MessageHandler::textDocument_onTypeFormatting(
|
|
DocumentOnTypeFormattingParam ¶m, ReplyOnce &reply) {
|
|
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
|
|
if (!wf) {
|
|
return;
|
|
}
|
|
std::string_view code = wf->buffer_content;
|
|
int pos = getOffsetForPosition(param.position, code);
|
|
auto lbrace = code.find_last_of('{', pos);
|
|
if (lbrace == std::string::npos)
|
|
lbrace = pos;
|
|
format(reply, wf, {(unsigned)lbrace, unsigned(pos - lbrace)});
|
|
}
|
|
|
|
void MessageHandler::textDocument_rangeFormatting(
|
|
DocumentRangeFormattingParam ¶m, ReplyOnce &reply) {
|
|
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
|
|
if (!wf) {
|
|
return;
|
|
}
|
|
std::string_view code = wf->buffer_content;
|
|
int begin = getOffsetForPosition(param.range.start, code),
|
|
end = getOffsetForPosition(param.range.end, code);
|
|
format(reply, wf, {(unsigned)begin, unsigned(end - begin)});
|
|
}
|
|
} // namespace ccls
|