diff_delta.dart 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import 'dart:math' as math;
  2. import '../models/quill_delta.dart';
  3. const Set<int> WHITE_SPACE = {
  4. 0x9,
  5. 0xA,
  6. 0xB,
  7. 0xC,
  8. 0xD,
  9. 0x1C,
  10. 0x1D,
  11. 0x1E,
  12. 0x1F,
  13. 0x20,
  14. 0xA0,
  15. 0x1680,
  16. 0x2000,
  17. 0x2001,
  18. 0x2002,
  19. 0x2003,
  20. 0x2004,
  21. 0x2005,
  22. 0x2006,
  23. 0x2007,
  24. 0x2008,
  25. 0x2009,
  26. 0x200A,
  27. 0x202F,
  28. 0x205F,
  29. 0x3000
  30. };
  31. // Diff between two texts - old text and new text
  32. class Diff {
  33. Diff(this.start, this.deleted, this.inserted);
  34. // Start index in old text at which changes begin.
  35. final int start;
  36. /// The deleted text
  37. final String deleted;
  38. // The inserted text
  39. final String inserted;
  40. @override
  41. String toString() {
  42. return 'Diff[$start, "$deleted", "$inserted"]';
  43. }
  44. }
  45. /* Get diff operation between old text and new text */
  46. Diff getDiff(String oldText, String newText, int cursorPosition) {
  47. var end = oldText.length;
  48. final delta = newText.length - end;
  49. for (final limit = math.max(0, cursorPosition - delta);
  50. end > limit && oldText[end - 1] == newText[end + delta - 1];
  51. end--) {}
  52. var start = 0;
  53. for (final startLimit = cursorPosition - math.max(0, delta);
  54. start < startLimit && oldText[start] == newText[start];
  55. start++) {}
  56. final deleted = (start >= end) ? '' : oldText.substring(start, end);
  57. final inserted = newText.substring(start, end + delta);
  58. return Diff(start, deleted, inserted);
  59. }
  60. int getPositionDelta(Delta user, Delta actual) {
  61. if (actual.isEmpty) {
  62. return 0;
  63. }
  64. final userItr = DeltaIterator(user);
  65. final actualItr = DeltaIterator(actual);
  66. var diff = 0;
  67. while (userItr.hasNext || actualItr.hasNext) {
  68. final length = math.min(userItr.peekLength(), actualItr.peekLength());
  69. final userOperation = userItr.next(length);
  70. final actualOperation = actualItr.next(length);
  71. if (userOperation.length != actualOperation.length) {
  72. throw 'userOp ${userOperation.length} does not match actualOp '
  73. '${actualOperation.length}';
  74. }
  75. if (userOperation.key == actualOperation.key) {
  76. continue;
  77. } else if (userOperation.isInsert && actualOperation.isRetain) {
  78. diff -= userOperation.length!;
  79. } else if (userOperation.isDelete && actualOperation.isRetain) {
  80. diff += userOperation.length!;
  81. } else if (userOperation.isRetain && actualOperation.isInsert) {
  82. String? operationTxt = '';
  83. if (actualOperation.data is String) {
  84. operationTxt = actualOperation.data as String?;
  85. }
  86. if (operationTxt!.startsWith('\n')) {
  87. continue;
  88. }
  89. diff += actualOperation.length!;
  90. }
  91. }
  92. return diff;
  93. }