// Copyright 2025 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package repo import ( "net/http" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/services/context" sourcegraph_service "code.gitea.io/gitea/services/sourcegraph" ) // sourcegraphRepoName returns the full repository name for Sourcegraph, // which includes the server domain prefix (e.g., "git.example.com/owner/repo") func sourcegraphRepoName(ctx *context.APIContext) string { return setting.Domain + "/" + ctx.Repo.Repository.FullName() } // SourcegraphHover returns hover information at a position func SourcegraphHover(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/sourcegraph/hover repository repoSourcegraphHover // --- // summary: Get code intelligence hover info // produces: // - application/json // parameters: // - name: owner // in: path // description: owner of the repo // type: string // required: true // - name: repo // in: path // description: name of the repo // type: string // required: true // - name: path // in: query // description: file path // type: string // required: true // - name: line // in: query // description: line number (0-indexed) // type: integer // required: true // - name: character // in: query // description: character position (0-indexed) // type: integer // required: true // - name: ref // in: query // description: git ref (commit SHA, branch, tag) // type: string // required: true // responses: // "200": // description: hover information // "400": // "$ref": "#/responses/error" // "404": // "$ref": "#/responses/notFound" // "503": // description: Sourcegraph integration not available if !setting.Sourcegraph.Enabled { ctx.APIError(http.StatusServiceUnavailable, "Sourcegraph integration is not enabled") return } path := ctx.FormString("path") line := ctx.FormInt("line") char := ctx.FormInt("character") ref := ctx.FormString("ref") if path == "" || ref == "" { ctx.APIError(http.StatusBadRequest, "path and ref are required") return } client := sourcegraph_service.GetClient() if client == nil { ctx.APIError(http.StatusServiceUnavailable, "Sourcegraph client not initialized") return } result, err := client.Hover(ctx, sourcegraphRepoName(ctx), ref, path, line, char) if err != nil { ctx.APIError(http.StatusBadGateway, err) return } if result == nil { ctx.JSON(http.StatusOK, map[string]any{}) return } // Render markdown content to HTML if result.Contents != "" { rendered, err := markdown.RenderString(markup.NewRenderContext(ctx).WithMetas(markup.ComposeSimpleDocumentMetas()), result.Contents) if err == nil { result.Contents = string(rendered) } } ctx.JSON(http.StatusOK, result) } // SourcegraphDefinition returns definition locations for a symbol func SourcegraphDefinition(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/sourcegraph/definition repository repoSourcegraphDefinition // --- // summary: Get code intelligence definition locations // produces: // - application/json // parameters: // - name: owner // in: path // description: owner of the repo // type: string // required: true // - name: repo // in: path // description: name of the repo // type: string // required: true // - name: path // in: query // description: file path // type: string // required: true // - name: line // in: query // description: line number (0-indexed) // type: integer // required: true // - name: character // in: query // description: character position (0-indexed) // type: integer // required: true // - name: ref // in: query // description: git ref (commit SHA, branch, tag) // type: string // required: true // responses: // "200": // description: definition locations // "400": // "$ref": "#/responses/error" // "404": // "$ref": "#/responses/notFound" // "503": // description: Sourcegraph integration not available if !setting.Sourcegraph.Enabled { ctx.APIError(http.StatusServiceUnavailable, "Sourcegraph integration is not enabled") return } path := ctx.FormString("path") line := ctx.FormInt("line") char := ctx.FormInt("character") ref := ctx.FormString("ref") if path == "" || ref == "" { ctx.APIError(http.StatusBadRequest, "path and ref are required") return } client := sourcegraph_service.GetClient() if client == nil { ctx.APIError(http.StatusServiceUnavailable, "Sourcegraph client not initialized") return } result, err := client.Definition(ctx, sourcegraphRepoName(ctx), ref, path, line, char) if err != nil { ctx.APIError(http.StatusBadGateway, err) return } if result == nil { result = []sourcegraph_service.Location{} } ctx.JSON(http.StatusOK, result) } // SourcegraphReferences returns reference locations for a symbol func SourcegraphReferences(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/sourcegraph/references repository repoSourcegraphReferences // --- // summary: Get code intelligence reference locations // produces: // - application/json // parameters: // - name: owner // in: path // description: owner of the repo // type: string // required: true // - name: repo // in: path // description: name of the repo // type: string // required: true // - name: path // in: query // description: file path // type: string // required: true // - name: line // in: query // description: line number (0-indexed) // type: integer // required: true // - name: character // in: query // description: character position (0-indexed) // type: integer // required: true // - name: ref // in: query // description: git ref (commit SHA, branch, tag) // type: string // required: true // responses: // "200": // description: reference locations // "400": // "$ref": "#/responses/error" // "404": // "$ref": "#/responses/notFound" // "503": // description: Sourcegraph integration not available if !setting.Sourcegraph.Enabled { ctx.APIError(http.StatusServiceUnavailable, "Sourcegraph integration is not enabled") return } path := ctx.FormString("path") line := ctx.FormInt("line") char := ctx.FormInt("character") ref := ctx.FormString("ref") if path == "" || ref == "" { ctx.APIError(http.StatusBadRequest, "path and ref are required") return } client := sourcegraph_service.GetClient() if client == nil { ctx.APIError(http.StatusServiceUnavailable, "Sourcegraph client not initialized") return } result, err := client.References(ctx, sourcegraphRepoName(ctx), ref, path, line, char) if err != nil { ctx.APIError(http.StatusBadGateway, err) return } if result == nil { result = []sourcegraph_service.Location{} } ctx.JSON(http.StatusOK, result) }