WIP add sourcegraph
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package sourcegraph
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// GraphQL queries for Sourcegraph API
|
||||
|
||||
const hoverQuery = `
|
||||
query Hover($repo: String!, $rev: String!, $path: String!, $line: Int!, $char: Int!) {
|
||||
repository(name: $repo) {
|
||||
commit(rev: $rev) {
|
||||
blob(path: $path) {
|
||||
lsif {
|
||||
hover(line: $line, character: $char) {
|
||||
markdown {
|
||||
text
|
||||
}
|
||||
range {
|
||||
start { line character }
|
||||
end { line character }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const definitionQuery = `
|
||||
query Definition($repo: String!, $rev: String!, $path: String!, $line: Int!, $char: Int!) {
|
||||
repository(name: $repo) {
|
||||
commit(rev: $rev) {
|
||||
blob(path: $path) {
|
||||
lsif {
|
||||
definitions(line: $line, character: $char) {
|
||||
nodes {
|
||||
resource {
|
||||
path
|
||||
repository {
|
||||
name
|
||||
}
|
||||
commit {
|
||||
oid
|
||||
}
|
||||
}
|
||||
range {
|
||||
start { line character }
|
||||
end { line character }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const referencesQuery = `
|
||||
query References($repo: String!, $rev: String!, $path: String!, $line: Int!, $char: Int!) {
|
||||
repository(name: $repo) {
|
||||
commit(rev: $rev) {
|
||||
blob(path: $path) {
|
||||
lsif {
|
||||
references(line: $line, character: $char, first: 100) {
|
||||
nodes {
|
||||
resource {
|
||||
path
|
||||
repository {
|
||||
name
|
||||
}
|
||||
commit {
|
||||
oid
|
||||
}
|
||||
}
|
||||
range {
|
||||
start { line character }
|
||||
end { line character }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const syncRepoMutation = `
|
||||
mutation SyncRepo($repo: String!) {
|
||||
scheduleRepositoryPermissionsSync(repository: $repo) {
|
||||
alwaysNil
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
// Response parsing structures
|
||||
|
||||
type hoverResponse struct {
|
||||
Repository *struct {
|
||||
Commit *struct {
|
||||
Blob *struct {
|
||||
LSIF *struct {
|
||||
Hover *struct {
|
||||
Markdown *struct {
|
||||
Text string `json:"text"`
|
||||
} `json:"markdown"`
|
||||
Range *struct {
|
||||
Start struct {
|
||||
Line int `json:"line"`
|
||||
Character int `json:"character"`
|
||||
} `json:"start"`
|
||||
End struct {
|
||||
Line int `json:"line"`
|
||||
Character int `json:"character"`
|
||||
} `json:"end"`
|
||||
} `json:"range"`
|
||||
} `json:"hover"`
|
||||
} `json:"lsif"`
|
||||
} `json:"blob"`
|
||||
} `json:"commit"`
|
||||
} `json:"repository"`
|
||||
}
|
||||
|
||||
type locationsResponse struct {
|
||||
Repository *struct {
|
||||
Commit *struct {
|
||||
Blob *struct {
|
||||
LSIF *struct {
|
||||
Definitions *locationNodes `json:"definitions,omitempty"`
|
||||
References *locationNodes `json:"references,omitempty"`
|
||||
} `json:"lsif"`
|
||||
} `json:"blob"`
|
||||
} `json:"commit"`
|
||||
} `json:"repository"`
|
||||
}
|
||||
|
||||
type locationNodes struct {
|
||||
Nodes []struct {
|
||||
Resource struct {
|
||||
Path string `json:"path"`
|
||||
Repository struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"repository"`
|
||||
Commit struct {
|
||||
OID string `json:"oid"`
|
||||
} `json:"commit"`
|
||||
} `json:"resource"`
|
||||
Range struct {
|
||||
Start struct {
|
||||
Line int `json:"line"`
|
||||
Character int `json:"character"`
|
||||
} `json:"start"`
|
||||
End struct {
|
||||
Line int `json:"line"`
|
||||
Character int `json:"character"`
|
||||
} `json:"end"`
|
||||
} `json:"range"`
|
||||
} `json:"nodes"`
|
||||
}
|
||||
|
||||
func parseHoverResponse(data json.RawMessage) (*HoverResult, error) {
|
||||
var resp hoverResponse
|
||||
if err := json.Unmarshal(data, &resp); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse hover response: %w", err)
|
||||
}
|
||||
|
||||
if resp.Repository == nil || resp.Repository.Commit == nil ||
|
||||
resp.Repository.Commit.Blob == nil || resp.Repository.Commit.Blob.LSIF == nil ||
|
||||
resp.Repository.Commit.Blob.LSIF.Hover == nil {
|
||||
return nil, nil // No hover info available
|
||||
}
|
||||
|
||||
hover := resp.Repository.Commit.Blob.LSIF.Hover
|
||||
result := &HoverResult{}
|
||||
|
||||
if hover.Markdown != nil {
|
||||
result.Contents = hover.Markdown.Text
|
||||
}
|
||||
|
||||
if hover.Range != nil {
|
||||
result.Range = &Range{
|
||||
Start: Position{
|
||||
Line: hover.Range.Start.Line,
|
||||
Character: hover.Range.Start.Character,
|
||||
},
|
||||
End: Position{
|
||||
Line: hover.Range.End.Line,
|
||||
Character: hover.Range.End.Character,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func parseLocationsResponse(data json.RawMessage, field string) ([]Location, error) {
|
||||
var resp locationsResponse
|
||||
if err := json.Unmarshal(data, &resp); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse locations response: %w", err)
|
||||
}
|
||||
|
||||
if resp.Repository == nil || resp.Repository.Commit == nil ||
|
||||
resp.Repository.Commit.Blob == nil || resp.Repository.Commit.Blob.LSIF == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var nodes *locationNodes
|
||||
switch field {
|
||||
case "definitions":
|
||||
nodes = resp.Repository.Commit.Blob.LSIF.Definitions
|
||||
case "references":
|
||||
nodes = resp.Repository.Commit.Blob.LSIF.References
|
||||
}
|
||||
|
||||
if nodes == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
locations := make([]Location, 0, len(nodes.Nodes))
|
||||
for _, node := range nodes.Nodes {
|
||||
locations = append(locations, Location{
|
||||
Repo: node.Resource.Repository.Name,
|
||||
Path: node.Resource.Path,
|
||||
Line: node.Range.Start.Line,
|
||||
Character: node.Range.Start.Character,
|
||||
})
|
||||
}
|
||||
|
||||
return locations, nil
|
||||
}
|
||||
Reference in New Issue
Block a user