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
29923022void 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
31743211auto 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
31883222auto 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+
32183257void DefaultPreprocessorState::operator ()(const ProcessingComplete &) {
32193258 done = true ;
32203259}
0 commit comments