add basic features

This commit is contained in:
Christoph Herb
2024-10-09 22:03:53 +02:00
parent 2191cababd
commit a72317b093
12 changed files with 2420 additions and 30 deletions

33
Makefile Normal file
View File

@@ -0,0 +1,33 @@
.PHONY: all format lint clean
GOCMD=go
LDFLAGS="-s -w ${LDFLAGS_OPT}"
all: build format lint ## Format, lint and build
build: ## Build
go build -o bin/go-grip main.go
test: ## Test
${GOCMD} test ./...
compile: ## Compile for every OS and Platform
echo "Compiling for every OS and Platform"
GOOS=darwin GOARCH=amd64 go build -o bin/go-grip-darwin-amd64 main.go
GOOS=darwin GOARCH=arm64 go build -o bin/go-grip-darwin-arm64 main.go
GOOS=linux GOARCH=amd64 go build -o bin/go-grip-linux-amd64 main.go
GOOS=linux GOARCH=arm64 go build -o bin/go-grip-linux-arm64 main.go
GOOS=windows GOARCH=amd64 go build -o bin/go-grip-windows-amd64 main.go
GOOS=windows GOARCH=arm64 go build -o bin/go-grip-windows-arm64 main.go
format: ## Format code
${GOCMD} fmt ./...
lint: ## Run linter
golangci-lint run
clean: ## Cleanup build dir
rm -r bin/
help: ## Display this help screen
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

16
README.md Normal file
View File

@@ -0,0 +1,16 @@
<br />
<div align="center">
<a href="#">
<img src=".github/assets/nix-dots.png" alt="Logo" height="80">
</a>
</div>
# go-grip
## Getting started on macOS
To get started on a bare `macOS` installation, first install Nix:
```
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
```

View File

@@ -1,34 +1,31 @@
/*
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
*/
package cmd
import (
"os"
"github.com/chrishrb/go-grip/pkg"
"github.com/spf13/cobra"
)
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "go-grip",
Short: "A brief description of your application",
Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Use: "go-grip [file]",
Short: "Render markdown document as html",
Args: cobra.MatchAll(cobra.MinimumNArgs(1), cobra.OnlyValidArgs),
Run: func(cmd *cobra.Command, args []string) {
dark, _ := cmd.Flags().GetBool("dark")
browser, _ := cmd.Flags().GetBool("browser")
port, _ := cmd.Flags().GetInt("port")
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
client := pkg.Client{Dark: dark, OpenBrowser: browser, Port: port}
bytes, err := client.MdToHTML(args[0])
cobra.CheckErr(err)
err = client.Serve(bytes)
cobra.CheckErr(err)
},
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
@@ -37,15 +34,7 @@ func Execute() {
}
func init() {
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.go-grip.yaml)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
rootCmd.Flags().BoolP("dark", "d", false, "Darkmode")
rootCmd.Flags().BoolP("browser", "b", true, "Open new browser tab")
rootCmd.Flags().IntP("port", "p", 6419, "Port to use")
}

3
go.mod
View File

@@ -3,6 +3,9 @@ module github.com/chrishrb/go-grip
go 1.22.7
require (
github.com/alecthomas/chroma/v2 v2.14.0 // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/gomarkdown/markdown v0.0.0-20240930133441-72d49d9543d8 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect

6
go.sum
View File

@@ -1,4 +1,10 @@
github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/gomarkdown/markdown v0.0.0-20240930133441-72d49d9543d8 h1:4txT5G2kqVAKMjzidIabL/8KqjIK71yj30YOeuxLn10=
github.com/gomarkdown/markdown v0.0.0-20240930133441-72d49d9543d8/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=

7
pkg/client.go Normal file
View File

@@ -0,0 +1,7 @@
package pkg
type Client struct {
Dark bool
OpenBrowser bool
Port int
}

23
pkg/open.go Normal file
View File

@@ -0,0 +1,23 @@
package pkg
import (
"os/exec"
"runtime"
)
func Open(url string) error {
var cmd string
var args []string
switch runtime.GOOS {
case "windows":
cmd = "cmd"
args = []string{"/c", "start"}
case "darwin":
cmd = "open"
default: // "linux", "freebsd", "openbsd", "netbsd"
cmd = "xdg-open"
}
args = append(args, url)
return exec.Command(cmd, args...).Start()
}

48
pkg/parser.go Normal file
View File

@@ -0,0 +1,48 @@
package pkg
import (
"io"
"os"
"github.com/alecthomas/chroma/v2/quick"
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/ast"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
)
func (client *Client) MdToHTML(filename string) ([]byte, error) {
bytes, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
extensions := parser.CommonExtensions | parser.AutoHeadingIDs
p := parser.NewWithExtensions(extensions)
doc := p.Parse(bytes)
htmlFlags := html.CommonFlags
opts := html.RendererOptions{Flags: htmlFlags, RenderNodeHook: client.renderHookCodeBlock}
renderer := html.NewRenderer(opts)
return markdown.Render(doc, renderer), err
}
func (client *Client) renderHookCodeBlock(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool) {
block, ok := node.(*ast.CodeBlock)
if !ok {
return ast.GoToNext, false
}
var style string
switch client.Dark {
case true:
style = "github-dark"
default:
style = "github"
}
quick.Highlight(w, string(block.Literal), string(block.Info), "html", style)
return ast.GoToNext, true
}

50
pkg/webserver.go Normal file
View File

@@ -0,0 +1,50 @@
package pkg
import (
"fmt"
"log"
"net/http"
"path/filepath"
"text/template"
)
type htmlStruct struct {
Content string
Darkmode bool
}
func (client *Client) Serve(htmlContent []byte) error {
// Serve static files
fs := http.FileServer(http.Dir("./static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
// Serve website with rendered markdown
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
err := serveTemplate(w, htmlStruct{Content: string(htmlContent), Darkmode: client.Dark})
if err != nil {
log.Fatal(err)
}
})
addr := fmt.Sprintf("http://localhost:%d", client.Port)
fmt.Printf("Starting server: %s\n", addr)
if client.OpenBrowser {
Open(addr)
}
http.ListenAndServe(fmt.Sprintf(":%d", client.Port), nil)
return nil
}
func serveTemplate(w http.ResponseWriter, html htmlStruct) error {
w.Header().Set("Content-Type", "text/html")
lp := filepath.Join("templates", "layout.html")
tmpl, err := template.ParseFiles(lp)
if err != nil {
return err
}
err = tmpl.Execute(w, html)
return err
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

19
templates/layout.html Normal file
View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Markdown Preview</title>
{{if .Darkmode }}
<link rel="stylesheet" href="/static/css/github-markdown-dark.css">
{{else}}
<link rel="stylesheet" href="/static/css/github-markdown-light.css">
{{end}}
</head>
<body class="markdown-body entry-content container-lg">
<div style="padding: 32px;">
<div class="">
{{ .Content }}
</div>
</div>
</body>
</html>