@@ -637,24 +637,37 @@ struct SourceFile {
637637 initLineMap ();
638638 }
639639
640- void getTokenStartPosition (unsigned offset, unsigned *line, unsigned *column,
641- std::string_view *fileName) const {
640+ [[nodiscard]] auto getTokenStartPosition (unsigned offset) const
641+ -> SourcePosition {
642642 auto it = std::lower_bound (lines.cbegin (), lines.cend (),
643643 static_cast <int >(offset));
644644 if (*it != static_cast <int >(offset)) --it;
645645
646646 assert (*it <= int (offset));
647647
648- if ( line) *line = int (std::distance (cbegin (lines), it) + 1 );
648+ auto line = std::uint32_t (std::distance (cbegin (lines), it) + 1 );
649649
650- if (column) {
651- const auto start = cbegin (source) + *it;
652- const auto end = cbegin (source) + offset;
650+ const auto start = cbegin (source) + *it;
651+ const auto end = cbegin (source) + offset;
653652
654- * column = utf8::unchecked::distance (start, end) + 1 ;
655- }
653+ const auto column =
654+ std::uint32_t ( utf8::unchecked::distance (start, end) + 1 );
656655
657- if (fileName) *fileName = this ->fileName ;
656+ return SourcePosition{fileName, line, column};
657+ }
658+
659+ [[nodiscard]] auto offsetAt (std::uint32_t line, std::uint32_t column) const
660+ -> std::uint32_t {
661+ if (line == 0 && column == 0 ) return 0 ;
662+ if (line > lines.size ()) return static_cast <std::uint32_t >(source.size ());
663+ const auto start = source.data ();
664+ const auto end = start + source.size ();
665+ const auto offsetOfTheLine = lines[line - 1 ];
666+ auto it = start + offsetOfTheLine;
667+ for (std::uint32_t i = 1 ; i < column; ++i) {
668+ utf8::unchecked::next (it);
669+ }
670+ return static_cast <std::uint32_t >(it - start);
658671 }
659672
660673 private:
@@ -713,6 +726,8 @@ struct Preprocessor::Private {
713726 };
714727 std::vector<Dep> dependencies_;
715728 std::function<auto ()->std::optional<PreprocessingState>> continuation_;
729+ std::optional<SourcePosition> codeCompletionLocation_;
730+ std::uint32_t codeCompletionOffset_ = 0 ;
716731 int localCount_ = 0 ;
717732
718733 int counter_ = 0 ;
@@ -1593,6 +1608,18 @@ void Preprocessor::Private::finalizeToken(std::vector<Token> &tokens,
15931608 const auto fileId = tk->sourceFile ;
15941609 TokenValue value{};
15951610
1611+ if (tk->sourceFile == 1 && codeCompletionLocation_.has_value ()) {
1612+ if (codeCompletionOffset_ < tk->offset ||
1613+ (codeCompletionOffset_ >= tk->offset &&
1614+ codeCompletionOffset_ < tk->offset + tk->length )) {
1615+ auto &completionToken =
1616+ tokens.emplace_back (TokenKind::T_CODE_COMPLETION, tk->offset , 0 );
1617+ completionToken.setFileId (fileId);
1618+
1619+ codeCompletionLocation_ = std::nullopt ;
1620+ }
1621+ }
1622+
15961623 switch (tk->kind ) {
15971624 case TokenKind::T_IDENTIFIER: {
15981625 kind = Lexer::classifyKeyword (tk->text );
@@ -2987,6 +3014,10 @@ void Preprocessor::beginPreprocessing(std::string source, std::string fileName,
29873014 if (tokens.empty ()) {
29883015 tokens.emplace_back (TokenKind::T_ERROR);
29893016 }
3017+
3018+ if (auto loc = d->codeCompletionLocation_ ) {
3019+ d->codeCompletionOffset_ = sourceFile->offsetAt (loc->line , loc->column );
3020+ }
29903021}
29913022
29923023void Preprocessor::endPreprocessing (std::vector<Token> &tokens) {
@@ -3002,6 +3033,16 @@ void Preprocessor::endPreprocessing(std::vector<Token> &tokens) {
30023033
30033034 // place the EOF token at the end of the main source file
30043035 const auto offset = d->sourceFiles_ [mainSourceFileId - 1 ]->source .size ();
3036+
3037+ if (d->codeCompletionLocation_ .has_value ()) {
3038+ auto sourceFile = d->sourceFiles_ [0 ].get ();
3039+
3040+ auto &tk = tokens.emplace_back (TokenKind::T_CODE_COMPLETION, offset, 0 );
3041+ tk.setFileId (mainSourceFileId);
3042+
3043+ d->codeCompletionLocation_ = std::nullopt ;
3044+ }
3045+
30053046 auto &tk = tokens.emplace_back (TokenKind::T_EOF_SYMBOL, offset);
30063047 tk.setFileId (mainSourceFileId);
30073048}
@@ -3165,10 +3206,7 @@ auto Preprocessor::tokenStartPosition(const Token &token) const
31653206 }
31663207
31673208 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;
3209+ return sourceFile.getTokenStartPosition (token.offset ());
31723210}
31733211
31743212auto Preprocessor::tokenEndPosition (const Token &token) const
@@ -3179,10 +3217,7 @@ auto Preprocessor::tokenEndPosition(const Token &token) const
31793217
31803218 auto &sourceFile = *d->sourceFiles_ [token.fileId () - 1 ];
31813219
3182- SourcePosition pos;
3183- sourceFile.getTokenStartPosition (token.offset () + token.length (), &pos.line ,
3184- &pos.column , &pos.fileName );
3185- return pos;
3220+ return sourceFile.getTokenStartPosition (token.offset () + token.length ());
31863221}
31873222
31883223auto Preprocessor::getTextLine (const Token &token) const -> std::string_view {
@@ -3215,6 +3250,11 @@ auto Preprocessor::resolve(const Include &include, bool isIncludeNext) const
32153250 return d->resolve (include, isIncludeNext);
32163251}
32173252
3253+ void Preprocessor::requestCodeCompletionAt (std::uint32_t line,
3254+ std::uint32_t column) {
3255+ d->codeCompletionLocation_ = SourcePosition{{}, line, column};
3256+ }
3257+
32183258void DefaultPreprocessorState::operator ()(const ProcessingComplete &) {
32193259 done = true ;
32203260}
0 commit comments