Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 47 additions & 40 deletions client/web/src/codeintel/ReferencesPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { type Observable, of } from 'rxjs'
import { map } from 'rxjs/operators'

import { CodeExcerpt } from '@sourcegraph/branded'
import type { HoveredToken } from '@sourcegraph/codeintellify'
import { type ErrorLike, logger, pluralize } from '@sourcegraph/common'
import { Position } from '@sourcegraph/extension-api-classes'
import { useQuery } from '@sourcegraph/http-client'
Expand Down Expand Up @@ -69,13 +68,12 @@ import {
} from './location'
import { FETCH_HIGHLIGHTED_BLOB } from './ReferencesPanelQueries'
import { newSettingsGetter } from './settings'
import { findSearchToken } from './token'
import { findSearchToken, type ZeroBasedPosition } from './token'
import { useRepoAndBlob } from './useRepoAndBlob'
import { isDefined } from './util/helpers'

import styles from './ReferencesPanel.module.scss'

type Token = HoveredToken & RepoSpec & RevisionSpec & FileSpec & ResolvedRevisionSpec
type Token = { range: State['range'] } & RepoSpec & RevisionSpec & FileSpec & ResolvedRevisionSpec

interface HighlightedFileLineRangesProps {
fetchHighlightedFileLineRanges: (parameters: FetchFileParameters, force?: boolean) => Observable<string[][]>
Expand All @@ -101,8 +99,10 @@ interface State {
repoName: string
revision?: string
filePath: string
line: number
character: number
range: {
start: OneBasedPosition
end?: OneBasedPosition
}
jumpToFirst: boolean
collapsedState: {
references: boolean
Expand All @@ -112,9 +112,14 @@ interface State {
}
}

interface OneBasedPosition {
line: number
character: number
}

function createStateFromLocation(location: H.Location): null | State {
const { hash, pathname, search } = location
const { line, character, viewState } = parseQueryAndHash(search, hash)
const { line, character, endLine, endCharacter, viewState } = parseQueryAndHash(search, hash)
const { filePath, repoName, revision } = parseBrowserRepoURL(pathname)

// If we don't have enough information in the URL, we can't render the panel
Expand Down Expand Up @@ -142,7 +147,11 @@ function createStateFromLocation(location: H.Location): null | State {
collapsedState.definitions = true
}

return { repoName, revision, filePath, line, character, jumpToFirst, collapsedState }
const range = {
start: { line, character },
end: endLine && endCharacter ? { line: endLine, character: endCharacter } : undefined,
}
return { repoName, revision, filePath, range, jumpToFirst, collapsedState }
}

export const ReferencesPanel: React.FunctionComponent<React.PropsWithChildren<ReferencesPanelProps>> = props => {
Expand All @@ -159,8 +168,7 @@ export const ReferencesPanel: React.FunctionComponent<React.PropsWithChildren<Re
repoName={state.repoName}
revision={state.revision}
filePath={state.filePath}
line={state.line}
character={state.character}
range={state.range}
jumpToFirst={state.jumpToFirst}
collapsedState={state.collapsedState}
/>
Expand All @@ -171,8 +179,7 @@ const RevisionResolvingReferencesList: React.FunctionComponent<
React.PropsWithChildren<
ReferencesPanelProps & {
repoName: string
line: number
character: number
range: State['range']
filePath: string
revision?: string
collapsedState: State['collapsedState']
Expand All @@ -184,7 +191,7 @@ const RevisionResolvingReferencesList: React.FunctionComponent<
// Scroll blob UI to the selected symbol right after the reference panel is rendered
// and shifted the blob UI (scroll into view is needed because there are a few cases
// when ref panel may overlap with current symbol)
useEffect(() => BlobAPI.scrollIntoView({ line: props.line }), [props.line])
useEffect(() => BlobAPI.scrollIntoView({ line: props.range.start.line }), [props.range.start.line])

if (loading && !data) {
return <LoadingCodeIntel />
Expand All @@ -205,8 +212,7 @@ const RevisionResolvingReferencesList: React.FunctionComponent<

const token = {
repoName: props.repoName,
line: props.line,
character: props.character,
range: props.range,
filePath: props.filePath,
revision: data.revision,
commitID: data.commitID,
Expand All @@ -233,29 +239,28 @@ interface ReferencesPanelPropsWithToken extends ReferencesPanelProps {
collapsedState: State['collapsedState']
}

function oneBasedPositionToZeroBased(p: OneBasedPosition): ZeroBasedPosition {
return {
line: p.line - 1,
character: p.character - 1,
}
}

const SearchTokenFindingReferencesList: React.FunctionComponent<
React.PropsWithChildren<ReferencesPanelPropsWithToken>
> = props => {
const languageId = getModeFromPath(props.token.filePath)
const spec = findLanguageSpec(languageId)
const tokenResult =
spec &&
findSearchToken({
text: props.fileContent,
position: {
line: props.token.line - 1,
character: props.token.character - 1,
},
lineRegexes: spec.commentStyles.map(style => style.lineRegex).filter(isDefined),
blockCommentStyles: spec.commentStyles.map(style => style.block).filter(isDefined),
identCharPattern: spec.identCharPattern,
})
const tokenRange = props.token.range
const tokenResult = findSearchToken({
text: props.fileContent,
start: oneBasedPositionToZeroBased(tokenRange.start),
end: tokenRange.end ? oneBasedPositionToZeroBased(tokenRange.end) : undefined,
})
const shouldMixPreciseAndSearchBasedReferences: boolean = newSettingsGetter(props.settingsCascade)<boolean>(
'codeIntel.mixPreciseAndSearchBasedReferences',
false
)

if (!spec || !tokenResult?.searchToken) {
if (tokenResult === undefined) {
return (
<div>
<Text className="text-danger">Could not find token.</Text>
Expand All @@ -269,12 +274,13 @@ const SearchTokenFindingReferencesList: React.FunctionComponent<
// change. This way we avoid showing stale results.
key={shouldMixPreciseAndSearchBasedReferences.toString()}
{...props}
token={props.token}
searchToken={tokenResult?.searchToken}
spec={spec}
fileContent={props.fileContent}
isFork={props.isFork}
isArchived={props.isArchived}
searchToken={tokenResult}
// The file extensions attached to the 'spec' value here are
// used for search-based code intel. However, determining
// the spec purely based on the file path is wrong.
//
// See FIXME(id: language-detection).
spec={findLanguageSpec(getModeFromPath(props.token.filePath))}
/>
)
}
Expand All @@ -285,7 +291,7 @@ const ReferencesList: React.FunctionComponent<
React.PropsWithChildren<
ReferencesPanelPropsWithToken & {
searchToken: string
spec: LanguageSpec
spec: LanguageSpec | undefined
fileContent: string
collapsedState: State['collapsedState']
}
Expand Down Expand Up @@ -322,8 +328,8 @@ const ReferencesList: React.FunctionComponent<
path: props.token.filePath,
// On the backend the line/character are 0-indexed, but what we
// get from hoverifier is 1-indexed.
line: props.token.line - 1,
character: props.token.character - 1,
line: props.token.range.start.line - 1,
character: props.token.range.start.character - 1,
filter: debouncedFilter || null,
firstReferences: 100,
afterReferences: null,
Expand Down Expand Up @@ -1124,7 +1130,8 @@ const LoadingCodeIntelFailed: React.FunctionComponent<React.PropsWithChildren<{
)

function sessionStorageKeyFromToken(token: Token): string {
return `${token.repoName}@${token.commitID}/${token.filePath}?L${token.line}:${token.character}`
const start = token.range.start
return `${token.repoName}@${token.commitID}/${token.filePath}?L${start.line}:${start.character}`
}

function locationToUrl(location: Location): string {
Expand Down
Loading