Procházet zdrojové kódy

[cm6] Improve begin environment autocompletion (#12982)

GitOrigin-RevId: 42731e6f2261f7ed9b85523a550c636968698fc3
Alf Eaton před 3 roky
rodič
revize
ea996582bf

+ 1 - 9
services/web/frontend/js/features/source-editor/languages/latex/close-bracket-config.ts

@@ -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
       }
 

+ 13 - 7
services/web/frontend/js/features/source-editor/languages/latex/complete.ts

@@ -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 {

+ 1 - 1
services/web/frontend/js/features/source-editor/languages/latex/completions/doc-environments.ts

@@ -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> =

+ 3 - 3
services/web/test/frontend/features/source-editor/components/codemirror-editor-autocomplete.spec.tsx

@@ -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')

+ 21 - 21
services/web/test/frontend/features/source-editor/components/codemirror-editor-visual.spec.tsx

@@ -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', '🏷'],