2022-05-19 19:56:43 +00:00
|
|
|
|
/-
|
|
|
|
|
Copyright (c) 2022 Henrik Böving. All rights reserved.
|
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
Authors: Henrik Böving
|
|
|
|
|
-/
|
2022-05-19 18:48:26 +00:00
|
|
|
|
import Lean
|
2022-12-02 16:55:27 +00:00
|
|
|
|
import Lake.Load
|
2022-05-19 18:48:26 +00:00
|
|
|
|
|
2023-03-09 20:37:13 +00:00
|
|
|
|
namespace DocGen4.Output.SourceLinker
|
2022-05-19 18:48:26 +00:00
|
|
|
|
|
|
|
|
|
open Lean
|
|
|
|
|
|
2022-05-19 18:52:54 +00:00
|
|
|
|
/--
|
|
|
|
|
Turns a Github git remote URL into an HTTPS Github URL.
|
2022-05-19 18:48:26 +00:00
|
|
|
|
Three link types from git supported:
|
|
|
|
|
- https://github.com/org/repo
|
|
|
|
|
- https://github.com/org/repo.git
|
|
|
|
|
- git@github.com:org/repo.git
|
2022-05-19 18:52:54 +00:00
|
|
|
|
|
|
|
|
|
TODO: This function is quite brittle and very Github specific, we can
|
2022-05-19 18:48:26 +00:00
|
|
|
|
probably do better.
|
|
|
|
|
-/
|
|
|
|
|
def getGithubBaseUrl (gitUrl : String) : String := Id.run do
|
|
|
|
|
let mut url := gitUrl
|
|
|
|
|
if url.startsWith "git@" then
|
|
|
|
|
url := url.drop 15
|
|
|
|
|
url := url.dropRight 4
|
2023-01-01 18:51:01 +00:00
|
|
|
|
return s!"https://github.com/{url}"
|
2022-05-19 18:48:26 +00:00
|
|
|
|
else if url.endsWith ".git" then
|
2023-01-01 18:51:01 +00:00
|
|
|
|
return url.dropRight 4
|
2022-05-19 18:48:26 +00:00
|
|
|
|
else
|
2023-01-01 18:51:01 +00:00
|
|
|
|
return url
|
2022-05-19 18:48:26 +00:00
|
|
|
|
|
2022-05-19 18:52:54 +00:00
|
|
|
|
/--
|
|
|
|
|
Obtain the Github URL of a project by parsing the origin remote.
|
|
|
|
|
-/
|
2022-05-19 18:48:26 +00:00
|
|
|
|
def getProjectGithubUrl : IO String := do
|
|
|
|
|
let out ← IO.Process.output {cmd := "git", args := #["remote", "get-url", "origin"]}
|
|
|
|
|
if out.exitCode != 0 then
|
|
|
|
|
throw <| IO.userError <| "git exited with code " ++ toString out.exitCode
|
2023-01-01 18:51:01 +00:00
|
|
|
|
return out.stdout.trimRight
|
2022-05-19 18:48:26 +00:00
|
|
|
|
|
2022-05-19 18:52:54 +00:00
|
|
|
|
/--
|
|
|
|
|
Obtain the git commit hash of the project that is currently getting analyzed.
|
|
|
|
|
-/
|
2022-05-19 18:48:26 +00:00
|
|
|
|
def getProjectCommit : IO String := do
|
|
|
|
|
let out ← IO.Process.output {cmd := "git", args := #["rev-parse", "HEAD"]}
|
|
|
|
|
if out.exitCode != 0 then
|
|
|
|
|
throw <| IO.userError <| "git exited with code " ++ toString out.exitCode
|
2023-01-01 18:51:01 +00:00
|
|
|
|
return out.stdout.trimRight
|
2022-05-19 18:48:26 +00:00
|
|
|
|
|
2022-05-19 18:52:54 +00:00
|
|
|
|
/--
|
|
|
|
|
Given a lake workspace with all the dependencies as well as the hash of the
|
|
|
|
|
compiler release to work with this provides a function to turn names of
|
|
|
|
|
declarations into (optionally positional) Github URLs.
|
|
|
|
|
-/
|
2022-07-21 00:25:26 +00:00
|
|
|
|
def sourceLinker (ws : Lake.Workspace) : IO (Name → Option DeclarationRange → String) := do
|
2022-08-09 21:30:43 +00:00
|
|
|
|
let leanHash := ws.lakeEnv.lean.githash
|
2022-05-19 18:48:26 +00:00
|
|
|
|
-- Compute a map from package names to source URL
|
2022-10-05 10:05:58 +00:00
|
|
|
|
let mut gitMap := Lean.mkHashMap
|
2023-01-01 18:51:01 +00:00
|
|
|
|
let projectBaseUrl := getGithubBaseUrl (← getProjectGithubUrl)
|
2022-05-19 18:48:26 +00:00
|
|
|
|
let projectCommit ← getProjectCommit
|
|
|
|
|
gitMap := gitMap.insert ws.root.name (projectBaseUrl, projectCommit)
|
2022-08-09 21:30:43 +00:00
|
|
|
|
let manifest ← Lake.Manifest.loadOrEmpty ws.root.manifestFile
|
|
|
|
|
|>.run (Lake.MonadLog.eio .normal)
|
2023-01-01 18:51:01 +00:00
|
|
|
|
|>.toIO (fun _ => IO.userError "Failed to load lake manifest")
|
2022-12-03 16:43:12 +00:00
|
|
|
|
for pkg in manifest.entryArray do
|
2022-12-02 16:55:27 +00:00
|
|
|
|
if let .git _ url rev .. := pkg then
|
|
|
|
|
gitMap := gitMap.insert pkg.name (getGithubBaseUrl url, rev)
|
2022-05-19 18:48:26 +00:00
|
|
|
|
|
2023-01-01 18:51:01 +00:00
|
|
|
|
return fun module range =>
|
2022-05-19 18:48:26 +00:00
|
|
|
|
let parts := module.components.map Name.toString
|
|
|
|
|
let path := (parts.intersperse "/").foldl (· ++ ·) ""
|
|
|
|
|
let root := module.getRoot
|
2022-10-05 10:05:58 +00:00
|
|
|
|
let basic := if root == `Lean ∨ root == `Init then
|
2022-05-19 18:48:26 +00:00
|
|
|
|
s!"https://github.com/leanprover/lean4/blob/{leanHash}/src/{path}.lean"
|
|
|
|
|
else
|
2022-06-19 14:41:59 +00:00
|
|
|
|
match ws.packageArray.find? (·.isLocalModule module) with
|
2022-05-19 18:48:26 +00:00
|
|
|
|
| some pkg =>
|
2022-08-09 21:30:43 +00:00
|
|
|
|
match gitMap.find? pkg.name with
|
|
|
|
|
| some (baseUrl, commit) => s!"{baseUrl}/blob/{commit}/{path}.lean"
|
|
|
|
|
| none => "https://example.com"
|
2022-05-19 18:48:26 +00:00
|
|
|
|
| none => "https://example.com"
|
|
|
|
|
|
|
|
|
|
match range with
|
|
|
|
|
| some range => s!"{basic}#L{range.pos.line}-L{range.endPos.line}"
|
|
|
|
|
| none => basic
|
|
|
|
|
|
2023-03-09 20:37:13 +00:00
|
|
|
|
end DocGen4.Output.SourceLinker
|