Skip to content
This repository has been archived by the owner on Feb 22, 2020. It is now read-only.

Activation refactor #117

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@
"sourcegraph": "^23.0.1",
"tsc-watch": "^2.2.1",
"tslint": "^5.20.1",
"typescript": "^3.1.6"
"typescript": "^3.7.2"
},
"dependencies": {
"@sourcegraph/basic-code-intel": "10.0.0",
Expand Down
205 changes: 51 additions & 154 deletions src/lang-go.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@babel/polyfill'

import { Handler, initLSIF, asyncFirst, wrapMaybe, Maybe, impreciseBadge } from '@sourcegraph/basic-code-intel'
import { activateCodeIntel, LSPProviders, HandlerArgs } from '@sourcegraph/basic-code-intel'
import { convertHover } from '@sourcegraph/lsp-client/dist/lsp-conversion'
import * as wsrpc from '@sourcegraph/vscode-ws-jsonrpc'
import { ajax } from 'rxjs/ajax'
Expand Down Expand Up @@ -666,34 +666,10 @@ function registerImplementations({
ctx.subscriptions.add(panelView)
}

interface MaybeProviders {
hover: (doc: sourcegraph.TextDocument, pos: sourcegraph.Position) => Promise<Maybe<sourcegraph.Hover | null>>
definition: (
doc: sourcegraph.TextDocument,
pos: sourcegraph.Position
) => Promise<Maybe<sourcegraph.Definition | null>>
references: (
doc: sourcegraph.TextDocument,
pos: sourcegraph.Position
) => Promise<Maybe<sourcegraph.Location[] | null>>
}

interface Providers {
hover: (doc: sourcegraph.TextDocument, pos: sourcegraph.Position) => Promise<sourcegraph.Hover | null>
definition: (doc: sourcegraph.TextDocument, pos: sourcegraph.Position) => Promise<sourcegraph.Definition | null>
references: (doc: sourcegraph.TextDocument, pos: sourcegraph.Position) => Promise<sourcegraph.Location[] | null>
}

const noopMaybeProviders = {
hover: () => Promise.resolve(undefined),
definition: () => Promise.resolve(undefined),
references: () => Promise.resolve(undefined),
}

/**
* Uses WebSockets to communicate with a language server.
*/
export async function initLSP(ctx: sourcegraph.ExtensionContext): Promise<MaybeProviders> {
export async function initLSP(ctx: sourcegraph.ExtensionContext): Promise<LSPProviders | undefined> {
const settings: BehaviorSubject<Settings> = new BehaviorSubject<Settings>({})
ctx.subscriptions.add(
sourcegraph.configuration.subscribe(() => {
Expand All @@ -703,16 +679,19 @@ export async function initLSP(ctx: sourcegraph.ExtensionContext): Promise<MaybeP
const accessToken = await getOrTryToCreateAccessToken()
const langserverAddress = sourcegraph.configuration.get<Settings>().get('go.serverUrl')
if (!langserverAddress) {
return noopMaybeProviders
return undefined
}

const unsubscribableSendRequest = mkSendRequest<any>(langserverAddress, accessToken)
const sendRequest = <T>(...args: Parameters<typeof unsubscribableSendRequest.sendRequest>): Promise<T> =>
unsubscribableSendRequest.sendRequest(...args)
ctx.subscriptions.add(unsubscribableSendRequest)

const hover = async (doc: sourcegraph.TextDocument, pos: sourcegraph.Position) =>
convertHover(
async function* hover(
doc: sourcegraph.TextDocument,
pos: sourcegraph.Position
): AsyncGenerator<sourcegraph.Hover | null, void, undefined> {
yield convertHover(
sourcegraph,
await sendRequest<lspTypes.Hover | null>({
rootURI: rootURIFromDoc(doc),
Expand All @@ -721,9 +700,13 @@ export async function initLSP(ctx: sourcegraph.ExtensionContext): Promise<MaybeP
useCache: true,
})
)
}

const definition = async (doc: sourcegraph.TextDocument, pos: sourcegraph.Position) =>
convert.xdefinition({
async function* definition(
doc: sourcegraph.TextDocument,
pos: sourcegraph.Position
): AsyncGenerator<sourcegraph.Definition, void, undefined> {
yield convert.xdefinition({
currentDocURI: doc.uri,
xdefinition: await sendRequest<lspext.Xdefinition[] | null>({
rootURI: rootURIFromDoc(doc),
Expand All @@ -732,9 +715,13 @@ export async function initLSP(ctx: sourcegraph.ExtensionContext): Promise<MaybeP
useCache: true,
}),
})
}

const references = async (doc: sourcegraph.TextDocument, pos: sourcegraph.Position) =>
convert.references({
async function* references(
doc: sourcegraph.TextDocument,
pos: sourcegraph.Position
): AsyncGenerator<sourcegraph.Location[] | null, void, undefined> {
yield convert.references({
currentDocURI: doc.uri,
references: await sendRequest<lspTypes.Location[]>({
rootURI: rootURIFromDoc(doc),
Expand All @@ -743,14 +730,15 @@ export async function initLSP(ctx: sourcegraph.ExtensionContext): Promise<MaybeP
useCache: true,
}),
})
}

registerExternalReferences({ ctx, sendRequest, settings })
registerImplementations({ ctx, sendRequest })

return {
hover: wrapMaybe(hover),
definition: wrapMaybe(definition),
references: wrapMaybe(references),
hover,
definition,
references,
}
}

Expand All @@ -765,42 +753,35 @@ function repoName(url: string): string {
return pathname
}

function initBasicCodeIntel(): Providers {
const handler = new Handler({
sourcegraph,
languageID: 'go',
fileExts: ['go'],
filterDefinitions: ({ repo, filePath, pos, fileContent, results }) => {
const currentFileImportedPaths = fileContent
.split('\n')
.map(line => {
// Matches the import at index 3
const match = /^(import |\t)(\w+ |\. )?"(.*)"$/.exec(line)
return match ? match[3] : undefined
})
.filter((x): x is string => Boolean(x))
const handlerArgs: HandlerArgs = {
sourcegraph,
languageID: 'go',
fileExts: ['go'],
filterDefinitions: ({ repo, filePath, pos, fileContent, results }) => {
const currentFileImportedPaths = fileContent
.split('\n')
.map(line => {
// Matches the import at index 3
const match = /^(import |\t)(\w+ |\. )?"(.*)"$/.exec(line)
return match ? match[3] : undefined
})
.filter((x): x is string => Boolean(x))

const currentFileImportPath = repo + '/' + path.dirname(filePath)
const currentFileImportPath = repo + '/' + path.dirname(filePath)

const filteredResults = results.filter(result => {
const resultImportPath = result.repo + '/' + path.dirname(result.file)
return (
currentFileImportedPaths.some(i => resultImportPath.includes(i)) ||
resultImportPath === currentFileImportPath
)
})
const filteredResults = results.filter(result => {
const resultImportPath = result.repo + '/' + path.dirname(result.file)
return (
currentFileImportedPaths.some(i => resultImportPath.includes(i)) ||
resultImportPath === currentFileImportPath
)
})

return filteredResults.length === 0 ? results : filteredResults
},
commentStyle: {
lineRegex: /\/\/\s?/,
},
})
return {
hover: handler.hover.bind(handler),
definition: handler.definition.bind(handler),
references: handler.references.bind(handler),
}
return filteredResults.length === 0 ? results : filteredResults
},
commentStyle: {
lineRegex: /\/\/\s?/,
},
}

// No-op for Sourcegraph versions prior to 3.0.
Expand All @@ -810,91 +791,7 @@ const goFiles = [{ pattern: '*.go' }]

export function activate(ctx: sourcegraph.ExtensionContext = DUMMY_CTX): void {
async function afterActivate(): Promise<void> {
const lsif = initLSIF()
// When access token creation fails, this becomes a noop
const lsp = await initLSP(ctx).catch<MaybeProviders>(() => noopMaybeProviders)
const basicCodeIntel = initBasicCodeIntel()

ctx.subscriptions.add(
sourcegraph.languages.registerHoverProvider(goFiles, {
provideHover: async (doc, pos) => {
const lsifResult = await lsif.hover(doc, pos)
if (lsifResult) {
return lsifResult.value
}

const lspResult = await lsp.hover(doc, pos)
if (lspResult) {
return lspResult.value
}

const val = await basicCodeIntel.hover(doc, pos)
if (!val) {
return undefined
}

return { ...val, badge: impreciseBadge }
},
})
)
ctx.subscriptions.add(
sourcegraph.languages.registerDefinitionProvider(goFiles, {
provideDefinition: async (doc, pos) => {
const lsifResult = await lsif.definition(doc, pos)
if (lsifResult) {
return lsifResult.value
}

const lspResult = await lsp.definition(doc, pos)
if (lspResult) {
return lspResult.value
}

const val = await basicCodeIntel.definition(doc, pos)
if (!val) {
return undefined
}

if (Array.isArray(val)) {
return val.map(v => ({ ...v, badge: impreciseBadge }))
}

return { ...val, badge: impreciseBadge }
},
})
)
ctx.subscriptions.add(
sourcegraph.languages.registerReferenceProvider(goFiles, {
provideReferences: async (doc, pos) => {
if (isLSPEnabled()) {
const references = await lsp.references(doc, pos)
return references ? references.value : null
}

// Gets an opaque value that is the same for all locations
// within a file but different from other files.
const file = (loc: sourcegraph.Location) => `${loc.uri.host} ${loc.uri.pathname} ${loc.uri.hash}`

// Concatenates LSIF results (if present) with fuzzy results
// because LSIF data might be sparse.
const lsifReferences = await lsif.references(doc, pos)
const fuzzyReferences = (await basicCodeIntel.references(doc, pos)) || []

const lsifFiles = new Set((lsifReferences ? lsifReferences.value : []).map(file))

return [
...(lsifReferences === undefined ? [] : lsifReferences.value),
// Drop fuzzy references from files that have LSIF results.
...fuzzyReferences
.filter(fuzzyRef => !lsifFiles.has(file(fuzzyRef)))
.map(v => ({
...v,
badge: impreciseBadge,
})),
]
},
})
)
activateCodeIntel(ctx, goFiles, handlerArgs, await initLSP(ctx))
}
setTimeout(afterActivate, 100)
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"extends": "./node_modules/@sourcegraph/tsconfig/tsconfig.json",
"compilerOptions": {
"target": "es2016",
"target": "es2019",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need async generators now.

"module": "esnext",
"moduleResolution": "node",
"sourceMap": true,
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5590,10 +5590,10 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=

typescript@^3.1.6:
version "3.3.3333"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3333.tgz#171b2c5af66c59e9431199117a3bcadc66fdcfd6"
integrity sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==
typescript@^3.7.2:
version "3.7.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==

unicode-canonical-property-names-ecmascript@^1.0.4:
version "1.0.4"
Expand Down