@@ -286,7 +286,8 @@ struct SwiftSyntaxMap {
286
286
std::vector<SwiftSyntaxToken> Tokens;
287
287
288
288
SwiftSyntaxMap (unsigned Capacity = 0 ) {
289
- Tokens.reserve (Capacity);
289
+ if (Capacity)
290
+ Tokens.reserve (Capacity);
290
291
}
291
292
292
293
void addToken (const SwiftSyntaxToken &Token) {
@@ -313,16 +314,32 @@ struct SwiftSyntaxMap {
313
314
});
314
315
}
315
316
316
- void adjustForReplacement (unsigned Offset, unsigned Len, unsigned NewLen) {
317
- unsigned EndOffset = Offset + Len;
317
+ SwiftEditorCharRange
318
+ adjustForReplacement (unsigned Offset, unsigned Len, unsigned NewLen) {
319
+ unsigned AffectedStart = Offset;
320
+ unsigned AffectedEnd = Offset + Len;
321
+
318
322
for (auto &Token: Tokens) {
319
- if (Token.Offset > EndOffset) {
323
+ if (Token.endOffset () <= AffectedStart)
324
+ continue ; // Completely before
325
+
326
+ if (Token.Offset >= AffectedEnd) {
320
327
Token.Offset += NewLen - Len;
321
- } else if (Token.endOffset () > Offset) {
322
- Token.Offset = Offset;
323
- Token.Length = 0 ;
328
+ continue ; // Completely after
324
329
}
330
+
331
+ if (Token.Offset < AffectedStart)
332
+ AffectedStart = Token.Offset ;
333
+ if (Token.endOffset () > AffectedEnd)
334
+ AffectedEnd = Token.endOffset ();
335
+
336
+ Token.Length = 0 ; // Forces a mismatch - no new token has length 0
325
337
}
338
+
339
+ // Adjust for the change in length
340
+ AffectedEnd += NewLen - Len;
341
+
342
+ return {AffectedStart, AffectedEnd - AffectedStart};
326
343
}
327
344
328
345
void forEach (EditorConsumer &Consumer) {
@@ -332,23 +349,24 @@ struct SwiftSyntaxMap {
332
349
}
333
350
}
334
351
335
- SwiftEditorCharRange forEachChanged (SwiftSyntaxMap &Prev,
336
- StringRef BufferText,
337
- EditorConsumer &Consumer) const {
338
- unsigned StartOffset = BufferText.size (), EndOffset = 0 ;
352
+ // / Returns true if there were changes
353
+ bool forEachChanged (SwiftSyntaxMap &Prev,
354
+ SwiftEditorCharRange &Affected,
355
+ StringRef BufferText,
356
+ EditorConsumer &Consumer) const {
357
+ unsigned StartOffset = Affected.Offset , EndOffset = Affected.endOffset ();
339
358
340
359
// Find the first tokens that don't match
341
360
auto Start = std::make_pair (Tokens.begin (), Prev.Tokens .begin ());
342
361
while (Start.first != Tokens.end () && Start.second != Prev.Tokens .end () &&
343
362
*Start.first == *Start.second )
344
363
++Start.first , ++Start.second ;
345
364
346
- if (Start.first != Tokens.end ())
365
+ if (Start.first != Tokens.end ()) {
347
366
StartOffset = std::min (Start.first ->Offset , StartOffset);
348
- if (Start.second != Prev.Tokens .end ())
349
- StartOffset = std::min (Start.second ->Offset , StartOffset);
350
- if (StartOffset == BufferText.size ()) // No differences
351
- return {0 , 0 };
367
+ } else if (Start.second == Prev.Tokens .end ()) {
368
+ return false ; // Both sets are identical
369
+ }
352
370
353
371
// Find the last tokens that don't match
354
372
auto End = std::make_pair (Tokens.rbegin (), Prev.Tokens .rbegin ());
@@ -358,16 +376,20 @@ struct SwiftSyntaxMap {
358
376
359
377
if (End.first != Tokens.rend ())
360
378
EndOffset = std::max (End.first ->endOffset (), EndOffset);
361
- if (End.second != Prev.Tokens .rend ())
362
- EndOffset = std::max (End.second ->endOffset (), EndOffset);
379
+
363
380
assert (EndOffset >= StartOffset);
364
381
365
382
// Adjust offsets to line boundaries
366
- StartOffset = getLineBoundary (BufferText, StartOffset, /* Start=*/ true );
367
- EndOffset = getLineBoundary (BufferText, EndOffset, /* Start=*/ false );
368
-
369
- if (Start.first == Tokens.end ()) // No tokens to return
370
- return {StartOffset, EndOffset - StartOffset};
383
+ StartOffset = getPrevLineBoundary (BufferText, StartOffset);
384
+ EndOffset = getNextLineBoundary (BufferText, EndOffset,
385
+ /* hasLength=*/ StartOffset < EndOffset);
386
+
387
+ if (Start.first == Tokens.end ()) {
388
+ // No tokens to return
389
+ Affected.Offset = StartOffset;
390
+ Affected.Length = EndOffset - StartOffset;
391
+ return true ;
392
+ }
371
393
372
394
auto From = Start.first ;
373
395
auto To = End.first ;
@@ -380,7 +402,7 @@ struct SwiftSyntaxMap {
380
402
if (Prev->endOffset () <= StartOffset)
381
403
break ;
382
404
// Multi-line token – move to previous line
383
- StartOffset = getLineBoundary (BufferText, Prev->Offset , /* Start= */ true );
405
+ StartOffset = getPrevLineBoundary (BufferText, Prev->Offset );
384
406
From = Prev;
385
407
};
386
408
@@ -391,7 +413,7 @@ struct SwiftSyntaxMap {
391
413
if (Prev->Offset >= EndOffset)
392
414
break ;
393
415
// Multi-line token – move to next line
394
- EndOffset = getLineBoundary (BufferText, Prev->endOffset (), /* Start= */ false );
416
+ EndOffset = getNextLineBoundary (BufferText, Prev->endOffset (), true );
395
417
To = Prev;
396
418
}
397
419
@@ -401,14 +423,23 @@ struct SwiftSyntaxMap {
401
423
Consumer.handleSyntaxMap (From->Offset , From->Length , Kind);
402
424
}
403
425
404
- return {StartOffset, EndOffset - StartOffset};
426
+ Affected.Offset = StartOffset;
427
+ Affected.Length = EndOffset - StartOffset;
428
+ return true ;
405
429
}
406
430
407
431
private:
408
- static size_t getLineBoundary (StringRef Text, size_t Offset, bool Start) {
409
- auto Bound = Start? Text.rfind (' \n ' , Offset) : Text.find (' \n ' , Offset - 1 );
432
+ static size_t getPrevLineBoundary (StringRef Text, size_t Offset) {
433
+ auto Bound = Text.rfind (' \n ' , Offset);
434
+ if (Bound == StringRef::npos)
435
+ return 0 ;
436
+ return Bound + 1 ;
437
+ }
438
+
439
+ static size_t getNextLineBoundary (StringRef Text, size_t Offset, bool hasLength) {
440
+ auto Bound = Text.find (' \n ' , hasLength? Offset - 1 : Offset);
410
441
if (Bound == StringRef::npos)
411
- return Start? 0 : Text.size ();
442
+ return Text.size ();
412
443
return Bound + 1 ;
413
444
}
414
445
};
@@ -1593,7 +1624,7 @@ ImmutableTextSnapshotRef SwiftEditorDocument::initializeText(
1593
1624
new EditableTextBuffer (Impl.FilePath , Buf->getBuffer ());
1594
1625
Impl.SyntaxMap .Tokens .clear ();
1595
1626
Impl.Edited = false ;
1596
- Impl.AffectedRange = {0 , ( unsigned ) Buf->getBufferSize ()};
1627
+ Impl.AffectedRange = {0 , Buf->getBufferSize ()};
1597
1628
Impl.SemanticInfo =
1598
1629
new SwiftDocumentSemanticInfo (Impl.FilePath , Impl.LangSupport );
1599
1630
Impl.SemanticInfo ->setCompilerArgs (Args);
@@ -1633,19 +1664,8 @@ ImmutableTextSnapshotRef SwiftEditorDocument::replaceText(
1633
1664
}
1634
1665
1635
1666
// update the old syntax data offsets to account for the replaced range
1636
- Impl.SyntaxMap .adjustForReplacement (Offset, Length, Str.size ());
1667
+ Impl.AffectedRange = Impl. SyntaxMap .adjustForReplacement (Offset, Length, Str.size ());
1637
1668
ImmutableTextBufferRef ImmBuf = Snapshot->getBuffer ();
1638
-
1639
- // The affected range starts from the previous newline.
1640
- if (Offset > 0 ) {
1641
- auto AffectedRangeOffset = ImmBuf->getText ().rfind (' \n ' , Offset);
1642
- Impl.AffectedRange .Offset =
1643
- AffectedRangeOffset != StringRef::npos ? AffectedRangeOffset + 1 : 0 ;
1644
- }
1645
- else
1646
- Impl.AffectedRange .Offset = 0 ;
1647
-
1648
- Impl.AffectedRange .Length = ImmBuf->getText ().size () - Impl.AffectedRange .Offset ;
1649
1669
Impl.Edited = true ;
1650
1670
1651
1671
return Snapshot;
@@ -1707,19 +1727,20 @@ void SwiftEditorDocument::readSyntaxInfo(EditorConsumer &Consumer) {
1707
1727
Impl.SyntaxInfo ->getBufferID ());
1708
1728
ModelContext.walk (SyntaxWalker);
1709
1729
1730
+ bool SawChanges = true ;
1710
1731
if (Impl.Edited ) {
1711
1732
auto Text = Impl.EditableBuffer ->getBuffer ()->getText ();
1712
- auto AffectedRange = NewMap.forEachChanged (Impl.SyntaxMap , Text, Consumer);
1713
- Impl. AffectedRange = AffectedRange ;
1733
+ SawChanges = NewMap.forEachChanged (Impl.SyntaxMap , Impl. AffectedRange , Text,
1734
+ Consumer) ;
1714
1735
} else {
1715
1736
NewMap.forEach (Consumer);
1716
1737
}
1717
- Impl.SyntaxMap = NewMap;
1738
+ Impl.SyntaxMap = std::move ( NewMap) ;
1718
1739
1719
1740
// Recording an affected length of 0 still results in the client updating its
1720
1741
// copy of the syntax map (by clearning all tokens on the line of the affected
1721
1742
// offset). We need to not record it at all to signal a no-op.
1722
- if (!Impl. AffectedRange . isEmpty () )
1743
+ if (SawChanges )
1723
1744
Consumer.recordAffectedRange (Impl.AffectedRange .Offset ,
1724
1745
Impl.AffectedRange .Length );
1725
1746
}
0 commit comments