mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-08 18:40:35 +00:00
[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:
parent
ec37d70b09
commit
21a4e0b6b3
3 changed files with 47 additions and 22 deletions
|
@ -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),
|
||||
]
|
||||
},
|
||||
}),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue