Răsfoiți Sursa

Merge pull request #27123 from overleaf/ae-goto-scroll-select-text

Highlight double-clicked word when syncing position from PDF to code

GitOrigin-RevId: da120af9dec203346cb85c6aa7e403f4e585c748
Alf Eaton 1 an în urmă
părinte
comite
9958ffdf68

+ 4 - 1
services/web/frontend/js/features/pdf-preview/components/pdf-js-viewer.tsx

@@ -268,7 +268,10 @@ function PdfJsViewer({ url, pdfFile }: PdfJsViewerProps) {
 
               window.dispatchEvent(
                 new CustomEvent('synctex:sync-to-position', {
-                  detail: clickPosition,
+                  detail: {
+                    position: clickPosition,
+                    selectText: window.getSelection()?.toString(),
+                  },
                 })
               )
             }

+ 6 - 6
services/web/frontend/js/features/pdf-preview/hooks/use-synctex.ts

@@ -89,12 +89,13 @@ export default function useSynctex(): {
   }, [dirname, getCurrentDocumentId, pathInFolder, rootDocId])
 
   const goToCodeLine = useCallback(
-    (file?: string, line?: number) => {
+    (file?: string, line?: number, selectText?: string) => {
       if (file) {
         const doc = findEntityByPath(file)?.entity
         if (doc) {
           openDocWithId(doc._id, {
             gotoLine: line,
+            selectText,
           })
           return
         }
@@ -186,9 +187,11 @@ export default function useSynctex(): {
   const _syncToCode = useCallback(
     ({
       position = positionRef.current,
+      selectText,
       visualOffset = 0,
     }: {
       position?: PdfScrollPosition
+      selectText?: string
       visualOffset?: number
     }) => {
       if (!position) {
@@ -231,7 +234,7 @@ export default function useSynctex(): {
       getJSON(`/project/${projectId}/sync/pdf?${params}`, { signal })
         .then(data => {
           const [{ file, line }] = data.code
-          goToCodeLine(file, line)
+          goToCodeLine(file, line, selectText)
           if (data.downloadedFromCache) {
             sendMB('synctex-downloaded-from-cache', {
               projectId,
@@ -266,10 +269,7 @@ export default function useSynctex(): {
 
   useEventListener(
     'synctex:sync-to-position',
-    useCallback(
-      (event: CustomEvent) => syncToCode({ position: event.detail }),
-      [syncToCode]
-    )
+    useCallback((event: CustomEvent) => syncToCode(event.detail), [syncToCode])
   )
 
   const [hasSingleSelectedDoc, setHasSingleSelectedDoc] = useDetachState(

+ 18 - 5
services/web/frontend/js/features/source-editor/extensions/cursor-position.ts

@@ -143,7 +143,7 @@ const dispatchSelectionAndScroll = (
 export const setCursorLineAndScroll = (
   view: EditorView,
   lineNumber: number,
-  columnNumber = 0,
+  columnNumber?: number,
   selectText?: string
 ) => {
   // TODO: map the position through any changes since the previous compile?
@@ -153,10 +153,23 @@ export const setCursorLineAndScroll = (
   const from = findValidPosition(doc, lineNumber, columnNumber)
 
   if (selectText) {
-    const to = from + selectText.length
-    if (doc.sliceString(from, to) === selectText) {
-      dispatchSelectionAndScroll(view, from, to)
-      return
+    if (columnNumber === undefined) {
+      // somewhere on this line
+      const line = doc.lineAt(from)
+      const index = line.text.indexOf(selectText)
+      if (index > -1 && index === line.text.lastIndexOf(selectText)) {
+        const from = line.from + index
+        const to = from + selectText.length
+        dispatchSelectionAndScroll(view, from, to)
+        return
+      }
+    } else {
+      // at this exact position
+      const to = from + selectText.length
+      if (doc.sliceString(from, to) === selectText) {
+        dispatchSelectionAndScroll(view, from, to)
+        return
+      }
     }
   }
 

+ 1 - 1
services/web/frontend/js/features/source-editor/utils/position.ts

@@ -3,7 +3,7 @@ import { Text } from '@codemirror/state'
 export const findValidPosition = (
   doc: Text,
   lineNumber: number, // 1-indexed
-  columnNumber: number // 0-indexed
+  columnNumber = 0 // 0-indexed
 ): number => {
   const lines = doc.lines