[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
This commit is contained in:
Domagoj Kriskovic 2024-01-15 10:02:38 +01:00 committed by Copybot
parent ec37d70b09
commit 21a4e0b6b3
3 changed files with 47 additions and 22 deletions

View file

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

View file

@ -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 { Tree } from '@lezer/common'
import {
@ -6,6 +11,7 @@ import {
descendantsOfNodeWithType,
} from '../../utils/tree-operations/ancestors'
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
@ -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),
* 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 = (
tree: Tree,

View file

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