Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codemirror blob: Scroll search match into view #42513

Merged
merged 1 commit into from Oct 5, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 36 additions & 0 deletions client/web/src/repo/blob/codemirror/search.ts
Expand Up @@ -128,6 +128,42 @@ class SearchPanel implements Panel {

if (!query.eq(this.query)) {
this.view.dispatch({ effects: setSearchQuery.of(query) })

// The following code scrolls next match into view if there is no
// match in the visible viewport. This is done by searching for the
// text from the currently top visible line and determining whether
// the next match is in the current viewport

const { scrollTop } = this.view.scrollDOM

// Get top visible line. More than half of the line must be visible.
// We don't use `view.viewportLineBlocks` because that also includes
// lines that are rendered but not actually visible.
let topLineBlock = this.view.lineBlockAtHeight(scrollTop)
if (Math.abs(topLineBlock.bottom - scrollTop) <= topLineBlock.height / 2) {
topLineBlock = this.view.lineBlockAtHeight(scrollTop + topLineBlock.height)
}

let result = getSearchQuery(this.view.state).getCursor(this.view.state.doc, topLineBlock.from).next()
if (result.done) {
// No match in the remainder of the document, wrap around
result = getSearchQuery(this.view.state).getCursor(this.view.state.doc).next()
if (result.done) {
// Search term is not in the document, nothing to do
return
}
}

const matchLineBlock = this.view.lineBlockAt(result.value.from)
const matchLineCenter = matchLineBlock.top + matchLineBlock.height / 2

if (matchLineCenter < scrollTop || matchLineCenter > scrollTop + this.view.scrollDOM.clientHeight) {
this.view.dispatch({
effects: EditorView.scrollIntoView(result.value.from, {
y: 'center',
}),
})
}
}
}

Expand Down