forked from tangled.org/core
this repo has no description

appview: implement a basic breadcrumb for files

This needs another pass to fix the intermediate directory links etc.

Changed files
+48 -12
appview
pages
templates
repo
knotserver
types
+1
.gitignore
···
.direnv/
tmp
*.db
.bin/
appview/pages/static/*
result
···
.direnv/
tmp
*.db
+
*.db-*
.bin/
appview/pages/static/*
result
appview.db-journal

This is a binary file and will not be displayed.

+10
appview/pages/pages.go
···
"io/fs"
"log"
"net/http"
"path"
"strings"
"github.com/dustin/go-humanize"
···
LoggedInUser *auth.User
RepoInfo RepoInfo
Active string
types.RepoBlobResponse
}
func (p *Pages) RepoBlob(w io.Writer, params RepoBlobParams) error {
params.Active = "overview"
return p.executeRepo("repo/blob", w, params)
}
···
"io/fs"
"log"
"net/http"
+
"os"
"path"
+
"path/filepath"
"strings"
"github.com/dustin/go-humanize"
···
LoggedInUser *auth.User
RepoInfo RepoInfo
Active string
+
File string
+
PathElems []string
types.RepoBlobResponse
}
func (p *Pages) RepoBlob(w io.Writer, params RepoBlobParams) error {
+
path := filepath.Dir(params.Path)
+
file := filepath.Base(params.Path)
+
+
params.PathElems = strings.Split(path, string(os.PathSeparator))
+
params.Path = path
+
params.File = file
params.Active = "overview"
return p.executeRepo("repo/blob", w, params)
}
+9 -1
appview/pages/templates/repo/blob.html
···
{{ $tot_lines := len $lines }}
{{ $tot_chars := len (printf "%d" $tot_lines) }}
{{ $code_number_style := "text-gray-400 left-0 bg-white text-right mr-2 select-none" }}
<pre class="font-mono text-sm overflow-auto relative text-ellipsis"><code>{{ range $idx, $line := $lines }}<span class="flex">
<span class="{{ $code_number_style }}" style="min-width: {{$tot_chars}}ch;">{{ add $idx 1 }}</span>
-
<span class="whitespace-pre">{{ $line }}</span></span>{{ else }}<em class="text-gray-400">this file is empty</em>{{ end }}</code></pre>
{{ end }}
···
{{ $tot_lines := len $lines }}
{{ $tot_chars := len (printf "%d" $tot_lines) }}
{{ $code_number_style := "text-gray-400 left-0 bg-white text-right mr-2 select-none" }}
+
<div class="pb-2 text-lg">
+
{{ range .PathElems }}
+
<a href="/{{ $.RepoInfo.FullName }}/tree/{{ $.Ref }}/{{ . }}" class="text-bold text-gray-500">{{ . }}</a> /
+
{{ end }}<span class="">{{ .File }}</span>
+
</div>
+
+
+
{{ if .IsBinary }}<p class="text-center text-gray-400">This is a binary file and will not be displayed.</p>{{ else }}
<pre class="font-mono text-sm overflow-auto relative text-ellipsis"><code>{{ range $idx, $line := $lines }}<span class="flex">
<span class="{{ $code_number_style }}" style="min-width: {{$tot_chars}}ch;">{{ add $idx 1 }}</span>
+
<span class="whitespace-pre">{{ $line }}</span></span>{{ else }}<em class="text-gray-400">this file is empty</em>{{ end }}</code></pre>{{ end}}
{{ end }}
+5 -1
knotserver/git/git.go
···
"github.com/go-git/go-git/v5/plumbing/object"
)
type GitRepo struct {
r *git.Repository
h plumbing.Hash
···
if !isbin {
return file.Contents()
} else {
-
return "Not displaying binary file", nil
}
}
···
"github.com/go-git/go-git/v5/plumbing/object"
)
+
var (
+
ErrBinaryFile = fmt.Errorf("binary file")
+
)
+
type GitRepo struct {
r *git.Repository
h plumbing.Hash
···
if !isbin {
return file.Contents()
} else {
+
return "", ErrBinaryFile
}
}
+1
knotserver/handler.go
···
r.Post("/git-upload-pack", h.UploadPack)
r.Route("/tree/{ref}", func(r chi.Router) {
r.Get("/*", h.RepoTree)
})
···
r.Post("/git-upload-pack", h.UploadPack)
r.Route("/tree/{ref}", func(r chi.Router) {
+
r.Get("/", h.RepoIndex)
r.Get("/*", h.RepoTree)
})
+21 -10
knotserver/routes.go
···
func (h *Handle) RepoIndex(w http.ResponseWriter, r *http.Request) {
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
l := h.l.With("path", path, "handler", "RepoIndex")
-
gr, err := git.Open(path, "")
if err != nil {
if errors.Is(err, plumbing.ErrReferenceNotFound) {
resp := types.RepoIndexResponse{
···
l.Warn("no readme found")
}
-
mainBranch, err := gr.FindMainBranch(h.c.Repo.MainBranch)
if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
-
l.Error("finding main branch", "error", err.Error())
return
}
-
files, err := gr.FileTree("")
-
if err != nil {
-
writeError(w, err.Error(), http.StatusInternalServerError)
-
l.Error("file tree", "error", err.Error())
-
return
}
resp := types.RepoIndexResponse{
IsEmpty: false,
-
Ref: mainBranch,
Commits: commits,
Description: getDescription(path),
Readme: readmeContent,
···
return
}
contents, err := gr.FileContent(treePath)
-
if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
···
Ref: ref,
Contents: string(safe),
Path: treePath,
}
h.showFile(resp, w, l)
···
func (h *Handle) RepoIndex(w http.ResponseWriter, r *http.Request) {
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
l := h.l.With("path", path, "handler", "RepoIndex")
+
ref := chi.URLParam(r, "ref")
+
gr, err := git.Open(path, ref)
if err != nil {
if errors.Is(err, plumbing.ErrReferenceNotFound) {
resp := types.RepoIndexResponse{
···
l.Warn("no readme found")
}
+
files, err := gr.FileTree("")
if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
+
l.Error("file tree", "error", err.Error())
return
}
+
if ref == "" {
+
mainBranch, err := gr.FindMainBranch(h.c.Repo.MainBranch)
+
if err != nil {
+
writeError(w, err.Error(), http.StatusInternalServerError)
+
l.Error("finding main branch", "error", err.Error())
+
return
+
}
+
ref = mainBranch
}
resp := types.RepoIndexResponse{
IsEmpty: false,
+
Ref: ref,
Commits: commits,
Description: getDescription(path),
Readme: readmeContent,
···
return
}
+
var isBinaryFile bool = false
contents, err := gr.FileContent(treePath)
+
if errors.Is(err, git.ErrBinaryFile) {
+
isBinaryFile = true
+
} else if errors.Is(err, object.ErrFileNotFound) {
+
notFound(w)
+
return
+
} else if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
···
Ref: ref,
Contents: string(safe),
Path: treePath,
+
IsBinary: isBinaryFile,
}
h.showFile(resp, w, l)
+1
types/repo.go
···
Contents string `json:"contents,omitempty"`
Ref string `json:"ref,omitempty"`
Path string `json:"path,omitempty"`
Lines int `json:"lines,omitempty"`
}
···
Contents string `json:"contents,omitempty"`
Ref string `json:"ref,omitempty"`
Path string `json:"path,omitempty"`
+
IsBinary bool `json:"is_binary,omitempty"`
Lines int `json:"lines,omitempty"`
}