[cm6+rt] getParentNode account for commands with arguments (#13345)

* [cm6+rt] getParentNode account for commands with arguments

* add explanation comment

* added test

* prettier

* check commandAncestor in same position

* using ancestorOfNodeWithToRange

* function rename

GitOrigin-RevId: bb837d956d029c1026dab03825634f24d5bc3905
This commit is contained in:
Domagoj Kriskovic 2023-06-19 13:23:47 +02:00 committed by Copybot
parent 1f5c4c1c9c
commit 98aa084089
3 changed files with 35 additions and 13 deletions

View file

@ -11,6 +11,7 @@ import {
ancestorOfNodeWithType,
isUnknownCommandWithName,
} from '../utils/tree-query'
import { lastAncestorAtEndPosition } from '../utils/tree-operations/ancestors'
export const wrapRanges =
(
@ -216,19 +217,10 @@ function getParentNode(
let node: SyntaxNode | undefined | null = null
if (typeof position === 'number') {
node = tree?.resolveInner(position, assoc)?.parent
// HACK: Spaces after UnknownCommands (and other commands without arguments)
// are included in the Command node. So we have to adjust for that here.
const preceedingCharacter = state.sliceDoc(
Math.max(0, position - 1),
position
)
if (
preceedingCharacter === ' ' &&
['UnknownCommand', 'Item', 'Left', 'Right'].some(name =>
node?.type.is(name)
)
) {
node = ancestorOfNodeWithType(node, 'Command')?.parent
const ancestorAtEndPos = lastAncestorAtEndPosition(node, position)
if (ancestorAtEndPos?.parent) {
node = ancestorAtEndPos.parent
}
} else {
node = position?.parent

View file

@ -99,6 +99,20 @@ export const ancestorOfNodeWithType = (
return null
}
export const lastAncestorAtEndPosition = (
node: SyntaxNode | null | undefined,
to: number
): SyntaxNode | null => {
for (let ancestor = node; ancestor; ancestor = ancestor.parent) {
if (ancestor.parent?.to === to) {
continue
} else if (ancestor.to === to) {
return ancestor
}
}
return null
}
export const descendantsOfNodeWithType = (
node: SyntaxNode,
type: string | number,

View file

@ -178,6 +178,22 @@ describe('toggleRanges', function () {
cm.applyCommand(BOLD_COMMAND)
expect(cm).line(1).to.equal('\\noindent \\textbf{<My paragraph>}')
})
it('still formats after unknown command with arguments', function () {
const cm = new CodemirrorTestSession(['\\foo{test}<My paragraph>'])
cm.applyCommand(BOLD_COMMAND)
expect(cm).line(1).to.equal('\\foo{test}\\textbf{<My paragraph>}')
})
it('still formats after known command with arguments', function () {
const cm1 = new CodemirrorTestSession(['\\cite{foo}<text>'])
cm1.applyCommand(BOLD_COMMAND)
expect(cm1).line(1).to.equal('\\cite{foo}\\textbf{<text>}')
const cm2 = new CodemirrorTestSession(['\\href{url}{title}<text>'])
cm2.applyCommand(BOLD_COMMAND)
expect(cm2).line(1).to.equal('\\href{url}{title}\\textbf{<text>}')
})
})
})
})