Merge pull request #12696 from overleaf/mj-rt-skip-more-preamble

[cm6+rt] Update skip-preamble-cursor to skip \maketitle and abstract

GitOrigin-RevId: 3c54d8159bfdb431763872790a2b82ac4cffc09f
This commit is contained in:
Mathias Jakobsen 2023-04-20 10:59:43 +01:00 committed by Copybot
parent 59b3b9b933
commit 3bd174631a
5 changed files with 90 additions and 29 deletions

View file

@ -731,6 +731,23 @@ export const atomicDecorations = (options: Options) => {
return false
}
}
} else if (nodeRef.type.is('Maketitle')) {
if (shouldDecorate(state, nodeRef)) {
const line = state.doc.lineAt(nodeRef.from)
const from = extendBackwardsOverEmptyLines(state.doc, line)
const to = extendForwardsOverEmptyLines(state.doc, line)
if (shouldDecorate(state, { from, to })) {
decorations.push(
Decoration.replace({
widget: new MakeTitleWidget(preamble),
block: true,
}).range(from, to)
)
}
return false
}
} else if (nodeRef.type.is('Item')) {
// only decorate \item inside a list
if (currentListEnvironment) {
@ -823,23 +840,6 @@ export const atomicDecorations = (options: Options) => {
widget: new TeXWidget(),
}).range(nodeRef.from, nodeRef.to)
)
return false
}
} else if (commandName === '\\maketitle') {
if (shouldDecorate(state, nodeRef)) {
const line = state.doc.lineAt(nodeRef.from)
const from = extendBackwardsOverEmptyLines(state.doc, line)
const to = extendForwardsOverEmptyLines(state.doc, line)
if (shouldDecorate(state, { from, to })) {
decorations.push(
Decoration.replace({
widget: new MakeTitleWidget(preamble),
block: true,
}).range(from, to)
)
}
return false
}
} else if (hasCharacterSubstitution(commandName)) {

View file

@ -1,7 +1,8 @@
import { EditorView, ViewPlugin } from '@codemirror/view'
import { EditorSelection } from '@codemirror/state'
import { findDocumentEnvironment } from '../../utils/tree-operations/environments'
import { findStartOfDocumentContent } from '../../utils/tree-operations/environments'
import { syntaxTree } from '@codemirror/language'
import { extendForwardsOverEmptyLines } from './selection'
export const skipPreambleWithCursor = ViewPlugin.define((view: EditorView) => {
let checkedOnce = false
return {
@ -21,10 +22,16 @@ export const skipPreambleWithCursor = ViewPlugin.define((view: EditorView) => {
)
) {
setTimeout(() => {
const position = findDocumentEnvironment(view.state)
const position =
extendForwardsOverEmptyLines(
update.state.doc,
update.state.doc.lineAt(
findStartOfDocumentContent(update.state) ?? 0
)
) + 1
view.dispatch({
selection: EditorSelection.cursor(
Math.min(position ? position + 1 : 0, update.state.doc.length)
Math.min(position, update.state.doc.length)
),
})
}, 0)

View file

@ -84,7 +84,8 @@
CenteringCtrlSeq,
BibliographyCtrlSeq,
BibliographyStyleCtrlSeq,
AuthorCtrlSeq
AuthorCtrlSeq,
MaketitleCtrlSeq
}
@external specialize {EnvName} specializeEnvName from "./tokens.mjs" {
@ -310,6 +311,9 @@ KnownCommand {
} |
Item {
ItemCtrlSeq optionalWhitespace?
} |
Maketitle {
MaketitleCtrlSeq optionalWhitespace?
}
}

View file

@ -65,6 +65,7 @@ import {
BibliographyStyleCtrlSeq,
CenteringCtrlSeq,
ListEnvName,
MaketitleCtrlSeq,
} from './latex.terms.mjs'
function nameChar(ch) {
@ -635,6 +636,7 @@ const otherKnowncommands = {
'\\centering': CenteringCtrlSeq,
'\\bibliography': BibliographyCtrlSeq,
'\\bibliographystyle': BibliographyStyleCtrlSeq,
'\\maketitle': MaketitleCtrlSeq,
}
// specializer for control sequences
// return new tokens for specific control sequences

View file

@ -1,6 +1,6 @@
import { ensureSyntaxTree } from '@codemirror/language'
import { EditorState } from '@codemirror/state'
import { SyntaxNode, SyntaxNodeRef } from '@lezer/common'
import { SyntaxNode, SyntaxNodeRef, Tree } from '@lezer/common'
import { previousSiblingIs } from './common'
import { NodeIntersectsChangeFn, ProjectionItem } from './projection'
@ -138,21 +138,69 @@ export const cursorIsAtEndEnvironment = (
}
}
export const findDocumentEnvironment = (state: EditorState): number | null => {
const tree = ensureSyntaxTree(state, state.doc.length, HUNDRED_MS)
let position: number | null = null
const findStartOfDocumentEnvironment = (tree: Tree): number | null => {
const docEnvironment = findNodeInDocument(tree, 'DocumentEnvironment')
return docEnvironment?.getChild('Content')?.from || null
}
const findStartOfAbstractEnvironment = (
tree: Tree,
state: EditorState
): number | null => {
const abstractEnvironment = findNodeInDocument(
tree,
(nodeRef: SyntaxNodeRef) => {
return Boolean(
nodeRef.type.is('$Environment') &&
getEnvironmentName(nodeRef.node, state) === 'abstract'
)
}
)
return abstractEnvironment?.getChild('Content')?.from || null
}
const findMaketitleCommand = (tree: Tree): number | null => {
const maketitle = findNodeInDocument(tree, 'Maketitle')
return maketitle?.to ?? null
}
const findNodeInDocument = (
tree: Tree,
predicate: number | string | ((node: SyntaxNodeRef) => boolean)
): SyntaxNode | null => {
let node: SyntaxNode | null = null
const predicateFn =
typeof predicate !== 'function'
? (nodeRef: SyntaxNodeRef) => {
return nodeRef.type.is(predicate)
}
: predicate
tree?.iterate({
enter(nodeRef) {
if (position !== null) {
if (node !== null) {
return false
}
if (nodeRef.type.is('DocumentEnvironment')) {
position = nodeRef.node.getChild('Content')?.from || null
if (predicateFn(nodeRef)) {
node = nodeRef.node
return false
}
},
})
return position
return node
}
export const findStartOfDocumentContent = (
state: EditorState
): number | null => {
const tree = ensureSyntaxTree(state, state.doc.length, HUNDRED_MS)
if (!tree) {
return null
}
return (
findStartOfAbstractEnvironment(tree, state) ??
findMaketitleCommand(tree) ??
findStartOfDocumentEnvironment(tree)
)
}
/**