HighlightedWordManager.coffee 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. define () ->
  2. class Highlight
  3. constructor: (options) ->
  4. @row = options.row
  5. @column = options.column
  6. @word = options.word
  7. @suggestions = options.suggestions
  8. class HighlightedWordManager
  9. constructor: (@ide) ->
  10. @highlights = rows: []
  11. addHighlight: (highlight) ->
  12. unless highlight instanceof Highlight
  13. highlight = new Highlight(highlight)
  14. highlight.markerId = @ide.editor.addMarker {
  15. row: highlight.row
  16. column: highlight.column
  17. length: highlight.word.length
  18. }, "sharelatex-spelling-highlight"
  19. @highlights.rows[highlight.row] ||= []
  20. @highlights.rows[highlight.row].push highlight
  21. removeHighlight: (highlight) ->
  22. @ide.editor.removeMarker(highlight.markerId)
  23. for h, i in @highlights.rows[highlight.row]
  24. if h == highlight
  25. @highlights.rows[highlight.row].splice(i, 1)
  26. removeWord: (word) ->
  27. toRemove = []
  28. for row in @highlights.rows
  29. for highlight in (row || [])
  30. if highlight.word == word
  31. toRemove.push(highlight)
  32. for highlight in toRemove
  33. @removeHighlight highlight
  34. moveHighlight: (highlight, position) ->
  35. @removeHighlight highlight
  36. highlight.row = position.row
  37. highlight.column = position.column
  38. @addHighlight highlight
  39. clearRows: (from, to) ->
  40. from ||= 0
  41. to ||= @highlights.rows.length - 1
  42. for row in @highlights.rows.slice(from, to + 1)
  43. for highlight in (row || []).slice(0)
  44. @removeHighlight highlight
  45. insertRows: (offset, number) ->
  46. # rows are inserted after offset. i.e. offset row is not modified
  47. affectedHighlights = []
  48. for row in @highlights.rows.slice(offset)
  49. affectedHighlights.push(highlight) for highlight in (row || [])
  50. for highlight in affectedHighlights
  51. @moveHighlight highlight,
  52. row: highlight.row + number
  53. column: highlight.column
  54. removeRows: (offset, number) ->
  55. # offset is the first row to delete
  56. affectedHighlights = []
  57. for row in @highlights.rows.slice(offset)
  58. affectedHighlights.push(highlight) for highlight in (row || [])
  59. for highlight in affectedHighlights
  60. if highlight.row >= offset + number
  61. @moveHighlight highlight,
  62. row: highlight.row - number
  63. column: highlight.column
  64. else
  65. @removeHighlight highlight
  66. findHighlightWithinRange: (range) ->
  67. rows = @highlights.rows.slice(range.start.row, range.end.row + 1)
  68. for row in rows
  69. for highlight in (row || [])
  70. if @_doesHighlightOverlapRange(highlight, range.start, range.end)
  71. return highlight
  72. return null
  73. applyChange: (change) ->
  74. start = change.range.start
  75. end = change.range.end
  76. if change.action == "insertText"
  77. if start.row != end.row
  78. rowsAdded = end.row - start.row
  79. @insertRows start.row + 1, rowsAdded
  80. # make a copy since we're going to modify in place
  81. oldHighlights = (@highlights.rows[start.row] || []).slice(0)
  82. for highlight in oldHighlights
  83. if highlight.column > start.column
  84. # insertion was fully before this highlight
  85. @moveHighlight highlight,
  86. row: end.row
  87. column: highlight.column + (end.column - start.column)
  88. else if highlight.column + highlight.word.length >= start.column
  89. # insertion was inside this highlight
  90. @removeHighlight highlight
  91. else if change.action == "insertLines"
  92. @insertRows start.row, change.lines.length
  93. else if change.action == "removeText"
  94. if start.row == end.row
  95. oldHighlights = (@highlights.rows[start.row] || []).slice(0)
  96. else
  97. rowsRemoved = end.row - start.row
  98. oldHighlights =
  99. (@highlights.rows[start.row] || []).concat(
  100. (@highlights.rows[end.row] || [])
  101. )
  102. @removeRows start.row + 1, rowsRemoved
  103. for highlight in oldHighlights
  104. if @_doesHighlightOverlapRange highlight, start, end
  105. @removeHighlight highlight
  106. else if @_isHighlightAfterRange highlight, start, end
  107. @moveHighlight highlight,
  108. row: start.row
  109. column: highlight.column - (end.column - start.column)
  110. else if change.action == "removeLines"
  111. @removeRows start.row, change.lines.length
  112. _doesHighlightOverlapRange: (highlight, start, end) ->
  113. highlightIsAllBeforeRange =
  114. highlight.row < start.row or
  115. (highlight.row == start.row and highlight.column + highlight.word.length <= start.column)
  116. highlightIsAllAfterRange =
  117. highlight.row > end.row or
  118. (highlight.row == end.row and highlight.column >= end.column)
  119. !(highlightIsAllBeforeRange or highlightIsAllAfterRange)
  120. _isHighlightAfterRange: (highlight, start, end) ->
  121. return true if highlight.row > end.row
  122. return false if highlight.row < end.row
  123. highlight.column >= end.column