diff --git a/README.md b/README.md index 6b27cfe..de4423b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,9 @@ USAGE: germanium [FLAGS] [FILE] FLAGS: - -o Write output image to specific filepath [default: ./output.png] + -o, --output Write output image to specific filepath [default: ./output.png] + -f, --font Specify font eg. 'Hack-Bold' + --list-fonts List all available fonts in your system --no-line-number Hide the line number --no-window-access-bar Hide the window access bar ``` diff --git a/font.go b/font.go index 8313423..5916e4e 100644 --- a/font.go +++ b/font.go @@ -2,7 +2,9 @@ package main import ( _ "embed" + "os" + findfont "github.com/flopp/go-findfont" "github.com/golang/freetype/truetype" "golang.org/x/image/font" ) @@ -15,7 +17,20 @@ var ( ) func LoadFont() (font.Face, error) { - ft, err := truetype.Parse(font_hack) + fontData := font_hack + if opts.Font != "Hack-Regular" { + fontPath, err := findfont.Find(opts.Font + ".ttf") + if err != nil { + return nil, err + } + + fontData, err = os.ReadFile(fontPath) + if err != nil { + return nil, err + } + } + + ft, err := truetype.Parse(fontData) if err != nil { return nil, err } diff --git a/formatter.go b/formatter.go index ee6d3c0..8e6fa4d 100644 --- a/formatter.go +++ b/formatter.go @@ -6,6 +6,7 @@ import ( "image/color" "image/png" "io" + "strconv" "github.com/alecthomas/chroma" "golang.org/x/image/font" @@ -36,46 +37,50 @@ func (f *PNGFormatter) Format(w io.Writer, style *chroma.Style, iterator chroma. } func (f *PNGFormatter) writePNG(w io.Writer, style *chroma.Style, tokens []chroma.Token) error { - linepad := fixed.I(f.editor.Min.X + int(f.fontSize)) - x := fixed.Int26_6((f.editor.Min.X + int(f.fontSize)) / int(f.fontSize)) - y := fixed.I(f.editor.Min.Y) + left := fixed.Int26_6(f.editor.Min.X * 64) + y := fixed.Int26_6(f.editor.Min.Y * 64) - for i, tokens := range chroma.SplitTokensIntoLines(tokens) { + lines := chroma.SplitTokensIntoLines(tokens) + format := fmt.Sprintf("%%%dd", len(strconv.Itoa(len(lines)))+2) + + for i, tokens := range lines { y += fixed.I(int(f.fontSize)) if i > 0 { y += fixed.I(int(f.fontSize * 0.25)) // padding between lines } if f.line != nil { - f.drawer.Dot.X = linepad + f.drawer.Dot.X = left f.drawer.Dot.Y = y f.drawer.Src = image.NewUniform(color.White) - f.drawer.DrawString(fmt.Sprintf("%2d", i+1)) + f.drawer.DrawString(fmt.Sprintf(format, i+1)) } + sx := left + fixed.Int26_6(int(f.fontSize)*64*2) + if f.line != nil { + sx += fixed.Int26_6(int(f.fontSize) * 64) + } else { + sx -= fixed.Int26_6(int(f.fontSize) * 64) + } + + f.drawer.Dot.X = sx for _, t := range tokens { s := style.Get(t.Type) f.drawer.Src = image.NewUniform(color.RGBA{s.Colour.Red(), s.Colour.Green(), s.Colour.Blue(), 255}) for _, c := range t.String() { if c == '\n' { - x = fixed.Int26_6((f.editor.Min.X + int(f.fontSize)) / int(f.fontSize)) + f.drawer.Dot.X = sx continue } if c == '\t' { - x += fixed.Int26_6(4) + f.drawer.Dot.X += fixed.Int26_6(float64(f.drawer.MeasureString(" ")) * 4.0) continue } - f.drawer.Dot.X = fixed.I(int(f.fontSize*0.6)) * x - if f.line != nil { - f.drawer.Dot.X += linepad - } else { - f.drawer.Dot.X += fixed.I(f.editor.Min.X) - } + f.drawer.Dot.X += fixed.Int26_6(float64(f.drawer.MeasureString(fmt.Sprintf("%c", c))) / f.fontSize) f.drawer.Dot.Y = y f.drawer.DrawString(fmt.Sprintf("%c", c)) - x++ } } } diff --git a/go.mod b/go.mod index 3c170f8..b8f9185 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.16 require ( github.com/alecthomas/chroma v0.8.2 + github.com/flopp/go-findfont v0.0.0-20201114153133-e7393a00c15b github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/jessevdk/go-flags v1.4.0 golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb diff --git a/go.sum b/go.sum index 5c11335..1d2a739 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,11 @@ +github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U= github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= github.com/alecthomas/chroma v0.8.2 h1:x3zkuE2lUk/RIekyAJ3XRqSCP4zwWDfcw/YJCuCAACg= github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= +github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo= github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= +github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY= github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= @@ -10,15 +13,19 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/flopp/go-findfont v0.0.0-20201114153133-e7393a00c15b h1:/wqXgpZNTP8qV1dPEApjJXlDQd5N/F9U/WEvy5SawUI= +github.com/flopp/go-findfont v0.0.0-20201114153133-e7393a00c15b/go.mod h1:wKKxRDjD024Rh7VMwoU90i6ikQRCr+JTHB5n4Ejkqvw= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -27,5 +34,6 @@ golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/ golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY= golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/main.go b/main.go index 54c2613..d0953ab 100644 --- a/main.go +++ b/main.go @@ -13,12 +13,15 @@ import ( "github.com/alecthomas/chroma/formatters" "github.com/alecthomas/chroma/lexers" "github.com/alecthomas/chroma/styles" + findfont "github.com/flopp/go-findfont" flags "github.com/jessevdk/go-flags" "golang.org/x/image/font" ) type Options struct { Output string `short:"o" long:"output" default:"output.png" description:"Write output image to specific filepath"` + Font string `short:"f" long:"font" default:"Hack-Regular" description:"Specify font eg. 'Hack-Bold'"` + ListFonts bool `long:"list-fonts" description:"List all available fonts in your system"` NoLineNum bool `long:"no-line-number" description:"Hide the line number"` NoWindowAccessBar bool `long:"no-window-access-bar" description:"Hide the window access bar"` } @@ -52,6 +55,11 @@ func main() { os.Exit(exitCodeErr) } + if opts.ListFonts { + listFonts() + os.Exit(exitCodeOK) + } + if len(args) != 1 { printUsage() fmt.Fprintln(os.Stderr, "File to read was not provided") @@ -68,7 +76,9 @@ USAGE: %s [FLAGS] [FILE] FLAGS: - -o Write output image to specific filepath [default: ./output.png] + -o, --output Write output image to specific filepath [default: ./output.png] + -f, --font Specify font eg. 'Hack-Bold' + --list-fonts List all available fonts in your system --no-line-number Hide the line number --no-window-access-bar Hide the window access bar @@ -148,6 +158,16 @@ func run(srcpath string) int { return exitCodeOK } +func listFonts() { + for _, path := range findfont.List() { + base := filepath.Base(path) + ext := filepath.Ext(path) + if ext == ".ttf" { + fmt.Println(base[0 : len(base)-len(ext)]) + } + } +} + func reader(srcpath string) (string, int, error) { if _, err := os.Stat(srcpath); os.IsNotExist(err) { return "", -1, fmt.Errorf("file does not exist")