gitshow

Log | Files | Refs

file.go (2248B)


      1 package main
      2 
      3 import (
      4 	"github.com/gorilla/mux"
      5 	// "fmt"
      6 	"html/template"
      7 	"github.com/go-git/go-git/v5/plumbing"
      8 	"log"
      9 	"net/http"
     10 	"path/filepath"
     11 	"strings"
     12 
     13 	// Chroma
     14 	chromahtml "github.com/alecthomas/chroma/v2/formatters/html"
     15 	"github.com/alecthomas/chroma/v2/lexers"
     16 	"github.com/alecthomas/chroma/v2/styles"
     17 )
     18 
     19 type FilePageData struct {
     20 	Name   string
     21 	Content template.HTML
     22 	Ref string
     23 }
     24 
     25 func getFile(w http.ResponseWriter, r *http.Request) {
     26 	logger := log.Default()
     27 	vars := mux.Vars(r)
     28 	reponame := vars["repository"]
     29 
     30 	repo, err := checkRepo(reponame)
     31 	if err != nil {
     32 		w.WriteHeader(http.StatusNotFound)
     33 		return
     34 	}
     35 
     36 	hash, err := repo.ResolveRevision(plumbing.Revision(vars["ref"]))
     37 	if err != nil {
     38 		w.WriteHeader(http.StatusNotFound)
     39 		return
     40 	}
     41 
     42 	commit, err := repo.CommitObject(*hash)
     43 	if err != nil {
     44 		w.WriteHeader(http.StatusNotFound)
     45 		return
     46 	}
     47 
     48 	// Get the path of the entry
     49 	path := r.RequestURI[len("/repos/") + len(reponame) + len("/file/") + len(vars["ref"]) + 1:len(r.RequestURI)]
     50 	logger.Printf("Trying to get file: %s (%s)", path, r.RequestURI)
     51 	entry, err := commit.File(path)
     52 	if err != nil {
     53 		w.WriteHeader(http.StatusNotFound)
     54 		return
     55 	}
     56 
     57 	content, err := entry.Contents()
     58 	if err != nil {
     59 		logger.Fatal(err)
     60 	}
     61 
     62 	lexer := lexers.Match(path)
     63 	if lexer == nil {
     64 		lexer = lexers.Fallback
     65 	}
     66 
     67 	if err != nil {
     68 		logger.Fatal(err)
     69 	}
     70 
     71 	var formatter = chromahtml.New(
     72 		chromahtml.WithLineNumbers(true),
     73 		chromahtml.WithClasses(true),
     74 		chromahtml.WithLinkableLineNumbers(true, ""),
     75 	)
     76 
     77 	if formatter == nil {
     78 		logger.Fatal("Could not get html formatter")
     79 	}
     80 
     81 	iterator, err := lexer.Tokenise(nil, content)
     82 	if err != nil {
     83 		w.WriteHeader(http.StatusInternalServerError)
     84 		return
     85 	}
     86 
     87 	sbuilder := new(strings.Builder)
     88 	formatter.Format(sbuilder, styles.Fallback, iterator)
     89 
     90 	w.WriteHeader(http.StatusOK)
     91 
     92 	tmpl := template.Must(template.ParseFiles(
     93 		filepath.Join("templates", "file.html"),
     94 		filepath.Join("templates", "wrap.html"),
     95 	))
     96 
     97 	_, ishtmx := r.Header["Hx-Request"]
     98 
     99 	data := FilePageData {
    100 		Name: reponame,
    101 		Content: template.HTML(sbuilder.String()),
    102 		Ref: commit.Hash.String(),
    103 	}
    104 
    105 	if ishtmx {
    106 		tmpl.ExecuteTemplate(w, "file_content", data)
    107 	} else {
    108 		tmpl.Execute(w, data)
    109 	}
    110 }