Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
vendor
result
bin
bin/
output/
go-grip
tests-local/
50 changes: 37 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: all run format emojiscraper build vendor test compile format lint clean
.PHONY: all run format emojiscraper build vendor test compile format lint clean release

# If the first argument is "run"...
ifeq (run,$(firstword $(MAKECMDGOALS)))
Expand All @@ -9,7 +9,16 @@ ifeq (run,$(firstword $(MAKECMDGOALS)))
endif

GOCMD=go
LDFLAGS="-s -w ${LDFLAGS_OPT}"

# pkgver variables
VERSION=$(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
COMMIT=$(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
BUILD_DATE=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
LDFLAGS=-s -w
VERSION_FLAGS=-X github.com/chrishrb/go-grip/cmd.Version=$(VERSION) \
-X github.com/chrishrb/go-grip/cmd.CommitHash=$(COMMIT) \
-X github.com/chrishrb/go-grip/cmd.BuildDate=$(BUILD_DATE) \
FULL_LDFLAGS=-ldflags "$(LDFLAGS) $(VERSION_FLAGS)"

all: vendor build format lint ## Format, lint and build

Expand All @@ -20,31 +29,46 @@ emojiscraper: ## Run emojiscraper
go run -tags debug main.go emojiscraper defaults/static/emojis pkg/emoji_map.go

build: ## Build
go build -tags debug -o bin/go-grip main.go
$(GOCMD) build -tags debug $(FULL_LDFLAGS) -o bin/go-grip main.go

vendor: ## Vendor
go mod vendor
$(GOCMD) mod vendor

test: ## Test
${GOCMD} 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.exe main.go
GOOS=windows GOARCH=arm64 go build -o bin/go-grip-windows-arm64.exe main.go
GOOS=darwin GOARCH=amd64 $(GOCMD) build $(FULL_LDFLAGS) -o bin/go-grip-darwin-amd64 main.go
GOOS=darwin GOARCH=arm64 $(GOCMD) build $(FULL_LDFLAGS) -o bin/go-grip-darwin-arm64 main.go
GOOS=linux GOARCH=amd64 $(GOCMD) build $(FULL_LDFLAGS) -o bin/go-grip-linux-amd64 main.go
GOOS=linux GOARCH=arm64 $(GOCMD) build $(FULL_LDFLAGS) -o bin/go-grip-linux-arm64 main.go
GOOS=windows GOARCH=amd64 $(GOCMD) build $(FULL_LDFLAGS) -o bin/go-grip-windows-amd64.exe main.go
GOOS=windows GOARCH=arm64 $(GOCMD) build $(FULL_LDFLAGS) -o bin/go-grip-windows-arm64.exe main.go

release: clean
@echo "Creating release $(VERSION)"
@if echo $(VERSION) | grep -q "dirty"; then \
echo "Error: dirty repo."; \
fi
mkdir -p bin/release
GOOS=darwin GOARCH=amd64 $(GOCMD) build $(FULL_LDFLAGS) -o bin/release/go-grip-$(VERSION)-darwin-amd64 main.go
GOOS=darwin GOARCH=arm64 $(GOCMD) build $(FULL_LDFLAGS) -o bin/release/go-grip-$(VERSION)-darwin-arm64 main.go
GOOS=linux GOARCH=amd64 $(GOCMD) build $(FULL_LDFLAGS) -o bin/release/go-grip-$(VERSION)-linux-amd64 main.go
GOOS=linux GOARCH=arm64 $(GOCMD) build $(FULL_LDFLAGS) -o bin/release/go-grip-$(VERSION)-linux-arm64 main.go
GOOS=windows GOARCH=amd64 $(GOCMD) build $(FULL_LDFLAGS) -o bin/release/go-grip-$(VERSION)-windows-amd64.exe main.go
GOOS=windows GOARCH=arm64 $(GOCMD) build $(FULL_LDFLAGS) -o bin/release/go-grip-$(VERSION)-windows-arm64.exe main.go
@echo "Release $(VERSION) created in bin/release/"

format: ## Format code
${GOCMD} fmt ./...
$(GOCMD) fmt ./...

lint: ## Run linter
golangci-lint run

clean: ## Cleanup build dir
rm -r bin/
rm -rf bin/
@go mod tidy

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}'
109 changes: 91 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<h3 align="center">go-grip</h3>

<p align="center">
Render your markdown files local<br>- with the look of GitHub
Render your markdown files local<br> (github flavored rendering)
</p>
</div>

Expand Down Expand Up @@ -55,46 +55,119 @@ go install github.com/chrishrb/go-grip@latest
> You can also use nix flakes to install this plugin.
> More useful information [here](https://nixos.wiki/wiki/Flakes).

## :hammer: Usage
## :hammer: Commands and Usage

To render the `README.md` file simply execute:
### Basic Usage

```bash
go-grip README.md
# or
go-grip

go-grip [COMMAND] <args>

# go-grip --help
Available commands:
go-grip render FILE - Generate static HTML from markdown
go-grip serve FILE - Serve markdown via local HTTP server

Available Commands:
completion Generate the autocompletion script for the specified shell
emojiscraper Scrape emojis from gist
help Help about any command
render Render markdown document as html
serve Run as a server and serve the markdown file
version Print the version number of go-grip

Flags:
-h, --help help for go-grip

Use "go-grip [command] --help" for more information about a command.

```

The browser will automatically open on http://localhost:6419. You can disable this behaviour with the `-b=false` option.
### Commands

You can also specify a port:
#### `render` - Generate static HTML Files

Render a markdown file as static HTML.

```
Usage:
go-grip render [file|directory] [flags]

Optional Flags:
--bounding-box Add bounding box to HTML output (default true)
-d, --directory Render all markdown files in directory
-h, --help help for render
-o, --output string Output directory for static files
--theme string Select CSS theme [light/dark/auto] (default "auto")

```bash
go-grip -p 80 README.md
```

or just open a file-tree with all available files in the current directory:
Examples:

```bash
go-grip -r=false
# render a single markdown file (opens it in a new browser tab)
go-grip render README.md

# specify custom output directory
go-grip render README.md -o /path/to/output

# render ALL markdown files in a directory
go-grip render -d /path/to/my-note/ --output ./html-notes/
```

It's also possible to activate the darkmode:
### `serve` - Live Preview Server

Start a local server to render and serve the markdown file.

The server will watch for changes to the file and automatically refresh the browser.
This is useful for live previewing markdown as you edit it.

```
Usage:
go-grip serve FILE [flags]

Flags:
--bounding-box Add bounding box to HTML output (default true)
-b, --browser Open browser tab automatically (default true)
-h, --help help for serve
-H, --host string Host to listen on (default "localhost")
-p, --port int Port to listen on (default 6419)
--theme string Select CSS theme [light/dark/auto] (default "auto")
```

Examples:

```bash
go-grip -d .
# Start server for live preview of a file
go-grip serve README.md

# Specify host and port
go-grip serve README.md -H 0.0.0.0 -p 8080

# Disable automatic browser opening
go-grip serve README.md -b=false
```

To terminate the current server simply press `CTRL-C`.
#### `-d/--directory` flag

When passed after the the `render` command, go-grip will:

1. Generate HTML for all markdown files in the directory
2. Create an index page linking to all rendered files
3. Copy all required static assets (CSS, JS, images)

## :pencil: Examples
## :pencil: Screen shots

<img src="./.github/docs/example-1.png" alt="examples" width="1000"/>

## :bug: Known TODOs / Bugs
## :bug: TODOs

- [ ] Tests and refactoring
- [ ] Make it possible to export the generated html
- [ ] Move `theme` selection feature from CLI to a button in rendered HTML
- [ ] Auto `Table of content` generation
- [ ] Purged static files (Opens the door for Single HTML output)
- [ ] Github flavored `blob` support
- [ ] Output to Image

## :pushpin: Similar tools

Expand Down
95 changes: 95 additions & 0 deletions cmd/render.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package cmd

import (
"fmt"
"os"
"path/filepath"

"github.com/chrishrb/go-grip/pkg"
"github.com/spf13/cobra"
)

var directoryMode bool

var renderCmd = &cobra.Command{
Use: "render [file|directory]",
Short: "render md document as static html",
Long: `Render a markdown file(s) as static HTML.

Basic usage:
go-grip render FILE # generate static HTML for a single file
go-grip render FILE --output DIR # specify output directory
go-grip render --directory DIR # render all markdown files in directory`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
input := args[0]

parser := pkg.NewParser(theme)
srv := pkg.NewServer(host, port, theme, boundingBox, browser, parser)

if outputDir == "" {
cacheDir, err := os.UserCacheDir()
if err != nil {
return fmt.Errorf("failed to get cache directory: %v", err)
}
outputDir = filepath.Join(cacheDir, "go-grip")
}

if err := os.MkdirAll(outputDir, 0755); err != nil {
return fmt.Errorf("failed to create output directory: %v", err)
}

if directoryMode {
return renderDirectory(srv, input, outputDir)
} else {
return renderSingleFile(srv, input, outputDir)
}
},
}

