Skip to content

Commit 494e814

Browse files
committed
chore: Add APIs to request code completion at a specific location
Signed-off-by: Roberto Raggi <[email protected]>
1 parent 9efb8d7 commit 494e814

File tree

2 files changed

+58
-17
lines changed

2 files changed

+58
-17
lines changed

src/parser/cxx/preprocessor.cc

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <cxx/literals.h>
2929
#include <cxx/preprocessor.h>
3030
#include <cxx/private/path.h>
31+
#include <utf8/checked.h>
3132
#include <utf8/unchecked.h>
3233

3334
#include <algorithm>
@@ -637,24 +638,35 @@ struct SourceFile {
637638
initLineMap();
638639
}
639640

640-
void getTokenStartPosition(unsigned offset, unsigned *line, unsigned *column,
641-
std::string_view *fileName) const {
641+
[[nodiscard]] auto getTokenStartPosition(unsigned offset) const
642+
-> SourcePosition {
642643
auto it = std::lower_bound(lines.cbegin(), lines.cend(),
643644
static_cast<int>(offset));
644645
if (*it != static_cast<int>(offset)) --it;
645646

646647
assert(*it <= int(offset));
647648

648-
if (line) *line = int(std::distance(cbegin(lines), it) + 1);
649+
auto line = std::uint32_t(std::distance(cbegin(lines), it) + 1);
649650

650-
if (column) {
651-
const auto start = cbegin(source) + *it;
652-
const auto end = cbegin(source) + offset;
651+
const auto start = cbegin(source) + *it;
652+
const auto end = cbegin(source) + offset;
653653

654-
*column = utf8::unchecked::distance(start, end) + 1;
655-
}
654+
const auto column =
655+
std::uint32_t(utf8::unchecked::distance(start, end) + 1);
656+
657+
return SourcePosition{fileName, line, column};
658+
}
656659

657-
if (fileName) *fileName = this->fileName;
660+
[[nodiscard]] auto offsetAt(std::uint32_t line, std::uint32_t column) const
661+
-> std::uint32_t {
662+
if (line == 0 && column == 0) return 0;
663+
if (line > lines.size()) return static_cast<std::uint32_t>(source.size());
664+
const auto start = source.data();
665+
const auto end = start + source.size();
666+
const auto offsetOfTheLine = lines[line - 1];
667+
auto it = start + offsetOfTheLine;
668+
utf8::advance(it, column - 1, end);
669+
return static_cast<std::uint32_t>(it - start);
658670
}
659671

660672
private:
@@ -713,6 +725,8 @@ struct Preprocessor::Private {
713725
};
714726
std::vector<Dep> dependencies_;
715727
std::function<auto()->std::optional<PreprocessingState>> continuation_;
728+
std::optional<SourcePosition> codeCompletionLocation_;
729+
std::uint32_t codeCompletionOffset_ = 0;
716730
int localCount_ = 0;
717731

718732
int counter_ = 0;
@@ -1593,6 +1607,18 @@ void Preprocessor::Private::finalizeToken(std::vector<Token> &tokens,
15931607
const auto fileId = tk->sourceFile;
15941608
TokenValue value{};
15951609

1610+
if (tk->sourceFile == 1 && codeCompletionLocation_.has_value()) {
1611+
if (codeCompletionOffset_ < tk->offset ||
1612+
(codeCompletionOffset_ >= tk->offset &&
1613+
codeCompletionOffset_ < tk->offset + tk->length)) {
1614+
auto &completionToken =
1615+
tokens.emplace_back(TokenKind::T_CODE_COMPLETION, tk->offset, 0);
1616+
completionToken.setFileId(fileId);
1617+
1618+
codeCompletionLocation_ = std::nullopt;
1619+
}
1620+
}
1621+
15961622
switch (tk->kind) {
15971623
case TokenKind::T_IDENTIFIER: {
15981624
kind = Lexer::classifyKeyword(tk->text);
@@ -2987,6 +3013,10 @@ void Preprocessor::beginPreprocessing(std::string source, std::string fileName,
29873013
if (tokens.empty()) {
29883014
tokens.emplace_back(TokenKind::T_ERROR);
29893015
}
3016+
3017+
if (auto loc = d->codeCompletionLocation_) {
3018+
d->codeCompletionOffset_ = sourceFile->offsetAt(loc->line, loc->column);
3019+
}
29903020
}
29913021

29923022
void Preprocessor::endPreprocessing(std::vector<Token> &tokens) {
@@ -3002,6 +3032,16 @@ void Preprocessor::endPreprocessing(std::vector<Token> &tokens) {
30023032

30033033
// place the EOF token at the end of the main source file
30043034
const auto offset = d->sourceFiles_[mainSourceFileId - 1]->source.size();
3035+
3036+
if (d->codeCompletionLocation_.has_value()) {
3037+
auto sourceFile = d->sourceFiles_[0].get();
3038+
3039+
auto &tk = tokens.emplace_back(TokenKind::T_CODE_COMPLETION, offset, 0);
3040+
tk.setFileId(mainSourceFileId);
3041+
3042+
d->codeCompletionLocation_ = std::nullopt;
3043+
}
3044+
30053045
auto &tk = tokens.emplace_back(TokenKind::T_EOF_SYMBOL, offset);
30063046
tk.setFileId(mainSourceFileId);
30073047
}
@@ -3165,10 +3205,7 @@ auto Preprocessor::tokenStartPosition(const Token &token) const
31653205
}
31663206

31673207
auto &sourceFile = *d->sourceFiles_[token.fileId() - 1];
3168-
SourcePosition pos;
3169-
sourceFile.getTokenStartPosition(token.offset(), &pos.line, &pos.column,
3170-
&pos.fileName);
3171-
return pos;
3208+
return sourceFile.getTokenStartPosition(token.offset());
31723209
}
31733210

31743211
auto Preprocessor::tokenEndPosition(const Token &token) const
@@ -3179,10 +3216,7 @@ auto Preprocessor::tokenEndPosition(const Token &token) const
31793216

31803217
auto &sourceFile = *d->sourceFiles_[token.fileId() - 1];
31813218

3182-
SourcePosition pos;
3183-
sourceFile.getTokenStartPosition(token.offset() + token.length(), &pos.line,
3184-
&pos.column, &pos.fileName);
3185-
return pos;
3219+
return sourceFile.getTokenStartPosition(token.offset() + token.length());
31863220
}
31873221

31883222
auto Preprocessor::getTextLine(const Token &token) const -> std::string_view {
@@ -3215,6 +3249,11 @@ auto Preprocessor::resolve(const Include &include, bool isIncludeNext) const
32153249
return d->resolve(include, isIncludeNext);
32163250
}
32173251

3252+
void Preprocessor::requestCodeCompletionAt(std::uint32_t line,
3253+
std::uint32_t column) {
3254+
d->codeCompletionLocation_ = SourcePosition{{}, line, column};
3255+
}
3256+
32183257
void DefaultPreprocessorState::operator()(const ProcessingComplete &) {
32193258
done = true;
32203259
}

src/parser/cxx/preprocessor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ class Preprocessor {
115115
[[nodiscard]] auto resolve(const Include &include, bool isIncludeNext) const
116116
-> std::optional<std::string>;
117117

118+
void requestCodeCompletionAt(std::uint32_t line, std::uint32_t column);
119+
118120
void squeeze();
119121

120122
private:

0 commit comments

Comments
 (0)