فهرست منبع

Merge pull request #10111 from overleaf/mj-lezer-file-outline

[web] Parser backed file outline

GitOrigin-RevId: 0825f4887ba4dae24a14dd1880d07b791d0b4cd9
Mathias Jakobsen 4 سال پیش
والد
کامیت
a54b633726

+ 1 - 0
services/web/app/views/project/editor/file-tree-react.pug

@@ -34,4 +34,5 @@ aside.editor-sidebar.full-size(
 			on-toggle="onToggle"
 			event-tracking="eventTracking"
 			highlighted-line="highlightedLine"
+			show="show"
 		)

+ 1 - 0
services/web/cypress/support/ct/window.ts

@@ -1,4 +1,5 @@
 window.i18n = { currentLangCode: 'en' }
 window.ExposedSettings = {
   appName: 'Overleaf',
+  validRootDocExtensions: ['tex', 'Rtex', 'ltx'],
 } as typeof window.ExposedSettings

+ 3 - 0
services/web/frontend/js/features/outline/components/outline-item.js

@@ -107,6 +107,9 @@ OutlineItem.propTypes = {
     title: PropTypes.string.isRequired,
     level: PropTypes.number,
     children: PropTypes.array,
+    // Used for caching in CM6
+    from: PropTypes.number,
+    to: PropTypes.number,
   }).isRequired,
   jumpToLine: PropTypes.func.isRequired,
   highlightedLine: PropTypes.number,

+ 8 - 0
services/web/frontend/js/features/outline/components/outline-pane.js

