2018-09-28 05:19:26 +00:00
|
|
|
/* Copyright 2017-2018 ccls Authors
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
==============================================================================*/
|
|
|
|
|
2018-10-28 17:49:31 +00:00
|
|
|
#include "message_handler.hh"
|
2018-09-28 05:19:26 +00:00
|
|
|
#include "pipeline.hh"
|
2018-10-29 04:21:21 +00:00
|
|
|
#include "working_files.hh"
|
2018-09-28 05:19:26 +00:00
|
|
|
|
|
|
|
#include <clang/Format/Format.h>
|
|
|
|
#include <clang/Tooling/Core/Replacement.h>
|
|
|
|
|
2018-10-28 17:49:31 +00:00
|
|
|
namespace ccls {
|
2018-09-28 05:19:26 +00:00
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
llvm::Expected<tooling::Replacements>
|
|
|
|
FormatCode(std::string_view code, std::string_view file, tooling::Range Range) {
|
|
|
|
StringRef Code(code.data(), code.size()), File(file.data(), file.size());
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2018-11-03 20:52:43 +00:00
|
|
|
std::vector<TextEdit> ReplacementsToEdits(std::string_view code,
|
|
|
|
const tooling::Replacements &Repls) {
|
|
|
|
std::vector<TextEdit> ret;
|
2018-09-28 05:19:26 +00:00
|
|
|
int i = 0, line = 0, col = 0;
|
|
|
|
auto move = [&](int p) {
|
|
|
|
for (; i < 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;
|
|
|
|
}
|
|
|
|
|
2018-10-28 17:49:31 +00:00
|
|
|
void Format(ReplyOnce &reply, WorkingFile *wfile, tooling::Range range) {
|
2018-09-28 05:19:26 +00:00
|
|
|
std::string_view code = wfile->buffer_content;
|
2018-10-28 17:49:31 +00:00
|
|
|
auto ReplsOrErr = FormatCode(code, wfile->filename, range);
|
2018-11-23 18:08:44 +00:00
|
|
|
if (ReplsOrErr)
|
|
|
|
reply(ReplacementsToEdits(code, *ReplsOrErr));
|
|
|
|
else
|
|
|
|
reply.Error(ErrorCode::UnknownErrorCode,
|
|
|
|
llvm::toString(ReplsOrErr.takeError()));
|
2018-09-28 05:19:26 +00:00
|
|
|
}
|
2018-10-28 17:49:31 +00:00
|
|
|
} // namespace
|
2018-09-28 05:19:26 +00:00
|
|
|
|
2018-10-28 17:49:31 +00:00
|
|
|
void MessageHandler::textDocument_formatting(DocumentFormattingParam ¶m,
|
|
|
|
ReplyOnce &reply) {
|
|
|
|
QueryFile *file = FindFile(reply, param.textDocument.uri.GetPath());
|
2018-12-01 06:44:52 +00:00
|
|
|
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
|
|
|
if (!wf)
|
2018-10-28 17:49:31 +00:00
|
|
|
return;
|
2018-12-01 06:44:52 +00:00
|
|
|
Format(reply, wf, {0, (unsigned)wf->buffer_content.size()});
|
2018-10-28 17:49:31 +00:00
|
|
|
}
|
2018-09-28 05:19:26 +00:00
|
|
|
|
2018-10-28 17:49:31 +00:00
|
|
|
void MessageHandler::textDocument_onTypeFormatting(
|
|
|
|
DocumentOnTypeFormattingParam ¶m, ReplyOnce &reply) {
|
|
|
|
QueryFile *file = FindFile(reply, param.textDocument.uri.GetPath());
|
2018-12-01 06:44:52 +00:00
|
|
|
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
|
|
|
if (!wf)
|
2018-10-28 17:49:31 +00:00
|
|
|
return;
|
2018-12-01 06:44:52 +00:00
|
|
|
std::string_view code = wf->buffer_content;
|
2018-10-28 17:49:31 +00:00
|
|
|
int pos = GetOffsetForPosition(param.position, code);
|
|
|
|
auto lbrace = code.find_last_of('{', pos);
|
|
|
|
if (lbrace == std::string::npos)
|
|
|
|
lbrace = pos;
|
2018-12-01 06:44:52 +00:00
|
|
|
Format(reply, wf, {(unsigned)lbrace, unsigned(pos - lbrace)});
|
2018-10-28 17:49:31 +00:00
|
|
|
}
|
2018-09-28 05:19:26 +00:00
|
|
|
|
2018-10-28 17:49:31 +00:00
|
|
|
void MessageHandler::textDocument_rangeFormatting(
|
|
|
|
DocumentRangeFormattingParam ¶m, ReplyOnce &reply) {
|
|
|
|
QueryFile *file = FindFile(reply, param.textDocument.uri.GetPath());
|
2018-12-01 06:44:52 +00:00
|
|
|
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
|
|
|
if (!wf)
|
2018-10-28 17:49:31 +00:00
|
|
|
return;
|
2018-12-01 06:44:52 +00:00
|
|
|
std::string_view code = wf->buffer_content;
|
2018-10-28 17:49:31 +00:00
|
|
|
int begin = GetOffsetForPosition(param.range.start, code),
|
|
|
|
end = GetOffsetForPosition(param.range.end, code);
|
2018-12-01 06:44:52 +00:00
|
|
|
Format(reply, wf, {(unsigned)begin, unsigned(end - begin)});
|
2018-10-28 17:49:31 +00:00
|
|
|
}
|
|
|
|
} // namespace ccls
|