func renderSingleFile(srv *pkg.Server, filePath string, outputDir string) error {
info, err := os.Stat(filePath)
if err != nil {
return fmt.Errorf("file not found: %s - %v", filePath, err)
}

if info.IsDir() {
return fmt.Errorf("expected a file but got a directory '%s'. Use --directory flag for directories", filePath)
}

if filepath.Ext(filePath) != ".md" {
return fmt.Errorf("file '%s' must be a markdown file with .md extension", filePath)
}

if err := srv.GenerateSingleFile(filePath, outputDir); err != nil {
return fmt.Errorf("failed to generate HTML: %v", err)
}

return nil
}

func renderDirectory(srv *pkg.Server, dirPath string, outputDir string) error {
info, err := os.Stat(dirPath)
if err != nil {
return fmt.Errorf("directory not found: %s - %v", dirPath, err)
}

if !info.IsDir() {
return fmt.Errorf("expected a directory but got a file '%s'. Remove --directory flag for single files", dirPath)
}

if err := srv.GenerateDirectoryFiles(dirPath, outputDir); err != nil {
return fmt.Errorf("failed to generate HTML files: %v", err)
}

return nil
}

func init() {
rootCmd.AddCommand(renderCmd)

renderCmd.Flags().StringVar(&theme, "theme", "auto", "Select CSS theme [light/dark/auto]")
renderCmd.Flags().BoolVar(&boundingBox, "bounding-box", true, "Add bounding box to HTML output")
renderCmd.Flags().StringVarP(&outputDir, "output", "o", "", "Output directory for static files")
renderCmd.Flags().BoolVarP(&directoryMode, "directory", "d", false, "Render all markdown files in directory")
}
45 changes: 21 additions & 24 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,30 @@ package cmd
import (
"os"

"github.com/chrishrb/go-grip/pkg"
"github.com/spf13/cobra"
)

