Skip to content
This repository was archived by the owner on Mar 10, 2022. It is now read-only.

Commit 5fde9ad

Browse files
committed
fix: render repository results in search notebooks
1 parent 9d1243b commit 5fde9ad

4 files changed

Lines changed: 181 additions & 69 deletions

File tree

src/queries/graphqlQuery.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export function graphqlQueryWithAccessToken<A, B>(
3030
const headers: any = {
3131
'Content-Length': data.length,
3232
}
33-
log.appendLine(`token: ${accessToken || 'undefined'}`)
3433
if (accessToken) {
3534
headers.Authorization = `token ${accessToken}`
3635
}

src/queries/searchQuery.ts

Lines changed: 81 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,82 @@ export function searchQueryResult(
1010
): Promise<SearchResult | undefined> {
1111
return graphqlQuery<SearchParameters, SearchResult>(
1212
gql`
13-
query Search($query: String!) {
14-
search(query: $query, patternType: ${SearchPatternType[patternType]}) {
13+
query ($query: String!) {
14+
search(query: $query) {
1515
results {
1616
results {
17+
__typename
1718
... on FileMatch {
1819
...FileMatchFields
1920
}
21+
... on CommitSearchResult {
22+
...CommitSearchResultFields
23+
}
24+
... on Repository {
25+
...RepositoryFields
26+
}
2027
}
21-
limitHit
22-
matchCount
23-
elapsedMilliseconds
28+
...SearchResultsAlertFields
2429
}
2530
}
2631
}
27-
2832
fragment FileMatchFields on FileMatch {
29-
file {
33+
repository {
34+
name
3035
url
3136
}
32-
repository {
33-
stars
37+
file {
38+
name
39+
path
40+
url
41+
content
42+
commit {
43+
oid
44+
}
3445
}
3546
lineMatches {
47+
preview
3648
lineNumber
3749
offsetAndLengths
38-
preview
50+
limitHit
51+
}
52+
}
53+
54+
fragment CommitSearchResultFields on CommitSearchResult {
55+
commit {
56+
message
57+
author {
58+
person {
59+
name
60+
}
61+
}
62+
}
63+
matches {
64+
url
65+
body {
66+
text
67+
}
68+
highlights {
69+
character
70+
line
71+
length
72+
}
73+
}
74+
}
75+
76+
fragment RepositoryFields on Repository {
77+
name
78+
stars
79+
}
80+
81+
fragment SearchResultsAlertFields on SearchResults {
82+
alert {
83+
title
84+
description
85+
proposedQueries {
86+
description
87+
query
88+
}
3989
}
4090
}
4191
`,
@@ -89,18 +139,37 @@ export interface SearchResult {
89139
}
90140
}
91141
}
92-
interface SearchResultNode {
142+
143+
export interface SearchResultNode {
144+
__typename: string
145+
name?: string
146+
stars?: number
93147
file?: {
94148
url?: string
95149
}
96150
repository?: {
97151
stars?: number
98152
}
99153
lineMatches?: LineMatch[]
154+
matches?: CommitMatch[]
100155
}
101156

102-
interface LineMatch {
157+
export interface LineMatch {
103158
lineNumber?: number
104159
offsetAndLengths?: [number, number][]
105160
preview?: string
106161
}
162+
163+
export interface CommitMatch {
164+
url?: string
165+
body?: {
166+
text?: string
167+
}
168+
highlights?: CommitHighlight[]
169+
}
170+
171+
export interface CommitHighlight {
172+
character?: number
173+
line?: number
174+
length?: number
175+
}

src/search/SourcegraphNotebookSerializer.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ export class SourcegraphNotebookSerializer implements vscode.NotebookSerializer
2828
const uriString: unknown = event.message?.uri
2929
if (event.message?.request === 'openEditor' && typeof uriString === 'string') {
3030
let uri = SourcegraphUri.parse(uriString)
31+
if (!uri.path) {
32+
uri = await fs.defaultFileUri(uri.repositoryName)
33+
}
3134
if (!uri.revision) {
3235
uri = uri.withRevision((await fs.repositoryMetadata(uri.repositoryName))?.defaultBranch)
3336
}

src/search/searchHtml.ts

Lines changed: 97 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as vscode from 'vscode'
22
import { SearchPatternType } from './scanner'
3-
import { searchQueryResult } from '../queries/searchQuery'
3+
import { searchQueryResult, SearchResultNode } from '../queries/searchQuery'
44

55
export async function searchHtml(
66
host: string,
@@ -12,70 +12,111 @@ export async function searchHtml(
1212
const html: string[] = []
1313
const nodes = result?.data?.search?.results?.results
1414
for (const node of nodes || []) {
15-
const url = node?.file?.url
16-
if (!url) {
15+
formatFileMatch(host, node, html)
16+
formatRepository(host, node, html)
17+
formatCommit(host, node, html)
18+
}
19+
return html.join('')
20+
}
21+
22+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
23+
function formatCommit(host: string, node: SearchResultNode, html: string[]): void {
24+
if (node.__typename !== 'CommitSearchResult') {
25+
return
26+
}
27+
// Not supported
28+
}
29+
30+
function formatRepository(host: string, node: SearchResultNode, html: string[]): void {
31+
if (node.__typename !== 'Repository') {
32+
return
33+
}
34+
if (!node.name) {
35+
return
36+
}
37+
const url = `sourcegraph://${host}/${node.name}`
38+
const stars = formatStars(node.stars)
39+
html.push('<p>')
40+
html.push(
41+
`<code><a style='cursor:pointer' class='sourcegraph-location' id="${url}">${node.name}</a>${stars}</code>`
42+
)
43+
html.push('</p>')
44+
}
45+
46+
function formatFileMatch(host: string, node: SearchResultNode, html: string[]): void {
47+
if (node.__typename !== 'FileMatch') {
48+
return
49+
}
50+
const url = node?.file?.url
51+
if (!url) {
52+
return
53+
}
54+
const lineMatches = node.lineMatches || []
55+
if (lineMatches.length === 0) {
56+
return
57+
}
58+
let first = true
59+
let filenameMatchesCount = 0
60+
for (const [lineMatchIndex, lineMatch] of lineMatches.entries()) {
61+
const line = lineMatch.lineNumber
62+
if (!line) {
1763
continue
1864
}
19-
const starCount = node?.repository?.stars
20-
const stars = starCount ? ` ⭐ ${formatStarCount(starCount)}` : ''
21-
const lineMatches = node.lineMatches || []
22-
if (lineMatches.length === 0) {
65+
const preview = lineMatch.preview
66+
if (!preview) {
2367
continue
2468
}
25-
let first = true
26-
let filenameMatchesCount = 0
27-
for (const [lineMatchIndex, lineMatch] of lineMatches.entries()) {
28-
const line = lineMatch.lineNumber
29-
if (!line) {
30-
continue
31-
}
32-
const preview = lineMatch.preview
33-
if (!preview) {
34-
continue
35-
}
36-
let index = 0
37-
const highlightedPreview: string[] = []
38-
if (lineMatchIndex > 0) {
39-
highlightedPreview.push('\n')
40-
}
41-
highlightedPreview.push(`L${line}: `)
42-
let character = 0
43-
for (const offsetsAndLength of lineMatch.offsetAndLengths || []) {
44-
const [start, length] = offsetsAndLength
45-
if (!character) {
46-
// Position the cursor at the first match on the line.
47-
character = start
48-
}
49-
const end = start + length
50-
highlightedPreview.push(escapeHtml(preview.slice(index, start)))
51-
highlightedPreview.push('<mark>')
52-
highlightedPreview.push(escapeHtml(preview.slice(start, end)))
53-
highlightedPreview.push('</mark>')
54-
index = end
55-
}
56-
highlightedPreview.push(escapeHtml(preview.slice(index, preview.length)))
57-
if (first) {
58-
first = false
59-
html.push('<p>')
60-
html.push(`<code>${url}${stars}</code>`)
61-
html.push('<pre>')
62-
}
63-
const uri = `sourcegraph://${host}${url}?L${line + 1}:${character}`
64-
html.push(
65-
`<a id='${uri}' style='cursor:pointer' class='sourcegraph-location'>${highlightedPreview.join('')}</a>`
66-
)
67-
filenameMatchesCount++
68-
if (filenameMatchesCount > 5) {
69-
break
69+
let index = 0
70+
const highlightedPreview: string[] = []
71+
if (lineMatchIndex > 0) {
72+
highlightedPreview.push('\n')
73+
}
74+
highlightedPreview.push(`L${line}: `)
75+
let character = 0
76+
for (const offsetsAndLength of lineMatch.offsetAndLengths || []) {
77+
const [start, length] = offsetsAndLength
78+
if (!character) {
79+
// Position the cursor at the first match on the line.
80+
character = start
7081
}
82+
const end = start + length
83+
highlightedPreview.push(escapeHtml(preview.slice(index, start)))
84+
highlightedPreview.push('<mark>')
85+
highlightedPreview.push(escapeHtml(preview.slice(start, end)))
86+
highlightedPreview.push('</mark>')
87+
index = end
88+
}
89+
highlightedPreview.push(escapeHtml(preview.slice(index, preview.length)))
90+
if (first) {
91+
first = false
92+
html.push('<p>')
93+
html.push(`<code>${url}${formatStars(node?.repository?.stars)}</code>`)
94+
html.push('<pre>')
95+
}
96+
const uri = `sourcegraph://${host}${url}?L${line + 1}:${character}`
97+
html.push(
98+
`<a id='${uri}' style='cursor:pointer' class='sourcegraph-location'>${highlightedPreview.join('')}</a>`
99+
)
100+
filenameMatchesCount++
101+
if (filenameMatchesCount > 5) {
102+
break
71103
}
72-
html.push('</pre>')
73-
html.push('</p>')
74104
}
75-
return html.join('')
105+
html.push('</pre>')
106+
html.push('</p>')
76107
}
77108

78-
function formatStarCount(starCount: number): string {
109+
function formatStars(starCount: number | undefined): string {
110+
const count = formatStarCount(starCount)
111+
if (count) {
112+
return ` ⭐${count}`
113+
}
114+
return count
115+
}
116+
function formatStarCount(starCount: number | undefined): string {
117+
if (!starCount) {
118+
return ''
119+
}
79120
if (starCount > 1000) {
80121
return `${Math.round(starCount / 1000)}k`
81122
}

0 commit comments

Comments
 (0)