Merge pull request #32114 from overleaf/mg-context-menu-cursor-movemenet

Move cursor on right-click within same line

GitOrigin-RevId: 8b622e9f557ecb1a33b7ba1a80d5752e05a72718
This commit is contained in:
Malik Glossop
2026-03-18 10:04:12 +01:00
committed by Copybot
parent f947b549e4
commit 7bb4427f93
2 changed files with 59 additions and 6 deletions

View File

@@ -153,13 +153,11 @@ function isPositionInsideSelection(pos: number, from: number, to: number) {
function isPositionInsideAnyRangeOrCursor(view: EditorView, pos: number) {
for (const range of view.state.selection.ranges) {
// If it's a cursor, treat a right-click anywhere on the same line as "inside".
// This avoids collapsing multi-cursor selections when right-clicking on blank lines
// or to the right of the caret.
// If it's a cursor (not a selection), only treat it as "inside" when
// right-clicking exactly on the cursor position. This allows cursor
// movement when clicking elsewhere on the same line.
if (range.from === range.to) {
const clickedLine = view.state.doc.lineAt(pos)
const cursorLine = view.state.doc.lineAt(range.from)
if (clickedLine.number === cursorLine.number) {
if (pos === range.from) {
return true
}
continue

View File

@@ -162,6 +162,61 @@ describe('editor context menu', { scrollBehavior: false }, function () {
cy.findByRole('menu').should('not.exist')
})
it('should move the cursor when right-clicking a different position on the same line', function () {
grantClipboardPermissions()
const pasteContent = 'XX'
const scope = mockScope()
cy.mount(
<TestContainer>
<EditorProviders scope={scope}>
<CodeMirrorEditor />
</EditorProviders>
</TestContainer>
)
// Stub clipboard to return known content for pasting
cy.window().then(win => {
const getTypeStub = cy.stub()
getTypeStub
.withArgs('text/plain')
.resolves(new Blob([pasteContent], { type: 'text/plain' }))
cy.stub(win.navigator.clipboard, 'read').resolves([
{
types: ['text/plain'],
getType: getTypeStub,
},
])
cy.stub(win.navigator.clipboard, 'readText').resolves(pasteContent)
})
cy.get('.cm-line').eq(16).as('line')
cy.get('@line').click()
cy.get('@line').type('aaaa bbbb')
// Right-click the left side of the line — opens context menu with cursor near start
cy.get('@line').rightclick('left')
cy.findByRole('menu').should('be.visible')
// Right-click the right side of the same line while menu is still open —
// cursor should move to the end of the line
cy.get('@line').rightclick('right')
cy.findByRole('menu').should('be.visible')
// Paste via context menu — content goes wherever the cursor is
cy.findByRole('menu').within(() => {
cy.findByRole('menuitem', { name: pasteLabelMatcher }).click()
})
// If cursor moved: "aaaa bbbbXX" (pasted at end)
cy.get('@line').should($line => {
const text = $line.text()
expect(text).to.equal('aaaa bbbb' + pasteContent)
})
})
it('should should close when clicking outside the editor', function () {
const scope = mockScope()
const outsideEditorButtonName = 'Recompile'