Skip to content

Instantly share code, notes, and snippets.

@ajstarks
Created June 13, 2019 22:34
Show Gist options
  • Save ajstarks/18d87e01207ee919754d6dbc025973c8 to your computer and use it in GitHub Desktop.
Save ajstarks/18d87e01207ee919754d6dbc025973c8 to your computer and use it in GitHub Desktop.
// Go Gestalt
// make a series of pages visualizing the layout of Go code
package main
import (
"bufio"
"flag"
"fmt"
"os"
"regexp"
"strings"
"github.com/ajstarks/deck/generate"
)
const (
commentcolor = "lightgray"
structcolor = "rgb(0,0,127)"
packagecolor = "black"
defcolor = "gray"
funcolor = "rgb(127,0,0)"
importcolor = "rgb(0,127,0)"
tabsize = 4
)
// vmap maps one range into another
func vmap(value float64, low1 float64, high1 float64, low2 float64, high2 float64) float64 {
return low2 + (high2-low2)*(value-low1)/(high1-low1)
}
// rematch indicates a match of a regular expression
// errors are considered no match
func rematch(pattern, s string) bool {
m, err := regexp.MatchString(pattern, s)
if err != nil {
return false
}
return m
}
// process reads an input file, and generates a series of pages
// showing the structure of the code.
func process(filename string, deck *generate.Deck, maxline int) error {
r, err := os.Open(filename)
if err != nil {
return err
}
color := defcolor
top := 90.0
bottom := 5.0
left := 5.0
right := 20.0
y := top
page := 1
colsize := 25.0
deck.StartDeck()
deck.StartSlide()
deck.Text(left, 95, filename, "sans", 1.5, "")
deck.TextEnd(95, 95, fmt.Sprintf("Page %d", page), "sans", 1, "")
scanner := bufio.NewScanner(r)
var incomment bool
for scanner.Scan() {
t := scanner.Text()
if strings.HasPrefix(t, "/*") {
incomment = true
}
if strings.HasPrefix(t, "*/") {
incomment = false
}
if rematch(".*//", t) || incomment {
color = commentcolor
} else if rematch("^package", t) {
color = packagecolor
} else if rematch("^func.*{", t) {
color = funcolor
} else if rematch("^type.*struct.*{", t) || rematch("^type.*interface.*{", t) {
color = structcolor
} else if rematch("^import", t) {
color = importcolor
} else {
color = defcolor
}
linelen := len(t)
ntabs := strings.Count(t, "\t")
ntlen := linelen - ntabs
codelen := ntlen + (ntabs * tabsize)
fmaxline := float64(maxline)
x := vmap(float64(codelen), 0, fmaxline, left, right)
tabshift := float64(ntabs)
deck.Line(left+tabshift, y, x, y, 0.5, color)
y -= 1.0
// new column
if y < bottom {
y = top
left += colsize
right += colsize
}
// new page
if left > 100 {
top = 90.0
bottom = 5.0
left = 5.0
right = 20.0
y = top
page++
deck.EndSlide()
deck.StartSlide()
deck.Text(left, 95, filename, "sans", 1.5, "")
deck.TextEnd(95, 95, fmt.Sprintf("Page %d", page), "sans", 1, "")
}
}
deck.EndSlide()
deck.EndDeck()
r.Close()
return nil
}
// for every input file, make a deck
func main() {
linelength := flag.Int("l", 100, "max line length")
flag.Parse()
deck := generate.NewSlides(os.Stdout, 0, 0)
for _, f := range flag.Args() {
if err := process(f, deck, *linelength); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
continue
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment