Skip to content
This repository was archived by the owner on Nov 6, 2018. It is now read-only.

Commit 63538c7

Browse files
committed
feat: new extension API in sourcegraph.d.ts, remove old code
BREAKING CHANGE: The extension API changed significantly for the alpha release. See `sourcegraph.d.ts`.
1 parent 4fa2930 commit 63538c7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+2380
-2634
lines changed

src/client/api/codeEditor.ts

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { BehaviorSubject, Observable, Subscription } from 'rxjs'
2+
import { handleRequests } from '../../common/proxy'
3+
import { Connection } from '../../protocol/jsonrpc2/connection'
4+
import { TextDocumentDecoration } from '../../protocol/plainTypes'
5+
import { ProvideTextDocumentDecorationSignature } from '../providers/decoration'
6+
import { FeatureProviderRegistry } from '../providers/registry'
7+
import { TextDocumentIdentifier } from '../types/textDocument'
8+
9+
/** @internal */
10+
export interface ClientCodeEditorAPI {
11+
$setDecorations(resource: string, decorations: TextDocumentDecoration[]): void
12+
}
13+
14+
/** @internal */
15+
export class ClientCodeEditor implements ClientCodeEditorAPI {
16+
private subscriptions = new Subscription()
17+
18+
/** Map of document URI to its decorations (last published by the server). */
19+
private decorations = new Map<string, BehaviorSubject<TextDocumentDecoration[] | null>>()
20+
21+
constructor(
22+
connection: Connection,
23+
private registry: FeatureProviderRegistry<undefined, ProvideTextDocumentDecorationSignature>
24+
) {
25+
this.subscriptions.add(
26+
this.registry.registerProvider(
27+
undefined,
28+
(textDocument: TextDocumentIdentifier): Observable<TextDocumentDecoration[] | null> =>
29+
this.getDecorationsSubject(textDocument.uri)
30+
)
31+
)
32+
33+
handleRequests(connection, 'codeEditor', this)
34+
}
35+
36+
public $setDecorations(resource: string, decorations: TextDocumentDecoration[]): void {
37+
this.getDecorationsSubject(resource, decorations)
38+
}
39+
40+
private getDecorationsSubject(
41+
resource: string,
42+
value?: TextDocumentDecoration[] | null
43+
): BehaviorSubject<TextDocumentDecoration[] | null> {
44+
let subject = this.decorations.get(resource)
45+
if (!subject) {
46+
subject = new BehaviorSubject<TextDocumentDecoration[] | null>(value || null)
47+
this.decorations.set(resource, subject)
48+
}
49+
if (value !== undefined) {
50+
subject.next(value)
51+
}
52+
return subject
53+
}
54+
55+
public unsubscribe(): void {
56+
// Clear decorations.
57+
for (const subject of this.decorations.values()) {
58+
subject.next(null)
59+
}
60+
61+
this.subscriptions.unsubscribe()
62+
}
63+
}

src/client/api/commands.ts

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { Subscription } from 'rxjs'
2+
import { createProxyAndHandleRequests } from '../../common/proxy'
3+
import { ExtCommandsAPI } from '../../extension/api/commands'
4+
import { Connection } from '../../protocol/jsonrpc2/connection'
5+
import { CommandRegistry } from '../providers/command'
6+
import { SubscriptionMap } from './common'
7+
8+
/** @internal */
9+
export interface ClientCommandsAPI {
10+
$unregister(id: number): void
11+
$registerCommand(id: number, command: string): void
12+
$executeCommand(command: string, args: any[]): Promise<any>
13+
}
14+
15+
/** @internal */
16+
export class ClientCommands implements ClientCommandsAPI {
17+
private subscriptions = new Subscription()
18+
private registrations = new SubscriptionMap()
19+
private proxy: ExtCommandsAPI
20+
21+
constructor(connection: Connection, private registry: CommandRegistry) {
22+
this.subscriptions.add(this.registrations)
23+
24+
this.proxy = createProxyAndHandleRequests('commands', connection, this)
25+
}
26+
27+
public $unregister(id: number): void {
28+
this.registrations.remove(id)
29+
}
30+
31+
public $registerCommand(id: number, command: string): void {
32+
this.registrations.add(
33+
id,
34+
this.registry.registerCommand({
35+
command,
36+
run: (...args: any[]): any => this.proxy.$executeCommand(id, args),
37+
})
38+
)
39+
}
40+
41+
public $executeCommand(command: string, args: any[]): Promise<any> {
42+
return this.registry.executeCommand({ command, arguments: args })
43+
}
44+
45+
public unsubscribe(): void {
46+
this.subscriptions.unsubscribe()
47+
}
48+
}

src/client/api/common.ts

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Unsubscribable } from 'sourcegraph'
2+
3+
/**
4+
* Manages a map of subscriptions keyed on a numeric ID.
5+
*
6+
* @internal
7+
*/
8+
export class SubscriptionMap {
9+
private map = new Map<number, Unsubscribable>()
10+
11+
/**
12+
* Adds a new subscription with the given {@link id}.
13+
*
14+
* @param id - A unique identifier for this subscription among all other entries in this map.
15+
* @param subscription - The subscription, unsubscribed when {@link SubscriptionMap#remove} is called.
16+
* @throws If there already exists an entry with the given {@link id}.
17+
*/
18+
public add(id: number, subscription: Unsubscribable): void {
19+
if (this.map.has(id)) {
20+
throw new Error(`subscription already exists with ID ${id}`)
21+
}
22+
this.map.set(id, subscription)
23+
}
24+
25+
/**
26+
* Unsubscribes the subscription that was previously added with the given {@link id}, and removes it from the
27+
* map.
28+
*/
29+
public remove(id: number): void {
30+
const subscription = this.map.get(id)
31+
if (!subscription) {
32+
throw new Error(`no subscription with ID ${id}`)
33+
}
34+
try {
35+
subscription.unsubscribe()
36+
} finally {
37+
this.map.delete(id)
38+
}
39+
}
40+
41+
/**
42+
* Unsubscribes all subscriptions in this map and clears it.
43+
*/
44+
public unsubscribe(): void {
45+
try {
46+
for (const subscription of this.map.values()) {
47+
subscription.unsubscribe()
48+
}
49+
} finally {
50+
this.map.clear()
51+
}
52+
}
53+
}

src/client/api/configuration.ts

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Observable, Subscription } from 'rxjs'
2+
import { createProxyAndHandleRequests } from '../../common/proxy'
3+
import { ExtConfigurationAPI } from '../../extension/api/configuration'
4+
import { ConfigurationUpdateParams } from '../../protocol'
5+
import { Connection } from '../../protocol/jsonrpc2/connection'
6+
7+
/** @internal */
8+
export interface ClientConfigurationAPI {
9+
$acceptConfigurationUpdate(params: ConfigurationUpdateParams): Promise<void>
10+
}
11+
12+
/**
13+
* @internal
14+
* @template C - The configuration schema.
15+
*/
16+
export class ClientConfiguration<C> implements ClientConfigurationAPI {
17+
private subscriptions = new Subscription()
18+
private proxy: ExtConfigurationAPI<C>
19+
20+
constructor(
21+
connection: Connection,
22+
environmentConfiguration: Observable<C>,
23+
private updateConfiguration: (params: ConfigurationUpdateParams) => Promise<void>
24+
) {
25+
this.proxy = createProxyAndHandleRequests('configuration', connection, this)
26+
27+
this.subscriptions.add(
28+
environmentConfiguration.subscribe(config => {
29+
this.proxy.$acceptConfigurationData(config)
30+
})
31+
)
32+
}
33+
34+
public async $acceptConfigurationUpdate(params: ConfigurationUpdateParams): Promise<void> {
35+
await this.updateConfiguration(params)
36+
}
37+
38+
public unsubscribe(): void {
39+
this.subscriptions.unsubscribe()
40+
}
41+
}

src/client/api/context.ts

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Subscription } from 'rxjs'
2+
import { ContextValues } from 'sourcegraph'
3+
import { handleRequests } from '../../common/proxy'
4+
import { Connection } from '../../protocol/jsonrpc2/connection'
5+
6+
/** @internal */
7+
export interface ClientContextAPI {
8+
$acceptContextUpdates(updates: ContextValues): void
9+
}
10+
11+
/** @internal */
12+
export class ClientContext implements ClientContextAPI {
13+
private subscriptions = new Subscription()
14+
15+
/**
16+
* Context keys set by this server. To ensure that context values are cleaned up, all context properties that
17+
* the server set are cleared upon deinitialization. This errs on the side of clearing too much (if another
18+
* server set the same context keys after this server, then those keys would also be cleared when this server's
19+
* client deinitializes).
20+
*/
21+
private keys = new Set<string>()
22+
23+
constructor(connection: Connection, private updateContext: (updates: ContextValues) => void) {
24+
handleRequests(connection, 'context', this)
25+
}
26+
27+
public $acceptContextUpdates(updates: ContextValues): void {
28+
for (const key of Object.keys(updates)) {
29+
this.keys.add(key)
30+
}
31+
this.updateContext(updates)
32+
}
33+
34+
public unsubscribe(): void {
35+
/**
36+
* Clear all context properties whose keys were ever set by the server. See {@link ClientContext#keys}.
37+
*/
38+
const updates: ContextValues = {}
39+
for (const key of this.keys) {
40+
updates[key] = null
41+
}
42+
this.keys.clear()
43+
this.updateContext(updates)
44+
45+
this.subscriptions.unsubscribe()
46+
}
47+
}

src/client/api/documents.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Observable, Subscription } from 'rxjs'
2+
import { filter } from 'rxjs/operators'
3+
import { TextDocument } from 'sourcegraph'
4+
import { createProxyAndHandleRequests } from '../../common/proxy'
5+
import { ExtDocumentsAPI } from '../../extension/api/documents'
6+
import { Connection } from '../../protocol/jsonrpc2/connection'
7+
import { TextDocumentItem } from '../types/textDocument'
8+
import { SubscriptionMap } from './common'
9+
10+
/** @internal */
11+
export class ClientDocuments {
12+
private subscriptions = new Subscription()
13+
private registrations = new SubscriptionMap()
14+
private proxy: ExtDocumentsAPI
15+
16+
constructor(
17+
connection: Connection,
18+
environmentTextDocument: Observable<Pick<TextDocument, 'uri' | 'languageId'> | null>
19+
) {
20+
this.proxy = createProxyAndHandleRequests('documents', connection, this)
21+
22+
this.subscriptions.add(
23+
environmentTextDocument.pipe(filter((v): v is TextDocumentItem => v !== null)).subscribe(doc => {
24+
this.proxy.$acceptDocumentData(doc)
25+
})
26+
)
27+
28+
this.subscriptions.add(this.registrations)
29+
}
30+
31+
public unsubscribe(): void {
32+
this.subscriptions.unsubscribe()
33+
}
34+
}

0 commit comments

Comments
 (0)