outline-manager.js 3.2 KB

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