Only select content when opening a file if it matches the expected text (#23324)

GitOrigin-RevId: 8b180ab897bb9027743c37f2b7faf690b7177eb6
This commit is contained in:
Alf Eaton
2025-02-04 09:50:10 +00:00
committed by Copybot
parent bb1745cf2d
commit da816f9478
7 changed files with 190 additions and 8 deletions
@@ -0,0 +1 @@
Simply use the section and subsection commands, as in this example document! With Overleaf, all the formatting and numbering is handled automatically according to the template you've chosen. If you're using the Visual Editor, you can also create new section and subsections via the buttons in the editor toolbar.
@@ -0,0 +1,8 @@
@article{greenwade93,
author = "George D. Greenwade",
title = "The {C}omprehensive {T}ex {A}rchive {N}etwork ({CTAN})",
year = "1993",
journal = "TUGBoat",
volume = "14",
number = "3",
pages = "342--351"}
@@ -1,6 +1,6 @@
export interface GotoLineOptions {
gotoLine: number
gotoColumn?: number
selectionLength?: number
selectText?: string
syncToPdf?: boolean
}
@@ -131,20 +131,32 @@ const dispatchSelectionAndScroll = (
})
}
const selectTextIfExists = (doc: Text, pos: number, selectText: string) => {
const selectionLength = pos + selectText.length
const text = doc.sliceString(pos, selectionLength)
return text === selectText
? EditorSelection.range(pos, selectionLength)
: EditorSelection.cursor(doc.lineAt(pos).from)
}
export const setCursorLineAndScroll = (
view: EditorView,
lineNumber: number,
columnNumber = 0,
selectionLength?: number
selectText?: string
) => {
// TODO: map the position through any changes since the previous compile?
let selectionRange
try {
const pos = findValidPosition(view.state.doc, lineNumber, columnNumber)
selectionRange = selectionLength
? EditorSelection.range(pos, pos + selectionLength)
: EditorSelection.cursor(pos)
const { doc } = view.state
const pos = findValidPosition(doc, lineNumber, columnNumber)
dispatchSelectionAndScroll(
view,
selectText
? selectTextIfExists(doc, pos, selectText)
: EditorSelection.cursor(pos)
)
} catch (error) {
// ignore invalid cursor position
debugConsole.debug('invalid cursor position', error)
@@ -476,7 +476,7 @@ function useCodeMirrorScope(view: EditorView) {
view,
options.gotoLine,
options.gotoColumn,
options.selectionLength
options.selectText
)
if (options.syncToPdf) {
emitSyncToPdf()
@@ -24,7 +24,7 @@ import { isMac } from '@/shared/utils/os'
export type IdeLayout = 'sideBySide' | 'flat'
export type IdeView = 'editor' | 'file' | 'pdf' | 'history'
type LayoutContextValue = {
export type LayoutContextValue = {
reattach: () => void
detach: () => void
detachIsLinked: boolean
@@ -0,0 +1,161 @@
import '../../../helpers/bootstrap-5'
import { EditorProviders } from '../../../helpers/editor-providers'
import FullProjectSearch from '../../../../../modules/full-project-search/frontend/js/components/full-project-search'
import {
LayoutContext,
LayoutContextValue,
} from '@/shared/context/layout-context'
import { FC, useState } from 'react'
describe('<FullProjectSearch/>', function () {
beforeEach(function () {
cy.interceptCompile()
cy.intercept('/project/*/flush', {
statusCode: 204,
}).as('project-history-flush')
cy.intercept('/project/*/changes?*', {
body: [],
}).as('project-history-changes')
cy.intercept('/project/*/latest/history', {
body: { chunk: mockHistoryChunk },
}).as('project-history-snapshot')
cy.intercept('get', '/project/*/blob/*', req => {
const blobId = req.url.split('/').pop() as string
req.reply({
fixture: `blobs/${blobId}`,
})
}).as('project-history-blob')
})
it('displays the search form', function () {
cy.mount(
<EditorProviders providers={{ LayoutProvider }}>
<FullProjectSearch />
</EditorProviders>
)
cy.findByRole('button', { name: 'Search' })
})
it('displays a close button', function () {
cy.mount(
<EditorProviders providers={{ LayoutProvider }}>
<FullProjectSearch />
</EditorProviders>
)
cy.findByRole('button', { name: 'Close' })
})
it('displays matched content', function () {
cy.mount(
<EditorProviders providers={{ LayoutProvider }}>
<FullProjectSearch />
</EditorProviders>
)
cy.findByRole('searchbox', { name: 'Search' }).type('and{enter}')
cy.findByRole('button', { name: 'main.tex 5' }) // TODO: remove count from name?
cy.get('.matched-file-hit').as('matches')
cy.get('@matches').should('have.length', 5)
cy.get('@matches').first().click()
cy.get('@matches').first().should('have.class', 'matched-file-hit-selected')
})
})
const createInitialValue = () =>
({
reattach: cy.stub(),
detach: cy.stub(),
detachIsLinked: false,
detachRole: null,
changeLayout: cy.stub(),
view: 'editor',
setView: cy.stub(),
chatIsOpen: false,
setChatIsOpen: cy.stub(),
reviewPanelOpen: false,
setReviewPanelOpen: cy.stub(),
miniReviewPanelVisible: false,
setMiniReviewPanelVisible: cy.stub(),
leftMenuShown: false,
setLeftMenuShown: cy.stub(),
loadingStyleSheet: false,
setLoadingStyleSheet: cy.stub(),
pdfLayout: 'flat',
pdfPreviewOpen: false,
projectSearchIsOpen: true,
setProjectSearchIsOpen: cy.stub(),
}) satisfies LayoutContextValue
const LayoutProvider: FC = ({ children }) => {
const [value] = useState(createInitialValue)
return (
<LayoutContext.Provider value={value}>{children}</LayoutContext.Provider>
)
}
const mockHistoryChunk = {
history: {
snapshot: {
files: {},
},
changes: [
{
operations: [
{
pathname: 'main.tex',
file: {
hash: '5199b66d9d1226551be436c66bad9d962cc05537',
stringLength: 7066,
},
},
],
timestamp: '2025-01-03T10:10:40.840Z',
authors: [],
v2Authors: ['66e040e0da7136ec75ffe8a3'],
projectVersion: '1.0',
},
{
operations: [
{
pathname: 'sample.bib',
file: {
hash: 'a0e21c740cf81e868f158e30e88985b5ea1d6c19',
stringLength: 244,
},
},
],
timestamp: '2025-01-03T10:10:40.856Z',
authors: [],
v2Authors: ['66e040e0da7136ec75ffe8a3'],
projectVersion: '2.0',
},
{
operations: [
{
pathname: 'frog.jpg',
file: {
hash: '5b889ef3cf71c83a4c027c4e4dc3d1a106b27809',
byteLength: 97080,
},
},
],
timestamp: '2025-01-03T10:10:40.890Z',
authors: [],
v2Authors: ['66e040e0da7136ec75ffe8a3'],
projectVersion: '3.0',
},
],
},
startVersion: 0,
}