Merge pull request #13594 from overleaf/ae-starred-caption

[cm6] Allow an asterisk after CaptionCtrlSeq

GitOrigin-RevId: e76e15afb676f6eddb8f09d710b0d90408584e29
This commit is contained in:
Alf Eaton 2023-06-29 09:53:43 +01:00 committed by Copybot
parent 62533ace6d
commit c6d832d6d9
6 changed files with 86 additions and 4 deletions

View file

@ -24,6 +24,7 @@ import { EndWidget } from './visual-widgets/end'
import { import {
getEnvironmentArguments, getEnvironmentArguments,
getEnvironmentName, getEnvironmentName,
getUnstarredEnvironmentName,
parseFigureData, parseFigureData,
} from '../../utils/tree-operations/environments' } from '../../utils/tree-operations/environments'
import { MathWidget } from './visual-widgets/math' import { MathWidget } from './visual-widgets/math'
@ -224,7 +225,7 @@ export const atomicDecorations = (options: Options) => {
enter(nodeRef) { enter(nodeRef) {
if (nodeRef.type.is('$Environment')) { if (nodeRef.type.is('$Environment')) {
if (shouldDecorate(state, nodeRef)) { if (shouldDecorate(state, nodeRef)) {
const envName = getEnvironmentName(nodeRef.node, state) const envName = getUnstarredEnvironmentName(nodeRef.node, state)
const hideInEnvironmentTypes = ['figure', 'table'] const hideInEnvironmentTypes = ['figure', 'table']
if (envName && hideInEnvironmentTypes.includes(envName)) { if (envName && hideInEnvironmentTypes.includes(envName)) {
const beginNode = nodeRef.node.getChild('BeginEnv') const beginNode = nodeRef.node.getChild('BeginEnv')

View file

@ -6,7 +6,7 @@ import {
} from '@codemirror/view' } from '@codemirror/view'
import { EditorState, Range } from '@codemirror/state' import { EditorState, Range } from '@codemirror/state'
import { syntaxTree } from '@codemirror/language' import { syntaxTree } from '@codemirror/language'
import { getEnvironmentName } from '../../utils/tree-operations/environments' import { getUnstarredEnvironmentName } from '../../utils/tree-operations/environments'
import { centeringNodeForEnvironment } from '../../utils/tree-operations/figure' import { centeringNodeForEnvironment } from '../../utils/tree-operations/figure'
import { Tree } from '@lezer/common' import { Tree } from '@lezer/common'
@ -103,7 +103,10 @@ export const markDecorations = ViewPlugin.define(
} }
} }
} else if (nodeRef.type.is('$Environment')) { } else if (nodeRef.type.is('$Environment')) {
const environmentName = getEnvironmentName(nodeRef.node, state) const environmentName = getUnstarredEnvironmentName(
nodeRef.node,
state
)
switch (environmentName) { switch (environmentName) {
case 'abstract': case 'abstract':

View file

@ -250,7 +250,7 @@ KnownCommand {
IncludeGraphicsArgument { FilePathArgument } IncludeGraphicsArgument { FilePathArgument }
} | } |
Caption { Caption {
CaptionCtrlSeq optionalWhitespace? OptionalArgument? TextArgument CaptionCtrlSeq "*"? optionalWhitespace? OptionalArgument? TextArgument
} | } |
Label { Label {
LabelCtrlSeq optionalWhitespace? LabelArgument LabelCtrlSeq optionalWhitespace? LabelArgument

View file

@ -739,6 +739,7 @@ const otherKnownEnvNames = {
document: DocumentEnvName, document: DocumentEnvName,
tikzpicture: TikzPictureEnvName, tikzpicture: TikzPictureEnvName,
figure: FigureEnvName, figure: FigureEnvName,
'figure*': FigureEnvName,
subfigure: FigureEnvName, subfigure: FigureEnvName,
enumerate: ListEnvName, enumerate: ListEnvName,
itemize: ListEnvName, itemize: ListEnvName,

View file

@ -236,6 +236,11 @@ export function getEnvironmentName(
return state.sliceDoc(nameNode.from, nameNode.to) return state.sliceDoc(nameNode.from, nameNode.to)
} }
export const getUnstarredEnvironmentName = (
node: SyntaxNode | null,
state: EditorState
): string | undefined => getEnvironmentName(node, state)?.replace(/\*$/, '')
export function getEnvironmentArguments(environmentNode: SyntaxNode) { export function getEnvironmentArguments(environmentNode: SyntaxNode) {
return environmentNode.getChild('BeginEnv')?.getChildren('TextArgument') return environmentNode.getChild('BeginEnv')?.getChildren('TextArgument')
} }

View file

@ -0,0 +1,72 @@
import { FC } from 'react'
import { EditorProviders } from '../../../helpers/editor-providers'
import CodemirrorEditor from '../../../../../frontend/js/features/source-editor/components/codemirror-editor'
import { mockScope } from '../helpers/mock-scope'
const Container: FC = ({ children }) => (
<div style={{ width: 785, height: 785 }}>{children}</div>
)
const mountEditor = (content: string) => {
const scope = mockScope(content)
scope.editor.showVisual = true
cy.mount(
<Container>
<EditorProviders scope={scope}>
<CodemirrorEditor />
</EditorProviders>
</Container>
)
// wait for the content to be parsed and revealed
cy.get('.cm-content').should('have.css', 'opacity', '1')
}
describe('<CodeMirrorEditor/> floats', function () {
beforeEach(function () {
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
cy.interceptEvents()
cy.interceptSpelling()
})
afterEach(function () {
window.metaAttributesCache.clear()
})
it('decorates a caption', function () {
mountEditor('\n\\caption{Foo}\n')
cy.get('.cm-line').eq(2).click()
cy.get('.cm-content').should('have.text', 'Foo')
})
it('decorates a caption in a figure', function () {
mountEditor('\\begin{figure}\n\\caption{Foo}\n\\end{figure}\n')
cy.get('.cm-line').eq(3).click()
cy.get('.cm-content').should('have.text', 'Foo')
})
it('decorates a caption in a table', function () {
mountEditor('\\begin{table}\n\\caption{Foo}\n\\end{table}\n')
cy.get('.cm-line').eq(3).click()
cy.get('.cm-content').should('have.text', 'Foo')
})
it('decorates a starred caption', function () {
mountEditor('\n\\caption*{Foo}\n')
cy.get('.cm-line').eq(2).click()
cy.get('.cm-content').should('have.text', 'Foo')
})
it('decorates a starred figure', function () {
mountEditor('\\begin{figure*}\n\\caption{Foo}\n\\end{figure*}\n')
cy.get('.cm-line').eq(3).click()
cy.get('.cm-content').should('have.text', 'Foo')
})
it('decorates a starred table', function () {
mountEditor('\\begin{table*}\n\\caption{Foo}\n\\end{table*}\n')
cy.get('.cm-line').eq(3).click()
cy.get('.cm-content').should('have.text', 'Foo')
})
})