21
21
#include " llvm/Support/MemoryBuffer.h"
22
22
#include " llvm/Support/raw_ostream.h"
23
23
#include < memory>
24
- using namespace clang ;
25
24
25
+ using namespace clang ;
26
+ using namespace llvm ;
27
+ using namespace html ;
26
28
27
29
// / HighlightRange - Highlight a range in the source code with the specified
28
30
// / start/end tags. B/E must be in the same file. This ensures that
@@ -104,6 +106,32 @@ void html::HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E,
104
106
}
105
107
}
106
108
109
+ namespace clang ::html {
110
+ struct RelexRewriteCache {
111
+ // These structs mimic input arguments of HighlightRange().
112
+ struct Highlight {
113
+ SourceLocation B, E;
114
+ std::string StartTag, EndTag;
115
+ bool IsTokenRange;
116
+ };
117
+ struct RawHighlight {
118
+ unsigned B, E;
119
+ std::string StartTag, EndTag;
120
+ };
121
+
122
+ // SmallVector isn't appropriate because these vectors are almost never small.
123
+ using HighlightList = std::vector<Highlight>;
124
+ using RawHighlightList = std::vector<RawHighlight>;
125
+
126
+ DenseMap<FileID, RawHighlightList> SyntaxHighlights;
127
+ DenseMap<FileID, HighlightList> MacroHighlights;
128
+ };
129
+ } // namespace clang::html
130
+
131
+ html::RelexRewriteCacheRef html::instantiateRelexRewriteCache () {
132
+ return std::make_shared<RelexRewriteCache>();
133
+ }
134
+
107
135
void html::EscapeText (Rewriter &R, FileID FID,
108
136
bool EscapeSpaces, bool ReplaceTabs) {
109
137
@@ -442,13 +470,18 @@ input.spoilerhider:checked + label + .spoiler{
442
470
// / information about keywords, macro expansions etc. This uses the macro
443
471
// / table state from the end of the file, so it won't be perfectly perfect,
444
472
// / but it will be reasonably close.
445
- void html::SyntaxHighlight (Rewriter &R, FileID FID, const Preprocessor &PP) {
446
- RewriteBuffer &RB = R.getEditBuffer (FID);
473
+ static void SyntaxHighlightImpl (
474
+ Rewriter &R, FileID FID, const Preprocessor &PP,
475
+ llvm::function_ref<void (RewriteBuffer &, unsigned , unsigned , const char *,
476
+ const char *, const char *)>
477
+ HighlightRangeCallback) {
447
478
479
+ RewriteBuffer &RB = R.getEditBuffer (FID);
448
480
const SourceManager &SM = PP.getSourceManager ();
449
481
llvm::MemoryBufferRef FromFile = SM.getBufferOrFake (FID);
482
+ const char *BufferStart = FromFile.getBuffer ().data ();
483
+
450
484
Lexer L (FID, FromFile, SM, PP.getLangOpts ());
451
- const char *BufferStart = L.getBuffer ().data ();
452
485
453
486
// Inform the preprocessor that we want to retain comments as tokens, so we
454
487
// can highlight them.
@@ -475,13 +508,13 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
475
508
476
509
// If this is a pp-identifier, for a keyword, highlight it as such.
477
510
if (Tok.isNot (tok::identifier))
478
- HighlightRange (RB, TokOffs, TokOffs+ TokLen, BufferStart,
479
- " <span class='keyword'>" , " </span>" );
511
+ HighlightRangeCallback (RB, TokOffs, TokOffs + TokLen, BufferStart,
512
+ " <span class='keyword'>" , " </span>" );
480
513
break ;
481
514
}
482
515
case tok::comment:
483
- HighlightRange (RB, TokOffs, TokOffs+ TokLen, BufferStart,
484
- " <span class='comment'>" , " </span>" );
516
+ HighlightRangeCallback (RB, TokOffs, TokOffs + TokLen, BufferStart,
517
+ " <span class='comment'>" , " </span>" );
485
518
break ;
486
519
case tok::utf8_string_literal:
487
520
// Chop off the u part of u8 prefix
@@ -498,8 +531,8 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
498
531
[[fallthrough]];
499
532
case tok::string_literal:
500
533
// FIXME: Exclude the optional ud-suffix from the highlighted range.
501
- HighlightRange (RB, TokOffs, TokOffs+ TokLen, BufferStart,
502
- " <span class='string_literal'>" , " </span>" );
534
+ HighlightRangeCallback (RB, TokOffs, TokOffs + TokLen, BufferStart,
535
+ " <span class='string_literal'>" , " </span>" );
503
536
break ;
504
537
case tok::hash: {
505
538
// If this is a preprocessor directive, all tokens to end of line are too.
@@ -516,8 +549,8 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
516
549
}
517
550
518
551
// Find end of line. This is a hack.
519
- HighlightRange (RB, TokOffs, TokEnd, BufferStart,
520
- " <span class='directive'>" , " </span>" );
552
+ HighlightRangeCallback (RB, TokOffs, TokEnd, BufferStart,
553
+ " <span class='directive'>" , " </span>" );
521
554
522
555
// Don't skip the next token.
523
556
continue ;
@@ -527,12 +560,43 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
527
560
L.LexFromRawLexer (Tok);
528
561
}
529
562
}
563
+ void html::SyntaxHighlight (Rewriter &R, FileID FID, const Preprocessor &PP,
564
+ RelexRewriteCacheRef Cache) {
565
+ RewriteBuffer &RB = R.getEditBuffer (FID);
566
+ const SourceManager &SM = PP.getSourceManager ();
567
+ llvm::MemoryBufferRef FromFile = SM.getBufferOrFake (FID);
568
+ const char *BufferStart = FromFile.getBuffer ().data ();
569
+
570
+ if (Cache) {
571
+ auto CacheIt = Cache->SyntaxHighlights .find (FID);
572
+ if (CacheIt != Cache->SyntaxHighlights .end ()) {
573
+ for (const RelexRewriteCache::RawHighlight &H : CacheIt->second ) {
574
+ HighlightRange (RB, H.B , H.E , BufferStart, H.StartTag .data (),
575
+ H.EndTag .data ());
576
+ }
577
+ return ;
578
+ }
579
+ }
580
+
581
+ // "Every time you would call HighlightRange, cache the inputs as well."
582
+ auto HighlightRangeCallback = [&](RewriteBuffer &RB, unsigned B, unsigned E,
583
+ const char *BufferStart,
584
+ const char *StartTag, const char *EndTag) {
585
+ HighlightRange (RB, B, E, BufferStart, StartTag, EndTag);
586
+
587
+ if (Cache)
588
+ Cache->SyntaxHighlights [FID].push_back ({B, E, StartTag, EndTag});
589
+ };
590
+
591
+ SyntaxHighlightImpl (R, FID, PP, HighlightRangeCallback);
592
+ }
593
+
594
+ static void HighlightMacrosImpl (
595
+ Rewriter &R, FileID FID, const Preprocessor &PP,
596
+ llvm::function_ref<void (Rewriter &, SourceLocation, SourceLocation,
597
+ const char *, const char *, bool )>
598
+ HighlightRangeCallback) {
530
599
531
- // / HighlightMacros - This uses the macro table state from the end of the
532
- // / file, to re-expand macros and insert (into the HTML) information about the
533
- // / macro expansions. This won't be perfectly perfect, but it will be
534
- // / reasonably close.
535
- void html::HighlightMacros (Rewriter &R, FileID FID, const Preprocessor& PP) {
536
600
// Re-lex the raw token stream into a token buffer.
537
601
const SourceManager &SM = PP.getSourceManager ();
538
602
std::vector<Token> TokenStream;
@@ -659,11 +723,44 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
659
723
// get highlighted.
660
724
Expansion = " <span class='macro_popup'>" + Expansion + " </span></span>" ;
661
725
662
- HighlightRange (R, LLoc.getBegin (), LLoc.getEnd (), " <span class='macro'>" ,
663
- Expansion.c_str (), LLoc.isTokenRange ());
726
+ HighlightRangeCallback (R, LLoc.getBegin (), LLoc.getEnd (),
727
+ " <span class='macro'>" , Expansion.c_str (),
728
+ LLoc.isTokenRange ());
664
729
}
665
730
666
731
// Restore the preprocessor's old state.
667
732
TmpPP.setDiagnostics (*OldDiags);
668
733
TmpPP.setPragmasEnabled (PragmasPreviouslyEnabled);
669
734
}
735
+
736
+ // / HighlightMacros - This uses the macro table state from the end of the
737
+ // / file, to re-expand macros and insert (into the HTML) information about the
738
+ // / macro expansions. This won't be perfectly perfect, but it will be
739
+ // / reasonably close.
740
+ void html::HighlightMacros (Rewriter &R, FileID FID, const Preprocessor &PP,
741
+ RelexRewriteCacheRef Cache) {
742
+ if (Cache) {
743
+ auto CacheIt = Cache->MacroHighlights .find (FID);
744
+ if (CacheIt != Cache->MacroHighlights .end ()) {
745
+ for (const RelexRewriteCache::Highlight &H : CacheIt->second ) {
746
+ HighlightRange (R, H.B , H.E , H.StartTag .data (), H.EndTag .data (),
747
+ H.IsTokenRange );
748
+ }
749
+ return ;
750
+ }
751
+ }
752
+
753
+ // "Every time you would call HighlightRange, cache the inputs as well."
754
+ auto HighlightRangeCallback = [&](Rewriter &R, SourceLocation B,
755
+ SourceLocation E, const char *StartTag,
756
+ const char *EndTag, bool isTokenRange) {
757
+ HighlightRange (R, B, E, StartTag, EndTag, isTokenRange);
758
+
759
+ if (Cache) {
760
+ Cache->MacroHighlights [FID].push_back (
761
+ {B, E, StartTag, EndTag, isTokenRange});
762
+ }
763
+ };
764
+
765
+ HighlightMacrosImpl (R, FID, PP, HighlightRangeCallback);
766
+ }
0 commit comments