Explorar el Código

[visual] Skip moving cursor inside argument if there is no decoration (#16365)

* [visual] Skip moving cursor inside argument if there is no decoration

* Refactor skipAtomicRanges function

* rangeSet outside the loop, continue rather than return

* use rangeSet.between

* prettier

GitOrigin-RevId: 85ef817e09ea7eb854cec43cb7866f61b4bfbc21
Domagoj Kriskovic hace 2 años
padre
commit
21a4e0b6b3

+ 2 - 0
services/web/frontend/js/features/source-editor/extensions/visual/atomic-decorations.ts

@@ -67,6 +67,7 @@ import { TableRenderingErrorWidget } from './visual-widgets/table-rendering-erro
 import { GraphicsWidget } from './visual-widgets/graphics'
 import { GraphicsWidget } from './visual-widgets/graphics'
 import { InlineGraphicsWidget } from './visual-widgets/inline-graphics'
 import { InlineGraphicsWidget } from './visual-widgets/inline-graphics'
 import { PreviewPath } from '../../../../../../types/preview-path'
 import { PreviewPath } from '../../../../../../types/preview-path'
+import { selectDecoratedArgument } from './select-decorated-argument'
 import {
 import {
   generateTable,
   generateTable,
   ParsedTableData,
   ParsedTableData,
@@ -1278,6 +1279,7 @@ export const atomicDecorations = (options: Options) => {
             }
             }
           }),
           }),
           skipPreambleWithCursor(field),
           skipPreambleWithCursor(field),
+          selectDecoratedArgument(field),
         ]
         ]
       },
       },
     }),
     }),

+ 45 - 20
services/web/frontend/js/features/source-editor/extensions/visual/select-decorated-argument.ts

@@ -1,4 +1,9 @@
-import { EditorSelection, EditorState, SelectionRange } from '@codemirror/state'
+import {
+  EditorSelection,
+  EditorState,
+  SelectionRange,
+  StateField,
+} from '@codemirror/state'
 import { syntaxTree } from '@codemirror/language'
 import { syntaxTree } from '@codemirror/language'
 import { Tree } from '@lezer/common'
 import { Tree } from '@lezer/common'
 import {
 import {
@@ -6,6 +11,7 @@ import {
   descendantsOfNodeWithType,
   descendantsOfNodeWithType,
 } from '../../utils/tree-operations/ancestors'
 } from '../../utils/tree-operations/ancestors'
 import { getMousedownSelection, selectionIntersects } from './selection'
 import { getMousedownSelection, selectionIntersects } from './selection'
+import { DecorationSet } from '@codemirror/view'
 
 
 /**
 /**
  * A custom extension that updates the selection in a transaction if the mouse pointer was used
  * A custom extension that updates the selection in a transaction if the mouse pointer was used
@@ -13,28 +19,47 @@ import { getMousedownSelection, selectionIntersects } from './selection'
  * or to drag a range across the whole range of an argument (the selection is placed inside the braces),
  * or to drag a range across the whole range of an argument (the selection is placed inside the braces),
  * when the selection was not already inside the command.
  * when the selection was not already inside the command.
  */
  */
-export const selectDecoratedArgument = EditorState.transactionFilter.of(tr => {
-  if (tr.selection && tr.isUserEvent('select.pointer')) {
-    const tree = syntaxTree(tr.state)
-    let selection = tr.selection
-    const mousedownSelection = getMousedownSelection(tr.state)
-    let replaced = false
-    for (const [index, range] of selection.ranges.entries()) {
-      const replacementRange =
-        selectArgument(tree, range, mousedownSelection, 1) ||
-        selectArgument(tree, range, mousedownSelection, -1)
-      if (replacementRange) {
-        selection = selection.replaceRange(replacementRange, index)
-        replaced = true
+export const selectDecoratedArgument = (
+  field: StateField<{ decorations: DecorationSet }>
+) =>
+  EditorState.transactionFilter.of(tr => {
+    if (tr.selection && tr.isUserEvent('select.pointer')) {
+      const tree = syntaxTree(tr.state)
+      let selection = tr.selection
+      const mousedownSelection = getMousedownSelection(tr.state)
+      let replaced = false
+      const rangeSet = tr.state.field(field, false)?.decorations
+      for (const [index, range] of selection.ranges.entries()) {
+        if (rangeSet) {
+          let isAtomicRange = false
+          rangeSet.between(range.anchor, range.anchor, (_from, to) => {
+            if (to > range.anchor) {
+              isAtomicRange = true
+              return false
+            }
+          })
+
+          if (isAtomicRange === false) {
+            // skip since decoration is not covering the selection
+            continue
+          }
+        }
+
+        const replacementRange =
+          selectArgument(tree, range, mousedownSelection, 1) ||
+          selectArgument(tree, range, mousedownSelection, -1)
+        if (replacementRange) {
+          selection = selection.replaceRange(replacementRange, index)
+          replaced = true
+        }
+      }
+      if (replaced) {
+        return [tr, { selection }]
       }
       }
     }
     }
-    if (replaced) {
-      return [tr, { selection }]
-    }
-  }
 
 
-  return tr
-})
+    return tr
+  })
 
 
 const selectArgument = (
 const selectArgument = (
   tree: Tree,
   tree: Tree,

+ 0 - 2
services/web/frontend/js/features/source-editor/extensions/visual/visual.ts

@@ -16,7 +16,6 @@ import { forceParsing, syntaxTree } from '@codemirror/language'
 import { hasLanguageLoadedEffect } from '../language'
 import { hasLanguageLoadedEffect } from '../language'
 import { restoreScrollPosition } from '../scroll-position'
 import { restoreScrollPosition } from '../scroll-position'
 import { listItemMarker } from './list-item-marker'
 import { listItemMarker } from './list-item-marker'
-import { selectDecoratedArgument } from './select-decorated-argument'
 import { pasteHtml } from './paste-html'
 import { pasteHtml } from './paste-html'
 import { commandTooltip } from '../command-tooltip'
 import { commandTooltip } from '../command-tooltip'
 import { tableGeneratorTheme } from './table-generator'
 import { tableGeneratorTheme } from './table-generator'
@@ -193,7 +192,6 @@ const extension = (options: Options) => [
   visualKeymap,
   visualKeymap,
   commandTooltip,
   commandTooltip,
   scrollJumpAdjuster,
   scrollJumpAdjuster,
-  selectDecoratedArgument,
   showContentWhenParsed,
   showContentWhenParsed,
   pasteHtml,
   pasteHtml,
   tableGeneratorTheme,
   tableGeneratorTheme,