Skip to content

Commit

Permalink
Move code rendering to the backend & frontend improvements (thomiceli…
Browse files Browse the repository at this point in the history
…#176)

Added Chroma & Goldmark

Added Mermaidjs

More languages supported

Add default values for gist links input

Added copy code from markdown blocks
  • Loading branch information
thomiceli committed Jan 4, 2024
1 parent eff8871 commit 845e28d
Show file tree
Hide file tree
Showing 24 changed files with 511 additions and 143 deletions.
8 changes: 7 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module github.com/thomiceli/opengist
go 1.20

require (
github.com/alecthomas/chroma/v2 v2.12.0
github.com/dustin/go-humanize v1.0.1
github.com/glebarez/go-sqlite v1.21.2
github.com/glebarez/sqlite v1.9.0
github.com/go-playground/validator/v10 v10.15.4
Expand All @@ -13,6 +15,10 @@ require (
github.com/markbates/goth v1.78.0
github.com/rs/zerolog v1.30.0
github.com/stretchr/testify v1.8.4
github.com/yuin/goldmark v1.6.0
github.com/yuin/goldmark-emoji v1.0.2
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
go.abhg.dev/goldmark/mermaid v0.5.0
golang.org/x/crypto v0.13.0
golang.org/x/text v0.13.0
gopkg.in/yaml.v3 v3.0.1
Expand All @@ -21,7 +27,7 @@ require (

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
Expand Down
29 changes: 29 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,16 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
github.com/alecthomas/chroma/v2 v2.12.0 h1:Wh8qLEgMMsN7mgyG8/qIpegky2Hvzr4By6gEF7cmWgw=
github.com/alecthomas/chroma/v2 v2.12.0/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chromedp/cdproto v0.0.0-20230220211738-2b1ec77315c9 h1:wMSvdj3BswqfQOXp2R1bJOAE7xIQLt2dlMQDMf836VY=
github.com/chromedp/chromedp v0.9.1 h1:CC7cC5p1BeLiiS2gfNNPwp3OaUxtRMBjfiw3E3k6dFA=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
Expand All @@ -46,6 +55,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
Expand All @@ -68,6 +81,9 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.15.4 h1:zMXza4EpOdooxPel5xDqXEdXG5r+WggpvnAKMsalBjs=
github.com/go-playground/validator/v10 v10.15.4/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/goccy/go-json v0.9.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
Expand Down Expand Up @@ -151,12 +167,14 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
Expand All @@ -177,6 +195,7 @@ github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++
github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc=
github.com/lestrrat-go/jwx v1.2.21/go.mod h1:9cfxnOH7G1gN75CaJP2hKGcxFEx5sPh1abRIA/ZJVh4=
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA=
github.com/markbates/goth v1.78.0 h1:7VEIFDycJp9deyVv3YraGBPdD0ZYQW93Y3Aw1eVP3BY=
github.com/markbates/goth v1.78.0/go.mod h1:X6xdNgpapSENS0O35iTBBcMHoJDQDfI9bJl+APCkYMc=
Expand Down Expand Up @@ -220,7 +239,17 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark-emoji v1.0.2 h1:c/RgTShNgHTtc6xdz2KKI74jJr6rWi7FPgnP9GAsO5s=
github.com/yuin/goldmark-emoji v1.0.2/go.mod h1:RhP/RWpexdp+KHs7ghKnifRoIs/Bq4nDS7tRbCkOwKY=
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
go.abhg.dev/goldmark/mermaid v0.5.0 h1:mDkykpSPJ+5wCQ8bSXgzJ2KQskjXkI5Ndxz7JYDHW38=
go.abhg.dev/goldmark/mermaid v0.5.0/go.mod h1:OCyk2o85TX2drWHH+HRy6bih2yZlUwbbv/R1MMh1YLs=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
Expand Down
11 changes: 10 additions & 1 deletion internal/db/gist.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package db

import (
"fmt"
"github.com/dustin/go-humanize"
"github.com/labstack/echo/v4"
"os/exec"
"strings"
"time"

"github.com/labstack/echo/v4"
"github.com/thomiceli/opengist/internal/git"
"gorm.io/gorm"
)
Expand Down Expand Up @@ -339,8 +340,16 @@ func (gist *Gist) File(revision string, filename string, truncate bool) (*git.Fi
return nil, nil
}

var size int64

size, err = git.GetFileSize(gist.User.Username, gist.Uuid, revision, filename)
if err != nil {
return nil, err
}

return &git.File{
Filename: filename,
Size: humanize.IBytes(uint64(size)),
Content: content,
Truncated: truncated,
}, err
Expand Down
19 changes: 19 additions & 0 deletions internal/git/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,25 @@ func GetFileContent(user string, gist string, revision string, filename string,
return content, truncated, nil
}

func GetFileSize(user string, gist string, revision string, filename string) (int64, error) {
repositoryPath := RepositoryPath(user, gist)

cmd := exec.Command(
"git",
"cat-file",
"-s",
revision+":"+filename,
)
cmd.Dir = repositoryPath

stdout, err := cmd.Output()
if err != nil {
return 0, err
}

return strconv.ParseInt(strings.TrimSuffix(string(stdout), "\n"), 10, 64)
}

func GetLog(user string, gist string, skip int) ([]*Commit, error) {
repositoryPath := RepositoryPath(user, gist)

Expand Down
1 change: 1 addition & 0 deletions internal/git/output_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

type File struct {
Filename string
Size string
OldFilename string
Content string
Truncated bool
Expand Down
134 changes: 134 additions & 0 deletions internal/render/highlight.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package render

import (
"bufio"
"bytes"
"fmt"
"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/formatters/html"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"
"github.com/thomiceli/opengist/internal/db"
"github.com/thomiceli/opengist/internal/git"
)

type RenderedFile struct {
*git.File
Type string
Lines []string
HTML string
}

type RenderedGist struct {
*db.Gist
Lines []string
HTML string
}

func HighlightFile(file *git.File) (RenderedFile, error) {
rendered := RenderedFile{
File: file,
}

style := newStyle()
lexer := newLexer(file.Filename)
if lexer.Config().Name == "markdown" {
return MarkdownFile(file)
}

formatter := html.New(html.WithClasses(true), html.PreventSurroundingPre(true))

iterator, err := lexer.Tokenise(nil, file.Content)
if err != nil {
return rendered, err
}

htmlbuf := bytes.Buffer{}
w := bufio.NewWriter(&htmlbuf)

tokensLines := chroma.SplitTokensIntoLines(iterator.Tokens())
lines := make([]string, 0, len(tokensLines))
for _, tokens := range tokensLines {
iterator = chroma.Literator(tokens...)
err = formatter.Format(&htmlbuf, style, iterator)
if err != nil {
return rendered, fmt.Errorf("unable to format code: %w", err)
}
lines = append(lines, htmlbuf.String())
htmlbuf.Reset()
}

_ = w.Flush()

rendered.Lines = lines
rendered.Type = parseFileTypeName(*lexer.Config())

return rendered, err
}

func HighlightGistPreview(gist *db.Gist) (RenderedGist, error) {
rendered := RenderedGist{
Gist: gist,
}

style := newStyle()
lexer := newLexer(gist.PreviewFilename)
if lexer.Config().Name == "markdown" {
return MarkdownGistPreview(gist)
}

formatter := html.New(html.WithClasses(true), html.PreventSurroundingPre(true))

iterator, err := lexer.Tokenise(nil, gist.Preview)
if err != nil {
return rendered, err
}

htmlbuf := bytes.Buffer{}
w := bufio.NewWriter(&htmlbuf)

tokensLines := chroma.SplitTokensIntoLines(iterator.Tokens())
lines := make([]string, 0, len(tokensLines))
for _, tokens := range tokensLines {
iterator = chroma.Literator(tokens...)
err = formatter.Format(&htmlbuf, style, iterator)
if err != nil {
return rendered, fmt.Errorf("unable to format code: %w", err)
}
lines = append(lines, htmlbuf.String())
htmlbuf.Reset()
}

_ = w.Flush()

rendered.Lines = lines

return rendered, err
}

func parseFileTypeName(config chroma.Config) string {
fileType := config.Name
if fileType == "fallback" || fileType == "plaintext" {
return "Text"
}

return fileType
}

func newLexer(filename string) chroma.Lexer {
var lexer chroma.Lexer
if lexer = lexers.Get(filename); lexer == nil {
lexer = lexers.Fallback
}

return lexer
}

func newStyle() *chroma.Style {
var style *chroma.Style
if style = styles.Get("catppuccin-latte"); style == nil {
style = styles.Fallback
}

return style
}
47 changes: 47 additions & 0 deletions internal/render/markdown.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package render

import (
"bytes"
"github.com/alecthomas/chroma/v2/formatters/html"
"github.com/thomiceli/opengist/internal/db"
"github.com/thomiceli/opengist/internal/git"
"github.com/yuin/goldmark"
emoji "github.com/yuin/goldmark-emoji"
highlighting "github.com/yuin/goldmark-highlighting/v2"
"github.com/yuin/goldmark/extension"
"go.abhg.dev/goldmark/mermaid"
)

func MarkdownGistPreview(gist *db.Gist) (RenderedGist, error) {
var buf bytes.Buffer
err := newMarkdown().Convert([]byte(gist.Preview), &buf)

return RenderedGist{
Gist: gist,
HTML: buf.String(),
}, err
}

func MarkdownFile(file *git.File) (RenderedFile, error) {
var buf bytes.Buffer
err := newMarkdown().Convert([]byte(file.Content), &buf)

return RenderedFile{
File: file,
HTML: buf.String(),
Type: "Markdown",
}, err
}

func newMarkdown() goldmark.Markdown {
return goldmark.New(
goldmark.WithExtensions(
extension.GFM,
highlighting.NewHighlighting(
highlighting.WithStyle("catppuccin-latte"),
highlighting.WithFormatOptions(html.WithClasses(true))),
emoji.Emoji,
&mermaid.Extender{},
),
)
}

0 comments on commit 845e28d

Please sign in to comment.