mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 15:12:02 +00:00
- Remove support for toggling native tooltips from the browser extension. This let users choose to keep the browser extension installed and partially active on GitHub but not show Sourcegraph's hovers. This functionality is less important now that GitHub's new code nav no longer uses hovers. For old GitHub Enterprise server instances (and GitHub.com users who have not enabled the new code view), users can disable the browser extension if they want to disable Sourcegraph's hover functionality. - Remove hover alerts, which were used to warn users that the results are imprecise. We still show this in a hover badge, which is a much nicer UI for this than a dismissible warning (which felt more "CYA"). - Remove command palette because it was inextricable from notifications and it was only used by the Sourcegraph extension API (which is deprecated and will be removed). - Remove the old notifications UI, which showed notification messages in Sourcegraph and code host UIs. This is no longer necessary with the removal of the command palette, because it is no longer possible to invoke long-running actions whose errors must be shown in a separate, global UI. ## Test plan Existing tests suffice to test the existing code intelligence functionality. This PR just removes functionality.
238 lines
10 KiB
TypeScript
238 lines
10 KiB
TypeScript
import { Remote } from 'comlink'
|
|
import { asyncScheduler, Observable, of, Unsubscribable } from 'rxjs'
|
|
import { observeOn, take, toArray, map, first } from 'rxjs/operators'
|
|
import * as sourcegraph from 'sourcegraph'
|
|
|
|
import { MaybeLoadingResult } from '@sourcegraph/codeintellify'
|
|
import { MarkupKind } from '@sourcegraph/extension-api-classes'
|
|
import { Location } from '@sourcegraph/extension-api-types'
|
|
|
|
import { assertToJSON, createBarrier, integrationTestContext } from '../../testing/testHelpers'
|
|
import { wrapRemoteObservable } from '../client/api/common'
|
|
import { FlatExtensionHostAPI } from '../contract'
|
|
|
|
describe('LanguageFeatures (integration)', () => {
|
|
testLocationProvider<sourcegraph.HoverProvider>({
|
|
name: 'registerHoverProvider',
|
|
registerProvider: extensionAPI => (selector, provider) =>
|
|
extensionAPI.languages.registerHoverProvider(selector, provider),
|
|
labeledProvider: label => ({
|
|
provideHover: (textDocument: sourcegraph.TextDocument, position: sourcegraph.Position) =>
|
|
of({
|
|
contents: { value: label, kind: MarkupKind.PlainText },
|
|
}).pipe(observeOn(asyncScheduler)),
|
|
}),
|
|
labeledProviderResults: labels => ({
|
|
contents: labels.map(label => ({ value: label, kind: MarkupKind.PlainText })),
|
|
aggregatedBadges: [],
|
|
}),
|
|
providerWithImplementation: run => ({ provideHover: run } as sourcegraph.HoverProvider),
|
|
getResult: (uri, extensionHostAPI) =>
|
|
wrapRemoteObservable(
|
|
extensionHostAPI.getHover({
|
|
textDocument: { uri },
|
|
position: { line: 1, character: 2 },
|
|
})
|
|
),
|
|
emptyResultValue: null,
|
|
})
|
|
testLocationProvider<sourcegraph.DefinitionProvider>({
|
|
name: 'registerDefinitionProvider',
|
|
registerProvider: extensionAPI => extensionAPI.languages.registerDefinitionProvider,
|
|
labeledProvider: label => ({
|
|
provideDefinition: (textDocument: sourcegraph.TextDocument, position: sourcegraph.Position) =>
|
|
of([{ uri: new URL(`file:///${label}`) }]).pipe(observeOn(asyncScheduler)),
|
|
}),
|
|
labeledProviderResults: labeledDefinitionResults,
|
|
providerWithImplementation: run => ({ provideDefinition: run } as sourcegraph.DefinitionProvider),
|
|
getResult: (uri, extensionHostAPI) =>
|
|
wrapRemoteObservable(
|
|
extensionHostAPI.getDefinition({
|
|
textDocument: { uri },
|
|
position: { line: 1, character: 2 },
|
|
})
|
|
),
|
|
emptyResultValue: [],
|
|
})
|
|
testLocationProvider<sourcegraph.ReferenceProvider>({
|
|
name: 'registerReferenceProvider',
|
|
registerProvider: extensionAPI => extensionAPI.languages.registerReferenceProvider,
|
|
labeledProvider: label => ({
|
|
provideReferences: (
|
|
textDocument: sourcegraph.TextDocument,
|
|
position: sourcegraph.Position,
|
|
context: sourcegraph.ReferenceContext
|
|
) => of([{ uri: new URL(`file:///${label}`) }]).pipe(observeOn(asyncScheduler)),
|
|
}),
|
|
labeledProviderResults: labels => labels.map(label => ({ uri: `file:///${label}`, range: undefined })),
|
|
providerWithImplementation: run =>
|
|
({
|
|
provideReferences: (
|
|
textDocument: sourcegraph.TextDocument,
|
|
position: sourcegraph.Position,
|
|
_context: sourcegraph.ReferenceContext
|
|
) => run(textDocument, position),
|
|
} as sourcegraph.ReferenceProvider),
|
|
getResult: (uri, extensionHostAPI) =>
|
|
wrapRemoteObservable(
|
|
extensionHostAPI.getReferences(
|
|
{
|
|
textDocument: { uri },
|
|
position: { line: 1, character: 2 },
|
|
},
|
|
{ includeDeclaration: true }
|
|
)
|
|
),
|
|
emptyResultValue: [],
|
|
})
|
|
testLocationProvider<sourcegraph.LocationProvider>({
|
|
name: 'registerLocationProvider',
|
|
registerProvider: extensionAPI => (selector, provider) =>
|
|
extensionAPI.languages.registerLocationProvider('x', selector, provider),
|
|
labeledProvider: label => ({
|
|
provideLocations: (textDocument: sourcegraph.TextDocument, position: sourcegraph.Position) =>
|
|
of([{ uri: new URL(`file:///${label}`) }]).pipe(observeOn(asyncScheduler)),
|
|
}),
|
|
labeledProviderResults: labels => labels.map(label => ({ uri: `file:///${label}`, range: undefined })),
|
|
providerWithImplementation: run =>
|
|
({
|
|
provideLocations: (textDocument: sourcegraph.TextDocument, position: sourcegraph.Position) =>
|
|
run(textDocument, position),
|
|
} as sourcegraph.LocationProvider),
|
|
getResult: (uri, extensionHostAPI) =>
|
|
wrapRemoteObservable(
|
|
extensionHostAPI.getLocations('x', {
|
|
textDocument: { uri },
|
|
position: { line: 1, character: 2 },
|
|
})
|
|
),
|
|
emptyResultValue: [],
|
|
})
|
|
})
|
|
|
|
/**
|
|
* Generates test cases for sourcegraph.languages.registerXyzProvider functions and their associated
|
|
* XyzProviders, for providers that return a list of locations.
|
|
*/
|
|
function testLocationProvider<P>({
|
|
name,
|
|
registerProvider,
|
|
labeledProvider,
|
|
labeledProviderResults,
|
|
providerWithImplementation,
|
|
getResult,
|
|
emptyResultValue,
|
|
}: {
|
|
name: keyof typeof sourcegraph.languages
|
|
registerProvider: (
|
|
extensionAPI: typeof sourcegraph
|
|
) => (selector: sourcegraph.DocumentSelector, provider: P) => Unsubscribable
|
|
labeledProvider: (label: string) => P
|
|
labeledProviderResults: (labels: string[]) => any
|
|
providerWithImplementation: (
|
|
run: (textDocument: sourcegraph.TextDocument, position: sourcegraph.Position) => void
|
|
) => P
|
|
getResult: (uri: string, extensionHostAPI: Remote<FlatExtensionHostAPI>) => Observable<MaybeLoadingResult<unknown>>
|
|
emptyResultValue: unknown
|
|
}): void {
|
|
describe(`languages.${name}`, () => {
|
|
it('registers and unregisters a single provider', async () => {
|
|
const { extensionAPI, extensionHostAPI } = await integrationTestContext()
|
|
|
|
// Register the provider and call it.
|
|
const subscription = registerProvider(extensionAPI)(['*'], labeledProvider('a'))
|
|
await extensionAPI.internal.sync()
|
|
expect(
|
|
await getResult('file:///f', extensionHostAPI)
|
|
.pipe(
|
|
first(({ isLoading }) => !isLoading),
|
|
map(({ result }) => result)
|
|
)
|
|
.toPromise()
|
|
).toEqual(labeledProviderResults(['a']))
|
|
|
|
// Unregister the provider and ensure it's removed.
|
|
subscription.unsubscribe()
|
|
expect(
|
|
await getResult('file:///f', extensionHostAPI)
|
|
.pipe(
|
|
first(({ isLoading }) => !isLoading),
|
|
map(({ result }) => result)
|
|
)
|
|
.toPromise()
|
|
).toEqual(emptyResultValue)
|
|
})
|
|
|
|
it('syncs with models', async () => {
|
|
const { extensionHostAPI, extensionAPI } = await integrationTestContext()
|
|
|
|
const subscription = registerProvider(extensionAPI)(['*'], labeledProvider('a'))
|
|
await extensionAPI.internal.sync()
|
|
|
|
await extensionHostAPI.addTextDocumentIfNotExists({
|
|
uri: 'file:///f2',
|
|
languageId: 'l1',
|
|
text: 't1',
|
|
})
|
|
await extensionHostAPI.addViewerIfNotExists({
|
|
type: 'CodeEditor',
|
|
resource: 'file:///f2',
|
|
selections: [],
|
|
isActive: true,
|
|
})
|
|
|
|
expect(
|
|
await getResult('file:///f2', extensionHostAPI)
|
|
.pipe(
|
|
first(({ isLoading }) => !isLoading),
|
|
map(({ result }) => result)
|
|
)
|
|
.toPromise()
|
|
).toEqual(labeledProviderResults(['a']))
|
|
|
|
subscription.unsubscribe()
|
|
})
|
|
|
|
it('supplies params to the provideXyz method', async () => {
|
|
const { extensionHostAPI, extensionAPI } = await integrationTestContext()
|
|
const { wait, done } = createBarrier()
|
|
registerProvider(extensionAPI)(
|
|
['*'],
|
|
providerWithImplementation((textDocument, position) => {
|
|
assertToJSON(textDocument, { uri: 'file:///f', languageId: 'l', text: 't' })
|
|
assertToJSON(position, { line: 1, character: 2 })
|
|
done()
|
|
})
|
|
)
|
|
await extensionAPI.internal.sync()
|
|
await getResult('file:///f', extensionHostAPI)
|
|
.pipe(
|
|
first(({ isLoading }) => !isLoading),
|
|
map(({ result }) => result)
|
|
)
|
|
.toPromise()
|
|
await wait
|
|
})
|
|
|
|
it('supports multiple providers', async () => {
|
|
const { extensionHostAPI, extensionAPI } = await integrationTestContext()
|
|
|
|
// Register 2 providers with different results.
|
|
registerProvider(extensionAPI)(['*'], labeledProvider('a'))
|
|
registerProvider(extensionAPI)(['*'], labeledProvider('b'))
|
|
await extensionAPI.internal.sync()
|
|
|
|
// Expect it to emit the first provider's result first (and not block on both providers being ready).
|
|
expect(await getResult('file:///f', extensionHostAPI).pipe(take(3), toArray()).toPromise()).toEqual([
|
|
{ isLoading: true, result: emptyResultValue },
|
|
{ isLoading: true, result: labeledProviderResults(['a']) },
|
|
{ isLoading: false, result: labeledProviderResults(['a', 'b']) },
|
|
])
|
|
})
|
|
})
|
|
}
|
|
|
|
function labeledDefinitionResults(labels: string[]): Location[] {
|
|
return labels.map(label => ({ uri: `file:///${label}`, range: undefined }))
|
|
}
|