diff --git a/package-lock.json b/package-lock.json index c75bb67c15..7393b52721 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3280,9 +3280,8 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" }, "node_modules/@codemirror/autocomplete": { - "version": "6.6.1", - "resolved": "git+ssh://git@github.com/overleaf/codemirror-autocomplete.git#4514fd21c6c9219f5c23a6a675ad843bb7a5b2bd", - "integrity": "sha512-3xD9M0e5cw0XsC7mMfRy+vKcOup7Nno4J3r0aTvwWqsUlQYBzT0R3sBEn6y+gHdpIpuSEx+jKIGKiqBsWI8czg==", + "version": "6.8.0", + "resolved": "git+ssh://git@github.com/overleaf/codemirror-autocomplete.git#03ea9e4565635c9bc005c9b809713d1897aabc59", "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", @@ -41256,7 +41255,7 @@ "@babel/preset-env": "^7.21.5", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.21.5", - "@codemirror/autocomplete": "github:overleaf/codemirror-autocomplete#4514fd21c6c9219f5c23a6a675ad843bb7a5b2bd", + "@codemirror/autocomplete": "github:overleaf/codemirror-autocomplete#v6.8.0-overleaf-1", "@codemirror/commands": "^6.2.3", "@codemirror/lang-markdown": "^6.1.1", "@codemirror/language": "^6.6.0", @@ -44935,9 +44934,8 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" }, "@codemirror/autocomplete": { - "version": "git+ssh://git@github.com/overleaf/codemirror-autocomplete.git#4514fd21c6c9219f5c23a6a675ad843bb7a5b2bd", - "integrity": "sha512-3xD9M0e5cw0XsC7mMfRy+vKcOup7Nno4J3r0aTvwWqsUlQYBzT0R3sBEn6y+gHdpIpuSEx+jKIGKiqBsWI8czg==", - "from": "@codemirror/autocomplete@github:overleaf/codemirror-autocomplete#4514fd21c6c9219f5c23a6a675ad843bb7a5b2bd", + "version": "git+ssh://git@github.com/overleaf/codemirror-autocomplete.git#03ea9e4565635c9bc005c9b809713d1897aabc59", + "from": "@codemirror/autocomplete@github:overleaf/codemirror-autocomplete#v6.8.0-overleaf-1", "requires": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", @@ -50239,7 +50237,7 @@ "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.21.5", "@babel/register": "^7.21.0", - "@codemirror/autocomplete": "github:overleaf/codemirror-autocomplete#4514fd21c6c9219f5c23a6a675ad843bb7a5b2bd", + "@codemirror/autocomplete": "github:overleaf/codemirror-autocomplete#v6.8.0-overleaf-1", "@codemirror/commands": "^6.2.3", "@codemirror/lang-markdown": "^6.1.1", "@codemirror/language": "^6.6.0", diff --git a/services/web/frontend/js/features/source-editor/languages/latex/completions/apply.ts b/services/web/frontend/js/features/source-editor/languages/latex/completions/apply.ts index 88efa89ddd..c98692224f 100644 --- a/services/web/frontend/js/features/source-editor/languages/latex/completions/apply.ts +++ b/services/web/frontend/js/features/source-editor/languages/latex/completions/apply.ts @@ -57,8 +57,12 @@ export const extendRequiredParameter = ( argumentNode.getChild('OpenBrace') && argumentNode.getChild('CloseBrace') - // add a closing brace if needed - if (nextChar(state.doc, change.to) !== '}') { + if (nextChar(state.doc, change.to) === '}') { + // include an existing closing brace, so the cursor moves after it + change.insert += '}' + change.to++ + } else { + // add a closing brace if needed if (countUnclosedBraces(state.doc, change.from, change.to) > 0) { change.insert += '}' } diff --git a/services/web/package.json b/services/web/package.json index e58944ff77..2d74202736 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -71,7 +71,7 @@ "@babel/preset-env": "^7.21.5", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.21.5", - "@codemirror/autocomplete": "github:overleaf/codemirror-autocomplete#4514fd21c6c9219f5c23a6a675ad843bb7a5b2bd", + "@codemirror/autocomplete": "github:overleaf/codemirror-autocomplete#v6.8.0-overleaf-1", "@codemirror/commands": "^6.2.3", "@codemirror/lang-markdown": "^6.1.1", "@codemirror/language": "^6.6.0", diff --git a/services/web/test/frontend/features/source-editor/components/codemirror-editor-autocomplete.spec.tsx b/services/web/test/frontend/features/source-editor/components/codemirror-editor-autocomplete.spec.tsx index e164dc7218..44e317e119 100644 --- a/services/web/test/frontend/features/source-editor/components/codemirror-editor-autocomplete.spec.tsx +++ b/services/web/test/frontend/features/source-editor/components/codemirror-editor-autocomplete.spec.tsx @@ -177,7 +177,7 @@ describe('autocomplete', { scrollBehavior: false }, function () { cy.contains('\\includegraphics[width=0.3\\textwidth]{frog.jpg}') // start a new line and select an "includegraphics" command completion - cy.get('@line').type('{rightArrow}{Enter}') + cy.get('@line').type('{Enter}') activeEditorLine().type('\\includegr') cy.contains('\\includegraphics[]{}').click() @@ -191,7 +191,7 @@ describe('autocomplete', { scrollBehavior: false }, function () { cy.contains('\\includegraphics[]{test-folder/example.png}') activeEditorLine() - .type(`${'{leftArrow}'.repeat('test-folder/example.png'.length)}fr`) + .type(`${'{leftArrow}'.repeat('test-folder/example.png}'.length)}fr`) .type('{ctrl+ }') cy.findAllByRole('listbox').should('have.length', 1) @@ -492,7 +492,7 @@ describe('autocomplete', { scrollBehavior: false }, function () { cy.get('@line').contains('\\cite{ref-2}') // start typing another reference - cy.get('@line').type(', re') + cy.get('@line').type('{leftArrow}, re') // autocomplete open again cy.findAllByRole('listbox').contains('ref-3').click() @@ -1031,37 +1031,37 @@ describe('autocomplete', { scrollBehavior: false }, function () { activeEditorLine().type('\\include{s', { delay: 100 }) cy.findAllByRole('option').contains('sometext.txt').click() activeEditorLine().should('have.text', '\\include{sometext.txt}') - activeEditorLine().type('{rightArrow}{Enter}') + activeEditorLine().type('{Enter}') activeEditorLine().type('\\inclu', { delay: 100 }) cy.contains('\\include{}').click() cy.contains('example.tex').click() activeEditorLine().should('have.text', '\\include{example}') - activeEditorLine().type('{rightArrow}{Enter}') + activeEditorLine().type('{Enter}') activeEditorLine().type('\\inclu', { delay: 100 }) cy.findAllByRole('option').contains('\\include{}').click() cy.findAllByRole('option').contains('sometext.txt').click() activeEditorLine().should('have.text', '\\include{sometext.txt}') - activeEditorLine().type('{rightArrow}{Enter}') + activeEditorLine().type('{Enter}') activeEditorLine().click().as('line') activeEditorLine().type('\\input{e', { delay: 100 }) cy.findAllByRole('option').contains('example.tex').click() activeEditorLine().should('have.text', '\\input{example}') - activeEditorLine().type('{rightArrow}{Enter}') + activeEditorLine().type('{Enter}') activeEditorLine().click().as('line') activeEditorLine().type('\\input{s', { delay: 100 }) cy.findAllByRole('option').contains('sometext.txt').click() activeEditorLine().should('have.text', '\\input{sometext.txt}') - activeEditorLine().type('{rightArrow}{Enter}') + activeEditorLine().type('{Enter}') activeEditorLine().type('\\inpu', { delay: 100 }) cy.findAllByRole('option').contains('\\input{}').click() cy.findAllByRole('option').contains('example.tex').click() activeEditorLine().should('have.text', '\\input{example}') - activeEditorLine().type('{rightArrow}{Enter}') + activeEditorLine().type('{Enter}') activeEditorLine().type('\\inpu', { delay: 100 }) cy.findAllByRole('option').contains('\\input{}').click()