outline-manager.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import { isEqual, cloneDeep } from 'lodash'
  2. import './controllers/outline-controller'
  3. import { matchOutline, nestOutline } from './outline-parser'
  4. import isValidTeXFile from '../../main/is-valid-tex-file'
  5. class OutlineManager {
  6. constructor(ide, scope) {
  7. this.ide = ide
  8. this.scope = scope
  9. this.shareJsDoc = null
  10. this.isTexFile = false
  11. this.flatOutline = []
  12. this.previousFlatOutline = []
  13. this.outline = []
  14. this.highlightedLine = null
  15. this.ignoreNextScroll = false
  16. this.ignoreNextCursorUpdate = false
  17. scope.$watch('editor.newSourceEditor', (now, before) => {
  18. if (before && !now) {
  19. this.updateOutline()
  20. this.broadcastChangeEvent()
  21. }
  22. })
  23. scope.$on('doc:after-opened', (ev, { isNewDoc }) => {
  24. if (isNewDoc) {
  25. // if a new doc is opened a cursor updates will be triggered before the
  26. // content is loaded. We have to ignore it or the outline highlight
  27. // will be incorrect. This doesn't happen when `doc:after-opened` is
  28. // fired without a new doc opened.
  29. this.ignoreNextCursorUpdate = true
  30. }
  31. // always ignore the next scroll update so the cursor update takes
  32. // precedence
  33. this.ignoreNextScroll = true
  34. this.shareJsDoc = scope.editor.sharejs_doc
  35. this.isTexFile = isValidTeXFile(scope.editor.open_doc_name)
  36. this.updateOutline()
  37. this.broadcastChangeEvent()
  38. })
  39. scope.$on('doc:changed', () => {
  40. this.updateOutline()
  41. this.broadcastChangeEvent()
  42. })
  43. scope.$on('file-view:file-opened', () => {
  44. this.isTexFile = false
  45. this.updateOutline()
  46. this.broadcastChangeEvent()
  47. })
  48. scope.$on('cursor:editor:update', (event, cursorPosition) => {
  49. if (this.ignoreNextCursorUpdate) {
  50. this.ignoreNextCursorUpdate = false
  51. return
  52. }
  53. this.updateHighlightedLine(cursorPosition.row + 1)
  54. this.broadcastChangeEvent()
  55. })
  56. scope.$on('scroll:editor:update', (event, middleVisibleRow) => {
  57. if (this.ignoreNextScroll) {
  58. this.ignoreNextScroll = false
  59. return
  60. }
  61. this.updateHighlightedLine(middleVisibleRow + 1)
  62. })
  63. }
  64. shouldShowOutline() {
  65. return !this.scope.editor.newSourceEditor
  66. }
  67. updateOutline() {
  68. // Disable if using CM6
  69. if (!this.shouldShowOutline()) {
  70. return
  71. }
  72. if (this.isTexFile) {
  73. const content = this.ide.editorManager.getCurrentDocValue()
  74. if (content) {
  75. this.flatOutline = matchOutline(content)
  76. if (!isEqual(this.flatOutline, this.previousFlatOutline)) {
  77. this.previousFlatOutline = cloneDeep(this.flatOutline)
  78. this.outline = nestOutline(this.flatOutline)
  79. }
  80. return
  81. }
  82. }
  83. this.previousFlatOutline = []
  84. this.outline = []
  85. }
  86. // set highlightedLine to the closest outline line above the editorLine
  87. updateHighlightedLine(editorLine) {
  88. let closestOutlineLine = null
  89. for (let lineId = 0; lineId < this.flatOutline.length; lineId++) {
  90. const outline = this.flatOutline[lineId]
  91. if (editorLine < outline.line) break // editorLine is above
  92. closestOutlineLine = outline.line
  93. }
  94. if (closestOutlineLine === this.highlightedLine) return
  95. this.highlightedLine = closestOutlineLine
  96. this.broadcastChangeEvent()
  97. }
  98. jumpToLine(line, syncToPdf) {
  99. this.ignoreNextScroll = true
  100. this.ide.editorManager.jumpToLine({ gotoLine: line, syncToPdf })
  101. }
  102. broadcastChangeEvent() {
  103. // Disable if using CM6
  104. if (!this.shouldShowOutline()) {
  105. return
  106. }
  107. this.scope.$broadcast('outline-manager:outline-changed', {
  108. isTexFile: this.isTexFile,
  109. outline: this.outline,
  110. highlightedLine: this.highlightedLine,
  111. })
  112. }
  113. }
  114. export default OutlineManager