@@ -16,6 +16,7 @@ const OutlinePane = React.memo(function OutlinePane({
   onToggle,
   eventTracking,
   highlightedLine,
+  show,
 }) {
   const { t } = useTranslation()
 
@@ -46,6 +47,12 @@ const OutlinePane = React.memo(function OutlinePane({
     }
   }
 
+  // NOTE: This flag is for disabling the rendering of the component. Used while
+  // both an Angular and React-based file outline is present in the code base.
+  if (!show) {
+    return null
+  }
+
   return (
     <div className={headerClasses}>
       <header className="outline-header">
@@ -82,6 +89,7 @@ OutlinePane.propTypes = {
   onToggle: PropTypes.func.isRequired,
   eventTracking: PropTypes.object.isRequired,
   highlightedLine: PropTypes.number,
+  show: PropTypes.bool.isRequired,
 }
 
 export default withErrorBoundary(OutlinePane)

+ 18 - 0
services/web/frontend/js/features/outline/controllers/outline-controller.js

@@ -8,6 +8,23 @@ App.controller('OutlineController', function ($scope, ide, eventTracking) {
   $scope.outline = []
   $scope.eventTracking = eventTracking
 
+  function shouldShowOutline() {
+    if ($scope.editor.showRichText) {
+      return true
+    }
+    return !$scope.editor.newSourceEditor
+  }
+
+  $scope.show = shouldShowOutline()
+
+  $scope.$watch('editor.newSourceEditor', function () {
+    $scope.show = shouldShowOutline()
+  })
+
+  $scope.$watch('editor.showRichText', function () {
+    $scope.show = shouldShowOutline()
+  })
+
   $scope.$on('outline-manager:outline-changed', onOutlineChange)
 
   function onOutlineChange(e, outlineInfo) {
@@ -40,5 +57,6 @@ App.component(
     'eventTracking',
     'onToggle',
     'isTexFile',
+    'show',
   ])
 )

+ 26 - 0
services/web/frontend/js/features/outline/outline-manager.js

@@ -16,6 +16,13 @@ class OutlineManager {
     this.ignoreNextScroll = false
     this.ignoreNextCursorUpdate = false
 
+    scope.$watch('editor.newSourceEditor', (now, before) => {
+      if (before && !now) {
+        this.updateOutline()
+        this.broadcastChangeEvent()
+      }
+    })
+
     scope.$on('doc:after-opened', (ev, { isNewDoc }) => {
       if (isNewDoc) {
         // if a new doc is opened a cursor updates will be triggered before the
@@ -65,10 +72,25 @@ class OutlineManager {
     scope.$watch('editor.showRichText', () => {
       this.ignoreNextScroll = true
       this.ignoreNextCursorUpdate = true
+      if (this.shouldShowOutline()) {
+        this.updateOutline()
+        this.broadcastChangeEvent()
+      }
     })
   }
 
+  shouldShowOutline() {
+    if (this.scope.editor.showRichText) {
+      return true
+    }
+    return !this.scope.editor.newSourceEditor
+  }
+
   updateOutline() {
+    // Disable if using CM6
+    if (!this.shouldShowOutline()) {
+      return
+    }
     if (this.isTexFile) {
       const content = this.ide.editorManager.getCurrentDocValue()
       if (content) {
@@ -103,6 +125,10 @@ class OutlineManager {
   }
 
   broadcastChangeEvent() {
+    // Disable if using CM6
+    if (!this.shouldShowOutline()) {
+      return
+    }
     this.scope.$broadcast('outline-manager:outline-changed', {
       isTexFile: this.isTexFile,
       outline: this.outline,

+ 1 - 1
services/web/frontend/js/ide/editor/EditorManager.js

@@ -231,7 +231,7 @@ export default EditorManager = (function () {
       const done = isNewDoc => {
         const eventName = 'doc:after-opened'
         this.$scope.$broadcast(eventName, { isNewDoc })
-        window.dispatchEvent(new CustomEvent(eventName, { isNewDoc }))
+        window.dispatchEvent(new CustomEvent(eventName, { detail: isNewDoc }))
         if (options.gotoLine != null) {
           // allow Ace to display document before moving, delay until next tick
           // added delay to make this happen later that gotoStoredPosition in

+ 18 - 0
services/web/frontend/js/shared/hooks/use-deep-compare-memo.ts

@@ -0,0 +1,18 @@
+import { DependencyList, useMemo, useRef } from 'react'
+import { isEqual } from 'lodash'
+
+function useDeepCompare(dependencies: DependencyList) {
+  const ref = useRef<DependencyList>([])
+  if (!isEqual(ref.current, dependencies)) {
+    ref.current = dependencies
+  }
+  return ref.current
+}
+
+export default function useDeepCompareMemo<T>(
+  factory: () => T,
+  dependencies: DependencyList
+) {
+  // eslint-disable-next-line react-hooks/exhaustive-deps
+  return useMemo(factory, useDeepCompare(dependencies))
+}

+ 3 - 3
services/web/frontend/js/shared/hooks/use-scope-event-emitter.js

@@ -10,11 +10,11 @@ export default function useScopeEventEmitter(eventName, broadcast = true) {
   const { $scope } = useIdeContext()
 
   return useCallback(
-    detail => {
+    (...detail) => {
       if (broadcast) {
-        $scope.$broadcast(eventName, detail)
+        $scope.$broadcast(eventName, ...detail)
       } else {
-        $scope.$emit(eventName, detail)
+        $scope.$emit(eventName, ...detail)
       }
     },
     [$scope, eventName, broadcast]

+ 3 - 0
services/web/test/frontend/features/outline/components/outline-pane.test.js

@@ -55,6 +55,7 @@ describe('<OutlinePane />', function () {
         jumpToLine={jumpToLine}
         onToggle={onToggle}
         eventTracking={eventTracking}
+        show
       />
     )
 
@@ -70,6 +71,7 @@ describe('<OutlinePane />', function () {
         jumpToLine={jumpToLine}
         onToggle={onToggle}
         eventTracking={eventTracking}
+        show
       />
     )
 
@@ -98,6 +100,7 @@ describe('<OutlinePane />', function () {
         jumpToLine={jumpToLine}
         onToggle={onToggle}
         eventTracking={eventTracking}
+        show
       />
     )