var (
theme string
boundingBox bool

browser bool
host string
port int

outputDir string
)

var rootCmd = &cobra.Command{
Use: "go-grip [file]",
Use: "go-grip [command] <args>",
Short: "Render markdown document as html",
Args: cobra.MatchAll(cobra.OnlyValidArgs),
RunE: func(cmd *cobra.Command, args []string) error {
theme, _ := cmd.Flags().GetString("theme")
browser, _ := cmd.Flags().GetBool("browser")
host, _ := cmd.Flags().GetString("host")
port, _ := cmd.Flags().GetInt("port")
boundingBox, _ := cmd.Flags().GetBool("bounding-box")

var file string
if len(args) == 1 {
file = args[0]
}

parser := pkg.NewParser(theme)
server := pkg.NewServer(host, port, theme, boundingBox, browser, parser)
return server.Serve(file)
},
Long: `go-grip is a tool for rendering markdown documents as HTML.

Available commands:
go-grip render FILE - Generate static HTML from markdown
go-grip serve FILE - Serve markdown via local HTTP server `,

SilenceUsage: true,
}

func Execute() {
Expand All @@ -37,9 +37,6 @@ func Execute() {
}

func init() {
rootCmd.Flags().String("theme", "auto", "Select css theme [light/dark/auto]")
rootCmd.Flags().BoolP("browser", "b", true, "Open new browser tab")
rootCmd.Flags().StringP("host", "H", "localhost", "Host to use")
rootCmd.Flags().IntP("port", "p", 6419, "Port to use")
rootCmd.Flags().Bool("bounding-box", true, "Add bounding box to HTML")
// no flag is used as root,
//TODO: potential for backwards compatibility
}
Loading