[cm6] Improve begin environment autocompletion (#12982)

GitOrigin-RevId: 42731e6f2261f7ed9b85523a550c636968698fc3
This commit is contained in:
Alf Eaton 2023-05-10 12:59:38 +01:00 committed by Copybot
parent a248da99c1
commit ea996582bf
5 changed files with 39 additions and 41 deletions

View file

@ -1,9 +1,5 @@
import { EditorState, SelectionRange, Text } from '@codemirror/state'
import {
CloseBracketConfig,
completionStatus,
prevChar,
} from '@codemirror/autocomplete'
import { CloseBracketConfig, prevChar } from '@codemirror/autocomplete'
export const closeBracketConfig: CloseBracketConfig = {
brackets: ['$', '$$', '[', '{', '('],
@ -74,10 +70,6 @@ export const closeBracketConfig: CloseBracketConfig = {
// don't auto-close \{
return open
}
// avoid auto-closing curly brackets when autocomplete is open
if (completionStatus(state)) {
return open
}
return open + close
}

View file

@ -6,7 +6,10 @@ import {
} from '@codemirror/autocomplete'
import { customEndCompletions } from './completions/environments'
import { customCommandCompletions } from './completions/doc-commands'
import { customEnvironmentCompletions } from './completions/doc-environments'
import {
customEnvironmentCompletions,
findEnvironmentsInDoc,
} from './completions/doc-environments'
import { Completions } from './completions/types'
import { buildReferenceCompletions } from './completions/references'
import { buildPackageCompletions } from './completions/packages'
@ -406,12 +409,6 @@ export const beginEnvironmentCompletionSource: CompletionSource = context => {
return null
}
// this completion source must only be active when the \begin command has a closing brace
const closeBrace = envNameGroup.getChild('CloseBrace')
if (!closeBrace) {
return null
}
const envName = envNameGroup.getChild('$EnvName')
if (!envName) {
return null
@ -419,10 +416,19 @@ export const beginEnvironmentCompletionSource: CompletionSource = context => {
const name = context.state.sliceDoc(envName.from, envName.to)
// if not directly after `\begin{…}`, exclude known environments
if (context.pos !== envNameGroup.to) {
const existingEnvironmentNames = findEnvironmentsInDoc(context)
if (existingEnvironmentNames.has(name)) {
return null
}
}
const completion = {
label: `\\begin{${name}} …`,
apply: applySnippet(snippet(name)),
extend: extendOverUnpairedClosingBrace,
boost: -99,
}
return {

View file

@ -22,7 +22,7 @@ export function customEnvironmentCompletions(context: CompletionContext) {
return completions
}
const findEnvironmentsInDoc = (context: CompletionContext) => {
export const findEnvironmentsInDoc = (context: CompletionContext) => {
const result = new Set<string>()
const environmentNamesProjection: ProjectionResult<EnvironmentName> =

View file

@ -321,10 +321,10 @@ describe('autocomplete', { scrollBehavior: false }, function () {
cy.get('.cm-line').eq(28).click().as('line')
cy.get('@line').type('\\begin{{}ab')
cy.findAllByRole('option').as('options')
cy.get('@options').should('have.length', 4)
cy.get('@options').should('have.length', 5)
// ---- The environment being typed should not appear in the list
cy.get('@options').contains('\\begin{ab}').should('not.exist')
// ---- The environment being typed should appear in the list
cy.get('@options').contains('\\begin{ab}').should('exist')
// ---- A new environment used elsewhere in the doc should appear next
cy.get('@options')

View file

@ -126,8 +126,8 @@ describe('<CodeMirrorEditor/> in Rich Text mode', function () {
function (command) {
cy.get('@first-line')
.type(`\\${command}{`)
.should('have.text', `\\${command}{`)
.type('} ') // Should still show braces for empty commands
.should('have.text', `{}`)
.type('{rightArrow} ')
.should('have.text', '{} ')
.type('{Backspace}{leftArrow}test text')
.should('have.text', '{test text}')
@ -148,10 +148,8 @@ describe('<CodeMirrorEditor/> in Rich Text mode', function () {
]).it('handles \\%s sectioning command', function (command) {
cy.get('@first-line')
.type(`\\${command}{`)
.should('have.text', `\\${command}{`)
.type(`}`)
.should('have.text', `\\${command}{}`)
.type(' ')
.type('{rightArrow} ')
.should('have.text', `\\${command}{} `)
// Press enter before closing brace
.type('{Backspace}{leftArrow}title{leftArrow}{Enter}')
@ -160,24 +158,14 @@ describe('<CodeMirrorEditor/> in Rich Text mode', function () {
.should('exist')
})
forEach([
'textsc',
'texttt',
'sout',
'emph',
['verb', '|', '|'],
'url',
'caption',
]).it(
forEach(['textsc', 'texttt', 'sout', 'emph', 'url', 'caption']).it(
'handles \\%s text',
function (command, openingBrace = '{', closingBrace = '}') {
function (command) {
cy.get('@first-line')
.type(`\\${command}${openingBrace}`)
.should('have.text', `\\${command}${openingBrace}`)
.type(`${closingBrace}`)
.should('have.text', `\\${command}${openingBrace}${closingBrace}`)
.type(' ')
.should('have.text', `\\${command}${openingBrace}${closingBrace} `)
.type(`\\${command}{`)
.should('have.text', `\\${command}{}`)
.type('{rightArrow} ')
.should('have.text', `\\${command}{} `)
.type('{Backspace}{leftArrow}test text{rightArrow} ')
.should('have.text', 'test text ')
.find(`.ol-cm-command-${command}`)
@ -185,6 +173,18 @@ describe('<CodeMirrorEditor/> in Rich Text mode', function () {
}
)
it('handles \\verb text', function () {
cy.get('@first-line')
.type(`\\verb|`)
.should('have.text', `\\verb|`)
.type('| ')
.should('have.text', `\\verb|| `)
.type('{Backspace}{leftArrow}test text{rightArrow} ')
.should('have.text', 'test text ')
.find(`.ol-cm-command-verb`)
.should('exist')
})
forEach([
['ref', '🏷'],
['label', '🏷'],