diff --git a/client/shared/BUILD.bazel b/client/shared/BUILD.bazel index 3697cb4aa9f..1a6cf173353 100644 --- a/client/shared/BUILD.bazel +++ b/client/shared/BUILD.bazel @@ -143,7 +143,6 @@ ts_project( "src/api/extension/util.ts", "src/api/extension/utils/ReferenceCounter.ts", "src/api/extension/worker.ts", - "src/api/features.ts", "src/api/sharedEventLogger.ts", "src/api/textDocumentTypes.ts", "src/api/util.ts", @@ -214,7 +213,6 @@ ts_project( "src/contributions/contributions.ts", "src/deprecated-theme-utils.ts", "src/extensions/controller.ts", - "src/extensions/createNoopLoadedController.ts", "src/extensions/createSyncLoadedController.ts", "src/extensions/extension.ts", "src/extensions/extensionManifest.ts", diff --git a/client/shared/src/api/features.ts b/client/shared/src/api/features.ts deleted file mode 100644 index 119739cbbab..00000000000 --- a/client/shared/src/api/features.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Remote } from 'comlink' -import { from } from 'rxjs' -import { switchMap } from 'rxjs/operators' - -import { memoizeObservable } from '@sourcegraph/common' - -import { wrapRemoteObservable } from './client/api/common' -import type { FlatExtensionHostAPI } from './contract' - -/** - * Typically used to display loading indicators re: ready state of extension features - */ -export const haveInitialExtensionsLoaded = memoizeObservable( - (extensionHostAPI: Promise>) => - from(extensionHostAPI).pipe( - switchMap(extensionHost => wrapRemoteObservable(extensionHost.haveInitialExtensionsLoaded())) - ), - () => 'haveInitialExtensionsLoaded' // only one instance -) diff --git a/client/shared/src/extensions/createNoopLoadedController.ts b/client/shared/src/extensions/createNoopLoadedController.ts deleted file mode 100644 index 6d101eeec43..00000000000 --- a/client/shared/src/extensions/createNoopLoadedController.ts +++ /dev/null @@ -1,61 +0,0 @@ -import type { Remote } from 'comlink' - -import { type ExposedToClient, initMainThreadAPI } from '../api/client/mainthread-api' -import type { FlatExtensionHostAPI } from '../api/contract' -import { createExtensionHostAPI } from '../api/extension/extensionHostApi' -import { createExtensionHostState } from '../api/extension/extensionHostState' -import { pretendRemote, syncPromiseSubscription } from '../api/util' -import type { PlatformContext } from '../platform/context' -import { isSettingsValid } from '../settings/settings' - -import type { Controller } from './controller' - -export function createNoopController(platformContext: PlatformContext): Controller { - const api: Promise<{ - remoteExtensionHostAPI: Remote - exposedToClient: ExposedToClient - }> = new Promise((resolve, reject) => { - platformContext.settings.subscribe(settingsCascade => { - ;(async () => { - const [injectNewCodeintel, newSettingsGetter] = await Promise.all([ - import('../codeintel/api').then(module => module.injectNewCodeintel), - import('../codeintel/legacy-extensions/api').then(module => module.newSettingsGetter), - ]) - - if (!isSettingsValid(settingsCascade)) { - throw new Error('Settings are not valid') - } - - const extensionHostState = createExtensionHostState( - { - clientApplication: 'sourcegraph', - initialSettings: settingsCascade, - }, - null, - null - ) - const extensionHostAPI = injectNewCodeintel(createExtensionHostAPI(extensionHostState), { - requestGraphQL: platformContext.requestGraphQL, - telemetryService: platformContext.telemetryService, - settings: newSettingsGetter(settingsCascade), - }) - const remoteExtensionHostAPI = pretendRemote(extensionHostAPI) - const exposedToClient = initMainThreadAPI(remoteExtensionHostAPI, platformContext).exposedToClient - - // We don't have to load any extensions so we are already done - extensionHostState.haveInitialExtensionsLoaded.next(true) - - return { remoteExtensionHostAPI, exposedToClient } - })().then(resolve, reject) - }) - }) - return { - executeCommand: parameters => api.then(({ exposedToClient }) => exposedToClient.executeCommand(parameters)), - registerCommand: entryToRegister => - syncPromiseSubscription( - api.then(({ exposedToClient }) => exposedToClient.registerCommand(entryToRegister)) - ), - extHostAPI: api.then(({ remoteExtensionHostAPI }) => remoteExtensionHostAPI), - unsubscribe: () => {}, - } -} diff --git a/client/web/BUILD.bazel b/client/web/BUILD.bazel index 6d0d15115b9..2fa1557db51 100644 --- a/client/web/BUILD.bazel +++ b/client/web/BUILD.bazel @@ -173,7 +173,6 @@ ts_project( "src/auth/icons.tsx", "src/auth/withAuthenticatedUser.tsx", "src/backend/diff.ts", - "src/backend/features.ts", "src/backend/getPersistentCache.ts", "src/backend/graphql.ts", "src/backend/persistenceMapper.ts", @@ -1290,7 +1289,6 @@ ts_project( "src/repo/blob/codemirror/react-interop.tsx", "src/repo/blob/codemirror/scip-snapshot.ts", "src/repo/blob/codemirror/search.tsx", - "src/repo/blob/codemirror/sourcegraph-extensions.ts", "src/repo/blob/codemirror/static-highlights.tsx", "src/repo/blob/codemirror/tooltips/CodyTooltip.tsx", "src/repo/blob/codemirror/tooltips/HovercardView.tsx", @@ -1801,7 +1799,6 @@ ts_project( "//:node_modules/apollo3-cache-persist", "//:node_modules/bloomfilter", "//:node_modules/classnames", - "//:node_modules/comlink", "//:node_modules/copy-to-clipboard", "//:node_modules/d3-time-format", "//:node_modules/date-fns", diff --git a/client/web/src/LegacyLayout.tsx b/client/web/src/LegacyLayout.tsx index 5d6a257d0d6..2f8e2b1b871 100644 --- a/client/web/src/LegacyLayout.tsx +++ b/client/web/src/LegacyLayout.tsx @@ -253,11 +253,7 @@ export const LegacyLayout: FC = props => { )} {needsSiteInit && !isSiteInit && } - + {fuzzyFinder && ( { private readonly subscriptions = new Subscription() - private readonly extensionsController: ExtensionsController | null constructor(props: StaticAppConfig) { super(props) @@ -102,11 +99,6 @@ export class LegacySourcegraphWebApp extends React.Component { - logger.error('Error sending search context to extensions!', error) - }) } public componentWillUnmount(): void { @@ -223,7 +211,6 @@ export class LegacySourcegraphWebApp extends React.Component { this.setState({ selectedSearchContextSpec: spec }) - this.setWorkspaceSearchContext(spec).catch(error => { - logger.error('Error sending search context to extensions', error) - }) } private setSelectedSearchContextSpec = (spec: string): void => { @@ -334,14 +318,6 @@ export class LegacySourcegraphWebApp extends React.Component { - if (this.extensionsController === null) { - return - } - const extensionHostAPI = await this.extensionsController.extHostAPI - await extensionHostAPI.setSearchContext(spec) - } - private fetchHighlightedFileLineRanges = ( parameters: FetchFileParameters, force?: boolean | undefined diff --git a/client/web/src/SourcegraphWebApp.tsx b/client/web/src/SourcegraphWebApp.tsx index 7d357ea73b3..6bb7e48d476 100644 --- a/client/web/src/SourcegraphWebApp.tsx +++ b/client/web/src/SourcegraphWebApp.tsx @@ -8,7 +8,6 @@ import { combineLatest, from, Subscription, fromEvent } from 'rxjs' import { HTTPStatusError } from '@sourcegraph/http-client' import { SharedSpanName, TraceSpanProvider } from '@sourcegraph/observability-client' -import type { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import type { PlatformContext } from '@sourcegraph/shared/src/platform/context' import { ShortcutProvider } from '@sourcegraph/shared/src/react-shortcuts' import { @@ -51,7 +50,6 @@ import { siteSubjectNoAdmin, viewerSubjectFromSettings } from './util/settings' export interface StaticSourcegraphWebAppContext { setSelectedSearchContextSpec: (spec: string) => void platformContext: PlatformContext - extensionsController: ExtensionsControllerProps['extensionsController'] | null } export interface DynamicSourcegraphWebAppContext { @@ -235,7 +233,6 @@ export const SourcegraphWebApp: FC = props => { const staticContext = { setSelectedSearchContextSpec, platformContext, - extensionsController: null, } satisfies StaticSourcegraphWebAppContext const dynamicContext = { diff --git a/client/web/src/backend/features.ts b/client/web/src/backend/features.ts deleted file mode 100644 index 53faf943c08..00000000000 --- a/client/web/src/backend/features.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { type Observable, from, concat } from 'rxjs' -import { switchMap } from 'rxjs/operators' - -import type { HoverMerged } from '@sourcegraph/client-api' -import type { MaybeLoadingResult } from '@sourcegraph/codeintellify' -import { wrapRemoteObservable } from '@sourcegraph/shared/src/api/client/api/common' -import type { DocumentHighlight } from '@sourcegraph/shared/src/codeintel/legacy-extensions/api' -import type { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' -import { - type FileSpec, - type UIPositionSpec, - type RepoSpec, - type ResolvedRevisionSpec, - toURIWithPath, -} from '@sourcegraph/shared/src/util/url' - -/** - * Fetches hover information for the given location. - * - * @param context the location - * @returns hover for the location - */ -export function getHover( - context: RepoSpec & ResolvedRevisionSpec & FileSpec & UIPositionSpec, - { extensionsController }: ExtensionsControllerProps<'extHostAPI'> -): Observable> { - return concat( - [{ isLoading: true, result: null }], - extensionsController !== null - ? from(extensionsController.extHostAPI).pipe( - switchMap(extensionHost => - wrapRemoteObservable( - extensionHost.getHover({ - textDocument: { - uri: toURIWithPath(context), - }, - position: { - character: context.position.character - 1, - line: context.position.line - 1, - }, - }) - ) - ) - ) - : [{ isLoading: false, result: null }] - ) -} - -/** - * Fetches document highlight information for the given location. - * - * @param context the location - * @returns document highlights for the location - */ -export function getDocumentHighlights( - context: RepoSpec & ResolvedRevisionSpec & FileSpec & UIPositionSpec, - { extensionsController }: ExtensionsControllerProps<'extHostAPI'> -): Observable { - return concat( - [[]], - extensionsController !== null - ? from(extensionsController.extHostAPI).pipe( - switchMap(extensionHost => - wrapRemoteObservable( - extensionHost.getDocumentHighlights({ - textDocument: { - uri: toURIWithPath(context), - }, - position: { - character: context.position.character - 1, - line: context.position.line - 1, - }, - }) - ) - ) - ) - : [[]] - ) -} diff --git a/client/web/src/codeintel/ReferencesPanel.mocks.ts b/client/web/src/codeintel/ReferencesPanel.mocks.ts index 76a648fd963..db3f1ea015b 100644 --- a/client/web/src/codeintel/ReferencesPanel.mocks.ts +++ b/client/web/src/codeintel/ReferencesPanel.mocks.ts @@ -682,7 +682,6 @@ const HIGHLIGHTED_FILE_MOCK = { } export const defaultProps: ReferencesPanelProps = { - extensionsController: null, telemetryService: NOOP_TELEMETRY_SERVICE, telemetryRecorder: noOpTelemetryRecorder, settingsCascade: { diff --git a/client/web/src/codeintel/ReferencesPanel.tsx b/client/web/src/codeintel/ReferencesPanel.tsx index 316bdb1e7ca..141e6a9b34e 100644 --- a/client/web/src/codeintel/ReferencesPanel.tsx +++ b/client/web/src/codeintel/ReferencesPanel.tsx @@ -13,7 +13,6 @@ import { type ErrorLike, logger, pluralize } from '@sourcegraph/common' import { Position } from '@sourcegraph/extension-api-classes' import type { FetchFileParameters } from '@sourcegraph/shared/src/backend/file' import { displayRepoName } from '@sourcegraph/shared/src/components/RepoLink' -import type { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import { HighlightResponseFormat } from '@sourcegraph/shared/src/graphql-operations' import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/context' import type { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings' @@ -72,7 +71,6 @@ export interface ReferencesPanelProps TelemetryProps, TelemetryV2Props, HoverThresholdProps, - ExtensionsControllerProps, HighlightedFileLineRangesProps { /** Whether to show the first loaded reference in mini code view */ jumpToFirst?: boolean diff --git a/client/web/src/codeintel/SideBlob.tsx b/client/web/src/codeintel/SideBlob.tsx index 0d4119355cd..4f64570beec 100644 --- a/client/web/src/codeintel/SideBlob.tsx +++ b/client/web/src/codeintel/SideBlob.tsx @@ -4,7 +4,6 @@ import classNames from 'classnames' import { Position } from '@sourcegraph/extension-api-classes' import { useQuery } from '@sourcegraph/http-client' -import { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import { PlatformContextProps } from '@sourcegraph/shared/src/platform/context' import { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings' import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry' @@ -24,12 +23,7 @@ import { FETCH_HIGHLIGHTED_BLOB } from './ReferencesPanelQueries' import styles from './ReferencesPanel.module.scss' -export interface SideBlobProps - extends TelemetryProps, - TelemetryV2Props, - SettingsCascadeProps, - PlatformContextProps, - ExtensionsControllerProps { +export interface SideBlobProps extends TelemetryProps, TelemetryV2Props, SettingsCascadeProps, PlatformContextProps { repository: string commitID: string file: string @@ -53,7 +47,6 @@ export const SideBlob: FC = props => { wrapLines = true, navigateToLineOnAnyClick = true, searchPanelConfig, - extensionsController, settingsCascade, telemetryService, telemetryRecorder, @@ -131,7 +124,6 @@ export const SideBlob: FC = props => { searchPanelConfig={searchPanelConfig} className={classNames(className, styles.sideBlobCode)} platformContext={platformContext} - extensionsController={extensionsController} settingsCascade={settingsCascade} telemetryService={telemetryService} telemetryRecorder={telemetryRecorder} diff --git a/client/web/src/communitySearchContexts/CommunitySearchContextPage.story.tsx b/client/web/src/communitySearchContexts/CommunitySearchContextPage.story.tsx index cca85b0120c..3ab0eb35a47 100644 --- a/client/web/src/communitySearchContexts/CommunitySearchContextPage.story.tsx +++ b/client/web/src/communitySearchContexts/CommunitySearchContextPage.story.tsx @@ -4,7 +4,6 @@ import { subDays } from 'date-fns' import { EMPTY, NEVER, type Observable, of } from 'rxjs' import { subtypeOf } from '@sourcegraph/common' -import type { ActionItemComponentProps } from '@sourcegraph/shared/src/actions/ActionItem' import type { SearchContextFields } from '@sourcegraph/shared/src/graphql-operations' import { noOpTelemetryRecorder } from '@sourcegraph/shared/src/telemetry' import { @@ -34,10 +33,6 @@ const config: Meta = { export default config -const EXTENSIONS_CONTROLLER: ActionItemComponentProps['extensionsController'] = { - executeCommand: () => new Promise(resolve => setTimeout(resolve, 750)), -} - const PLATFORM_CONTEXT: CommunitySearchContextPageProps['platformContext'] = { settings: NEVER, sourcegraphURL: '', @@ -116,7 +111,6 @@ const commonProps = () => patternType: SearchPatternType.standard, setPatternType: action('setPatternType'), caseSensitive: false, - extensionsController: { ...EXTENSIONS_CONTROLLER }, platformContext: PLATFORM_CONTEXT, setCaseSensitivity: action('setCaseSensitivity'), activation: undefined, diff --git a/client/web/src/communitySearchContexts/CommunitySearchContextPage.tsx b/client/web/src/communitySearchContexts/CommunitySearchContextPage.tsx index 349e63f672d..dff3571f5f8 100644 --- a/client/web/src/communitySearchContexts/CommunitySearchContextPage.tsx +++ b/client/web/src/communitySearchContexts/CommunitySearchContextPage.tsx @@ -8,7 +8,6 @@ import { catchError, startWith } from 'rxjs/operators' import { SyntaxHighlightedSearchQuery } from '@sourcegraph/branded' import { asError, isErrorLike } from '@sourcegraph/common' import { displayRepoName } from '@sourcegraph/shared/src/components/RepoLink' -import type { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/context' import type { QueryState, SearchContextInputProps, SearchContextProps } from '@sourcegraph/shared/src/search' import type { SettingsCascadeProps, Settings } from '@sourcegraph/shared/src/settings/settings' @@ -40,7 +39,6 @@ const specTypes: { [k in CommunitySearchContextSpecs]: number } = { export interface CommunitySearchContextPageProps extends SettingsCascadeProps, - ExtensionsControllerProps<'executeCommand'>, PlatformContextProps<'settings' | 'sourcegraphURL' | 'requestGraphQL' | 'telemetryRecorder'>, SearchContextInputProps, Pick { diff --git a/client/web/src/components/legacyLayoutRouteContext.mock.ts b/client/web/src/components/legacyLayoutRouteContext.mock.ts index 912df4a5eb9..5899a70b0e9 100644 --- a/client/web/src/components/legacyLayoutRouteContext.mock.ts +++ b/client/web/src/components/legacyLayoutRouteContext.mock.ts @@ -31,7 +31,6 @@ export const injectedAppConfig = {} as unknown as StaticInjectedAppConfig export const staticWebAppConfig = { setSelectedSearchContextSpec: () => {}, platformContext: NOOP_PLATFORM_CONTEXT as PlatformContext, - extensionsController: null, } satisfies StaticSourcegraphWebAppContext export const dynamicWebAppConfig = { diff --git a/client/web/src/contributions.ts b/client/web/src/contributions.ts index 095ae1de0ac..dc6fc043103 100644 --- a/client/web/src/contributions.ts +++ b/client/web/src/contributions.ts @@ -1,34 +1,10 @@ -import { useEffect, useRef, useState } from 'react' - -import { type NavigateFunction, useLocation, useNavigate } from 'react-router-dom' -import { Subscription } from 'rxjs' - -import type { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' -import { registerHoverContributions } from '@sourcegraph/shared/src/hover/actions' -import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/context' - -interface Props extends ExtensionsControllerProps, PlatformContextProps {} +import { useEffect, useState } from 'react' /** * A component that registers global contributions. It is implemented as a React component so that its * registrations use the React lifecycle. */ -export function GlobalContributions(props: Props): null { - const { extensionsController, platformContext } = props - - const location = useLocation() - const navigate = useNavigate() - - // Location and navigate may be used by the hover contributions after they - // are initialized and closed over. To avoid stale data, we keep them in - // refs. - const locationRef = useRef(location) - const navigateRef = useRef(navigate) - useEffect(() => { - locationRef.current = location - navigateRef.current = navigate - }, [location, navigate]) - +export function GlobalContributions(): null { const [error, setError] = useState(null) useEffect(() => { @@ -38,24 +14,6 @@ export function GlobalContributions(props: Props): null { .catch(setError) }, []) - useEffect(() => { - const subscriptions = new Subscription() - if (extensionsController !== null) { - const historyOrNavigate: NavigateFunction = ((to: any, options: any): void => - navigateRef.current?.(to, options)) as any - subscriptions.add( - registerHoverContributions({ - platformContext, - historyOrNavigate, - getLocation: () => locationRef.current, - extensionsController, - locationAssign: globalThis.location.assign.bind(globalThis.location), - }) - ) - } - return () => subscriptions.unsubscribe() - }, [extensionsController, platformContext]) - // Throw error to the if (error) { throw error diff --git a/client/web/src/repo/RepoContainer.tsx b/client/web/src/repo/RepoContainer.tsx index 1917b08a0d7..65ab0edec1d 100644 --- a/client/web/src/repo/RepoContainer.tsx +++ b/client/web/src/repo/RepoContainer.tsx @@ -19,14 +19,13 @@ import { NEVER, of } from 'rxjs' import { catchError, switchMap } from 'rxjs/operators' import type { StreamingSearchResultsListProps } from '@sourcegraph/branded' -import { asError, type ErrorLike, isErrorLike, logger, repeatUntil } from '@sourcegraph/common' +import { asError, type ErrorLike, isErrorLike, repeatUntil } from '@sourcegraph/common' import { isCloneInProgressErrorLike, isRepoSeeOtherErrorLike, isRevisionNotFoundErrorLike, } from '@sourcegraph/shared/src/backend/errors' import { RepoQuestionIcon } from '@sourcegraph/shared/src/components/icons' -import type { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import { useKeyboardShortcut } from '@sourcegraph/shared/src/keyboardShortcuts/useKeyboardShortcut' import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/context' import { Shortcut } from '@sourcegraph/shared/src/react-shortcuts' @@ -36,7 +35,6 @@ import { escapeSpaces } from '@sourcegraph/shared/src/search/query/filters' import type { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings' import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService' import { lazyComponent } from '@sourcegraph/shared/src/util/lazyComponent' -import { makeRepoURI } from '@sourcegraph/shared/src/util/url' import { LoadingSpinner, Panel, useObservable } from '@sourcegraph/wildcard' import type { AuthenticatedUser } from '../auth' @@ -86,7 +84,6 @@ const RepoSettingsArea = lazyComponent(() => import('./settings/RepoSettingsArea export interface RepoContainerContext extends RepoHeaderContributionsLifecycleProps, SettingsCascadeProps, - ExtensionsControllerProps, PlatformContextProps, HoverThresholdProps, TelemetryProps, @@ -123,7 +120,6 @@ interface RepoContainerProps extends SettingsCascadeProps, PlatformContextProps, TelemetryProps, - ExtensionsControllerProps, Pick, BreadcrumbSetters, BreadcrumbsProps, @@ -330,7 +326,7 @@ const RepoUserContainer: FC = ({ repoHeaderContributionsLifecycleProps, ...props }) => { - const { extensionsController, repoContainerRoutes, authenticatedUser, selectedSearchContextSpec } = props + const { repoContainerRoutes, authenticatedUser, selectedSearchContextSpec } = props const location = useLocation() @@ -365,41 +361,6 @@ const RepoUserContainer: FC = ({ // The external links to show in the repository header, if any. const [externalLinks, setExternalLinks] = useState() - // Update the workspace roots service to reflect the current repo / resolved revision - useEffect(() => { - const workspaceRootUri = - resolvedRevisionOrError && - !isErrorLike(resolvedRevisionOrError) && - makeRepoURI({ - repoName, - revision: resolvedRevisionOrError.commitID, - }) - - if (workspaceRootUri && extensionsController !== null) { - extensionsController.extHostAPI - .then(extensionHostAPI => - extensionHostAPI.addWorkspaceRoot({ - uri: workspaceRootUri, - inputRevision: revision || '', - }) - ) - .catch(error => { - logger.error('Error adding workspace root', error) - }) - } - - // Clear the Sourcegraph extensions model's roots when navigating away. - return () => { - if (workspaceRootUri && extensionsController !== null) { - extensionsController.extHostAPI - .then(extensionHostAPI => extensionHostAPI.removeWorkspaceRoot(workspaceRootUri)) - .catch(error => { - logger.error('Error removing workspace root', error) - }) - } - } - }, [extensionsController, repoName, resolvedRevisionOrError, revision]) - // Update the navbar query to reflect the current repo / revision const [enableV2QueryInput] = useV2QueryInput() const queryPrefix = useMemo( diff --git a/client/web/src/repo/RepoRevisionContainer.tsx b/client/web/src/repo/RepoRevisionContainer.tsx index ffd239ad1e9..c9df3d24bcc 100644 --- a/client/web/src/repo/RepoRevisionContainer.tsx +++ b/client/web/src/repo/RepoRevisionContainer.tsx @@ -4,7 +4,6 @@ import { Route, Routes } from 'react-router-dom' import type { StreamingSearchResultsListProps } from '@sourcegraph/branded' import { isErrorLike } from '@sourcegraph/common' -import type { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/context' import type { SearchContextProps } from '@sourcegraph/shared/src/search' import type { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings' @@ -49,7 +48,6 @@ import styles from './RepoRevisionContainer.module.scss' export interface RepoRevisionContainerContext extends RepoHeaderContributionsLifecycleProps, SettingsCascadeProps, - ExtensionsControllerProps, PlatformContextProps, TelemetryProps, HoverThresholdProps, @@ -83,7 +81,6 @@ interface RepoRevisionContainerProps PlatformContextProps, TelemetryProps, HoverThresholdProps, - ExtensionsControllerProps, Pick, RevisionSpec, BreadcrumbSetters, diff --git a/client/web/src/repo/blob/BlobPage.tsx b/client/web/src/repo/blob/BlobPage.tsx index 685725bd18a..9e550a74284 100644 --- a/client/web/src/repo/blob/BlobPage.tsx +++ b/client/web/src/repo/blob/BlobPage.tsx @@ -21,7 +21,6 @@ import { useCurrentSpan, } from '@sourcegraph/observability-client' import type { FetchFileParameters } from '@sourcegraph/shared/src/backend/file' -import type { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import { HighlightResponseFormat } from '@sourcegraph/shared/src/graphql-operations' import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/context' import type { SearchContextProps } from '@sourcegraph/shared/src/search' @@ -100,7 +99,6 @@ interface BlobPageProps PlatformContextProps, TelemetryProps, TelemetryV2Props, - ExtensionsControllerProps, HoverThresholdProps, BreadcrumbSetters, SearchStreamingProps, @@ -609,7 +607,6 @@ export const BlobPage: React.FunctionComponent = ({ className, co blobInfo={{ ...blobInfoOrError, commitID }} wrapCode={wrapCode} platformContext={props.platformContext} - extensionsController={props.extensionsController} settingsCascade={props.settingsCascade} onHoverShown={props.onHoverShown} telemetryService={props.telemetryService} diff --git a/client/web/src/repo/blob/CodeMirrorBlob.tsx b/client/web/src/repo/blob/CodeMirrorBlob.tsx index 499276424a5..bda7c3bb126 100644 --- a/client/web/src/repo/blob/CodeMirrorBlob.tsx +++ b/client/web/src/repo/blob/CodeMirrorBlob.tsx @@ -22,7 +22,6 @@ import { } from '@sourcegraph/common' import { getOrCreateCodeIntelAPI, type CodeIntelAPI } from '@sourcegraph/shared/src/codeintel/api' import { editorHeight, useCodeMirror, useCompartment } from '@sourcegraph/shared/src/components/CodeMirrorEditor' -import type { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import { useKeyboardShortcut } from '@sourcegraph/shared/src/keyboardShortcuts/useKeyboardShortcut' import type { PlatformContext, PlatformContextProps } from '@sourcegraph/shared/src/platform/context' import { Shortcut } from '@sourcegraph/shared/src/react-shortcuts' @@ -65,7 +64,6 @@ import { navigateToLineOnAnyClickExtension } from './codemirror/navigate-to-any- import { CodeMirrorContainer } from './codemirror/react-interop' import { scipSnapshot } from './codemirror/scip-snapshot' import { search, type SearchPanelConfig } from './codemirror/search' -import { sourcegraphExtensions } from './codemirror/sourcegraph-extensions' import { staticHighlights, type Range } from './codemirror/static-highlights' import { codyWidgetExtension } from './codemirror/tooltips/CodyTooltip' import { HovercardView } from './codemirror/tooltips/HovercardView' @@ -98,7 +96,6 @@ export interface BlobProps TelemetryProps, TelemetryV2Props, HoverThresholdProps, - ExtensionsControllerProps, CodeMirrorBlobProps { className: string @@ -217,7 +214,6 @@ export const CodeMirrorBlob: React.FunctionComponent = props => { wrapCode, ariaLabel, role, - extensionsController, isBlameVisible, blameHunks, ocgVisibility, @@ -395,13 +391,6 @@ export const CodeMirrorBlob: React.FunctionComponent = props => { pinnedTooltip, navigateToLineOnAnyClick ? navigateToLineOnAnyClickExtension(navigate) : codeIntelExtension, syntaxHighlight.of(blobInfo), - extensionsController !== null && !navigateToLineOnAnyClick - ? sourcegraphExtensions({ - blobInfo, - initialSelection: position, - extensionsController, - }) - : [], blobProps, blameDecorations, wrapCodeSettings, @@ -426,7 +415,6 @@ export const CodeMirrorBlob: React.FunctionComponent = props => { staticHighlightRanges, navigate, blobInfo, - extensionsController, isCodyEnabled, openCodeGraphExtension, codeIntelExtension, diff --git a/client/web/src/repo/blob/codemirror/sourcegraph-extensions.ts b/client/web/src/repo/blob/codemirror/sourcegraph-extensions.ts deleted file mode 100644 index 05d52224d48..00000000000 --- a/client/web/src/repo/blob/codemirror/sourcegraph-extensions.ts +++ /dev/null @@ -1,165 +0,0 @@ -/** - * This file contains CodeMirror extensions to integrate with Sourcegraph - * extensions. - * - * This integration is done in various ways, see the specific extensions for - * more information. - */ - -import type { Extension } from '@codemirror/state' -import { type PluginValue, ViewPlugin, type ViewUpdate } from '@codemirror/view' -import type { Remote } from 'comlink' -import { combineLatest, EMPTY, from, type Observable, Subject, Subscription } from 'rxjs' -import { catchError, map, shareReplay, switchMap } from 'rxjs/operators' - -import { type LineOrPositionOrRange, logger, lprToSelectionsZeroIndexed } from '@sourcegraph/common' -import type { FlatExtensionHostAPI } from '@sourcegraph/shared/src/api/contract' -import { haveInitialExtensionsLoaded } from '@sourcegraph/shared/src/api/features' -import type { ViewerId } from '@sourcegraph/shared/src/api/viewerTypes' -import type { RequiredExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' -import { toURIWithPath } from '@sourcegraph/shared/src/util/url' - -import type { BlobInfo } from '../CodeMirrorBlob' - -import { type SelectedLineRange, selectedLines } from './linenumbers' - -/** - * Context holds all the information needed for CodeMirror extensions to - * communicate with the extensions host. - */ -interface Context { - viewerId: ViewerId - extensionsController: RequiredExtensionsControllerProps['extensionsController'] - extensionHostAPI: Remote - blobInfo: BlobInfo -} - -/** - * Enables integration with Sourcegraph extensions: - * - Document highlights - * - Hovercards (partially) - * - Selection updates - * - Reference panel warmup - */ -export function sourcegraphExtensions({ - blobInfo, - initialSelection, - extensionsController, -}: { - blobInfo: BlobInfo - initialSelection: LineOrPositionOrRange - extensionsController: RequiredExtensionsControllerProps['extensionsController'] -}): Extension { - const subscriptions = new Subscription() - - // Initialize document and viewer as early as possible and make context - // available as observable - const contextObservable = from( - extensionsController.extHostAPI.then(async extensionHostAPI => { - const uri = toURIWithPath(blobInfo) - - const [, viewerId] = await Promise.all([ - // This call should be made before adding viewer, but since - // messages to web worker are handled in order, we can use Promise.all - extensionHostAPI.addTextDocumentIfNotExists({ - uri, - languageId: blobInfo.mode, - text: blobInfo.content, - }), - extensionHostAPI.addViewerIfNotExists({ - type: 'CodeEditor' as const, - resource: uri, - selections: lprToSelectionsZeroIndexed(initialSelection), - isActive: true, - }), - ]) - - return [viewerId, extensionHostAPI] as [ViewerId, Remote] - }) - ).pipe( - catchError(() => { - logger.error('Unable to initialize extensions context') - return EMPTY - }), - map(([viewerId, extensionHostAPI]) => { - subscriptions.add(() => { - extensionHostAPI - .removeViewer(viewerId) - .catch(error => logger.error('Error removing viewer from extension host', error)) - }) - - return { - blobInfo, - viewerId, - extensionHostAPI, - extensionsController, - } - }), - shareReplay(1) - ) - - return [ - // This view plugin is used to have a way to cleanup any resources via the - // `destroy` method. - ViewPlugin.define(() => ({ - destroy() { - subscriptions.unsubscribe() - }, - })), - ViewPlugin.define(() => new SelectionManager(contextObservable)), - ViewPlugin.define(() => new WarmupReferencesManager(contextObservable)), - ] -} - -// -// Selection change notifier -// - -/** - * The selection manager listens to CodeMirror selection changes and sends them - * to the extensions host. - */ -class SelectionManager implements PluginValue { - private nextSelection: Subject = new Subject() - private subscription = new Subscription() - - constructor(context: Observable) { - this.subscription = combineLatest([context, this.nextSelection]).subscribe(([context, selection]) => { - // Used to convert SelectedLineRange type to a valid LineOrPositionOrRange type to keep TypeScript happy - let lprSelection: LineOrPositionOrRange = {} - if (selection) { - lprSelection = - selection.line !== selection.endLine - ? { line: selection.line, endLine: selection.endLine } - : { line: selection.line, character: selection.character } - } - context.extensionHostAPI - .setEditorSelections(context.viewerId, lprToSelectionsZeroIndexed(lprSelection)) - .catch(error => logger.error('Error updating editor selections on extension host', error)) - }) - } - - public destroy(): void { - this.subscription.unsubscribe() - } - - public update(update: ViewUpdate): void { - if (update.state.field(selectedLines) !== update.startState.field(selectedLines)) { - this.nextSelection.next(update.state.field(selectedLines)) - } - } -} - -class WarmupReferencesManager implements PluginValue { - private subscription: Subscription - - constructor(context: Observable) { - this.subscription = context - .pipe(switchMap(context => haveInitialExtensionsLoaded(context.extensionsController.extHostAPI))) - .subscribe() - } - - public destroy(): void { - this.subscription.unsubscribe() - } -} diff --git a/client/web/src/repo/blob/codemirror/tooltips/HovercardView.tsx b/client/web/src/repo/blob/codemirror/tooltips/HovercardView.tsx index 0d2cbd7726c..09ade9de280 100644 --- a/client/web/src/repo/blob/codemirror/tooltips/HovercardView.tsx +++ b/client/web/src/repo/blob/codemirror/tooltips/HovercardView.tsx @@ -19,7 +19,11 @@ type Unwrap = T extends Observable ? U : never // WebHoverOverlay expects to be passed the overlay position. Since CodeMirror // positions the element we always use the same value. -const dummyOverlayPosition = { left: 0, bottom: 0 } +const NOOP_OVERLAY_POSITION = { left: 0, bottom: 0 } + +// WebHoverOverlay is shared witht the browser extension and expects to be passed +// an extension controller. This is a dummy value that is never used. +const NOOP_EXTENSION_CONTROLLER = { executeCommand: () => Promise.resolve(undefined) } /** * This class is responsible for rendering a WebHoverOverlay component as a @@ -126,14 +130,14 @@ export class HovercardView implements TooltipView { platformContext={props.platformContext} settingsCascade={props.settingsCascade} telemetryService={props.telemetryService} - extensionsController={props.extensionsController} + extensionsController={NOOP_EXTENSION_CONTROLLER} // Hover props actionsOrError={actionsOrError} hoverOrError={hoverOrError} // CodeMirror handles the positioning but a // non-nullable value must be passed for the // hovercard to render - overlayPosition={dummyOverlayPosition} + overlayPosition={NOOP_OVERLAY_POSITION} hoveredToken={hoveredToken} pinOptions={{ showCloseButton: pinned, diff --git a/client/web/src/repo/blob/panel/BlobPanel.tsx b/client/web/src/repo/blob/panel/BlobPanel.tsx index a9e8b93e612..0a6d793d8b7 100644 --- a/client/web/src/repo/blob/panel/BlobPanel.tsx +++ b/client/web/src/repo/blob/panel/BlobPanel.tsx @@ -7,7 +7,6 @@ import { type Panel, useBuiltinTabbedPanelViews } from '@sourcegraph/branded/src import { PanelContent } from '@sourcegraph/branded/src/components/panel/views/PanelContent' import { isDefined, isErrorLike } from '@sourcegraph/common' import type { FetchFileParameters } from '@sourcegraph/shared/src/backend/file' -import type { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import type { Scalars } from '@sourcegraph/shared/src/graphql-operations' import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/context' import type { Settings, SettingsCascadeOrError, SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings' @@ -27,7 +26,6 @@ interface Props extends AbsoluteRepoFile, ModeSpec, SettingsCascadeProps, - ExtensionsControllerProps, PlatformContextProps, Pick, OwnConfigProps, @@ -47,7 +45,6 @@ export type BlobPanelTabID = 'info' | 'def' | 'references' | 'impl' | 'typedef' * A React hook that registers panel views for the blob. */ function useBlobPanelViews({ - extensionsController, revision, filePath, repoID, @@ -90,7 +87,6 @@ function useBlobPanelViews({ { subjects: null, final: null, }, - extensionsController: null, platformContext: { settings: NEVER, updateSettings: () => Promise.reject(new Error('updateSettings not implemented')), diff --git a/client/web/src/repo/tree/TreePage.tsx b/client/web/src/repo/tree/TreePage.tsx index 99ac6633c4a..d154c644830 100644 --- a/client/web/src/repo/tree/TreePage.tsx +++ b/client/web/src/repo/tree/TreePage.tsx @@ -18,18 +18,17 @@ import classNames from 'classnames' import { Navigate } from 'react-router-dom' import { catchError } from 'rxjs/operators' -import { asError, encodeURIPathComponent, type ErrorLike, isErrorLike, logger, basename } from '@sourcegraph/common' +import { asError, encodeURIPathComponent, type ErrorLike, isErrorLike, basename } from '@sourcegraph/common' import { gql, useQuery } from '@sourcegraph/http-client' import { fetchTreeEntries } from '@sourcegraph/shared/src/backend/repo' import { displayRepoName } from '@sourcegraph/shared/src/components/RepoLink' -import type { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/context' import type { Settings } from '@sourcegraph/shared/src/schema/settings.schema' import type { SearchContextProps } from '@sourcegraph/shared/src/search' import type { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings' import { noOpTelemetryRecorder } from '@sourcegraph/shared/src/telemetry' import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService' -import { toPrettyBlobURL, toURIWithPath } from '@sourcegraph/shared/src/util/url' +import { toPrettyBlobURL } from '@sourcegraph/shared/src/util/url' import { Badge, Button, @@ -81,7 +80,6 @@ const FILE_COMMITS_QUERY = gql` ` export interface Props extends SettingsCascadeProps, - ExtensionsControllerProps, PlatformContextProps, TelemetryProps, CodeIntelligenceProps, @@ -197,47 +195,8 @@ export const TreePage: FC = ({ }) const treeWithHistory = fileCommitData?.repository?.commit?.tree?.entries - const showCodeInsights = - !isErrorLike(settingsCascade.final) && - !!settingsCascade.final?.experimentalFeatures?.codeInsights && - settingsCascade.final['insights.displayLocation.directory'] === true - const showOwnership = ownEnabled && !isSourcegraphDotCom - // Add DirectoryViewer - const uri = toURIWithPath({ repoName, commitID, filePath }) - - const { extensionsController } = props - useEffect(() => { - if (!showCodeInsights || extensionsController === null) { - return - } - - const viewerIdPromise = extensionsController.extHostAPI - .then(extensionHostAPI => - extensionHostAPI.addViewerIfNotExists({ - type: 'DirectoryViewer', - isActive: true, - resource: uri, - }) - ) - .catch(error => { - logger.error('Error adding viewer to extension host:', error) - return null - }) - - return () => { - Promise.all([extensionsController.extHostAPI, viewerIdPromise]) - .then(([extensionHostAPI, viewerId]) => { - if (viewerId) { - return extensionHostAPI.removeViewer(viewerId) - } - return - }) - .catch(error => logger.error('Error removing viewer from extension host:', error)) - } - }, [uri, showCodeInsights, extensionsController]) - const getPageTitle = (): string => { const repoString = displayRepoName(repoName) if (filePath) { diff --git a/client/web/src/repo/tree/TreePageContent.tsx b/client/web/src/repo/tree/TreePageContent.tsx index 8a9612d5764..1c48cd10089 100644 --- a/client/web/src/repo/tree/TreePageContent.tsx +++ b/client/web/src/repo/tree/TreePageContent.tsx @@ -9,7 +9,6 @@ import { encodeURIPathComponent, numberWithCommas, pluralize } from '@sourcegrap import { gql, useQuery } from '@sourcegraph/http-client' import { TeamAvatar } from '@sourcegraph/shared/src/components/TeamAvatar' import { UserAvatar } from '@sourcegraph/shared/src/components/UserAvatar' -import type { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import { SearchPatternType, type TreeFields } from '@sourcegraph/shared/src/graphql-operations' import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/context' import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService' @@ -146,7 +145,7 @@ const ExtraInfoSection: React.FC<{ ) } -interface TreePageContentProps extends ExtensionsControllerProps, TelemetryProps, PlatformContextProps { +interface TreePageContentProps extends TelemetryProps, PlatformContextProps { filePath: string tree: TreeFields treeWithHistory?: TreeHistoryFields[] diff --git a/client/web/src/search/results/StreamingSearchResults.story.tsx b/client/web/src/search/results/StreamingSearchResults.story.tsx index b6ec1a3ed5d..7d78125d9c2 100644 --- a/client/web/src/search/results/StreamingSearchResults.story.tsx +++ b/client/web/src/search/results/StreamingSearchResults.story.tsx @@ -55,7 +55,6 @@ const defaultProps: StreamingSearchResultsProps = { searchAggregationEnabled: true, codeMonitoringEnabled: true, ownEnabled: true, - extensionsController: {} as any, } const decorator: Decorator = Story => { diff --git a/client/web/src/search/results/StreamingSearchResults.test.tsx b/client/web/src/search/results/StreamingSearchResults.test.tsx index d78201b8549..b050473abe8 100644 --- a/client/web/src/search/results/StreamingSearchResults.test.tsx +++ b/client/web/src/search/results/StreamingSearchResults.test.tsx @@ -58,7 +58,6 @@ describe('StreamingSearchResults', () => { searchAggregationEnabled: false, codeMonitoringEnabled: true, ownEnabled: true, - extensionsController: {} as any, } const revisionsMockResponses = generateMockedResponses(GitRefType.GIT_BRANCH, 5, 'github.com/golang/oauth2') diff --git a/client/web/src/search/results/StreamingSearchResults.tsx b/client/web/src/search/results/StreamingSearchResults.tsx index 5cdf414fad7..fcbdd0f29e0 100644 --- a/client/web/src/search/results/StreamingSearchResults.tsx +++ b/client/web/src/search/results/StreamingSearchResults.tsx @@ -5,7 +5,6 @@ import type { Observable } from 'rxjs' import { limitHit, useUrlFilters } from '@sourcegraph/branded' import type { FetchFileParameters } from '@sourcegraph/shared/src/backend/file' -import { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import { SearchPatternType } from '@sourcegraph/shared/src/graphql-operations' import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/context' import type { QueryUpdate, SearchContextProps } from '@sourcegraph/shared/src/search' @@ -40,8 +39,7 @@ export interface StreamingSearchResultsProps CodeInsightsProps, SearchAggregationProps, CodeMonitoringProps, - OwnConfigProps, - ExtensionsControllerProps { + OwnConfigProps { authenticatedUser: AuthenticatedUser | null isSourcegraphDotCom: boolean fetchHighlightedFileLineRanges: (parameters: FetchFileParameters, force?: boolean) => Observable @@ -56,7 +54,6 @@ export const StreamingSearchResults: FC = props => searchAggregationEnabled, codeMonitoringEnabled, platformContext, - extensionsController, } = props const location = useLocation() @@ -273,7 +270,6 @@ export const StreamingSearchResults: FC = props => settingsCascade={props.settingsCascade} telemetryService={telemetryService} platformContext={platformContext} - extensionsController={extensionsController} /> ) } diff --git a/client/web/src/search/results/components/new-search-content/NewSearchContent.tsx b/client/web/src/search/results/components/new-search-content/NewSearchContent.tsx index e7de4614532..35ac7aec382 100644 --- a/client/web/src/search/results/components/new-search-content/NewSearchContent.tsx +++ b/client/web/src/search/results/components/new-search-content/NewSearchContent.tsx @@ -17,7 +17,6 @@ import { Observable } from 'rxjs' import { StreamingProgress, StreamingSearchResultsList, useSearchResultState } from '@sourcegraph/branded' import { FetchFileParameters } from '@sourcegraph/shared/src/backend/file' import { FilePrefetcher } from '@sourcegraph/shared/src/components/PrefetchableFile' -import { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import { HighlightResponseFormat, SearchPatternType } from '@sourcegraph/shared/src/graphql-operations' import { PlatformContextProps } from '@sourcegraph/shared/src/platform/context' import { @@ -73,7 +72,6 @@ interface NewSearchContentProps extends TelemetryProps, SettingsCascadeProps, PlatformContextProps, - ExtensionsControllerProps, SearchPatternTypeProps, SearchPatternTypeMutationProps { submittedURLQuery: string @@ -127,7 +125,6 @@ export const NewSearchContent: FC = props => { codeMonitoringEnabled, options, platformContext, - extensionsController, onNavbarQueryChange, onSearchSubmit, onQuerySubmit, @@ -337,7 +334,6 @@ export const NewSearchContent: FC = props => { > = ) } -interface FilePreviewPanelProps - extends PlatformContextProps, - SettingsCascadeProps, - ExtensionsControllerProps, - TelemetryProps { +interface FilePreviewPanelProps extends PlatformContextProps, SettingsCascadeProps, TelemetryProps { blobInfo: SearchResultPreview onClose: () => void } const FilePreviewPanel: FC = props => { - const { blobInfo, onClose, platformContext, settingsCascade, extensionsController, telemetryService } = props + const { blobInfo, onClose, platformContext, settingsCascade, telemetryService } = props const staticHighlights = useMemo(() => { if (blobInfo.type === 'path') { @@ -440,7 +432,6 @@ const FilePreviewPanel: FC = props => { telemetryService={NOOP_TELEMETRY_SERVICE} // TODO (dadlerj): update to use a real telemetry recorder telemetryRecorder={noOpTelemetryRecorder} - extensionsController={extensionsController} staticHighlightRanges={staticHighlights} />