Prettier printing.
This commit is contained in:
parent
8a218f35c0
commit
467d1d3d44
5 changed files with 73 additions and 26 deletions
|
|
@ -196,14 +196,14 @@ func expandSigils(input string, vars map[string][]string) []string {
|
||||||
func expandRecipeSigils(input string, vars map[string][]string) string {
|
func expandRecipeSigils(input string, vars map[string][]string) string {
|
||||||
expanded := ""
|
expanded := ""
|
||||||
for i := 0; i < len(input); {
|
for i := 0; i < len(input); {
|
||||||
j := strings.IndexAny(input[i:], "$\\")
|
off := strings.IndexAny(input[i:], "$\\")
|
||||||
if j < 0 {
|
if off < 0 {
|
||||||
expanded += input[i:]
|
expanded += input[i:]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
expanded += input[i : i+off]
|
||||||
|
i += off
|
||||||
|
|
||||||
expanded += input[i:j]
|
|
||||||
i = j
|
|
||||||
c, w := utf8.DecodeRuneInString(input[i:])
|
c, w := utf8.DecodeRuneInString(input[i:])
|
||||||
if c == '$' {
|
if c == '$' {
|
||||||
i += w
|
i += w
|
||||||
|
|
|
||||||
8
lex.go
8
lex.go
|
|
@ -49,6 +49,7 @@ type token struct {
|
||||||
typ tokenType // token type
|
typ tokenType // token type
|
||||||
val string // token string
|
val string // token string
|
||||||
line int // line where it was found
|
line int // line where it was found
|
||||||
|
col int // column on which the token began
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *token) String() string {
|
func (t *token) String() string {
|
||||||
|
|
@ -65,6 +66,7 @@ type lexer struct {
|
||||||
input string // input string to be lexed
|
input string // input string to be lexed
|
||||||
output chan token // channel on which tokens are sent
|
output chan token // channel on which tokens are sent
|
||||||
start int // token beginning
|
start int // token beginning
|
||||||
|
startcol int // column on which the token begins
|
||||||
pos int // position within input
|
pos int // position within input
|
||||||
line int // line within input
|
line int // line within input
|
||||||
col int // column within input
|
col int // column within input
|
||||||
|
|
@ -129,11 +131,13 @@ func (l *lexer) next() rune {
|
||||||
func (l *lexer) skip() {
|
func (l *lexer) skip() {
|
||||||
l.next()
|
l.next()
|
||||||
l.start = l.pos
|
l.start = l.pos
|
||||||
|
l.startcol = l.col
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lexer) emit(typ tokenType) {
|
func (l *lexer) emit(typ tokenType) {
|
||||||
l.output <- token{typ, l.input[l.start:l.pos], l.line}
|
l.output <- token{typ, l.input[l.start:l.pos], l.line, l.startcol}
|
||||||
l.start = l.pos
|
l.start = l.pos
|
||||||
|
l.startcol = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consume the next run if it is in the given string.
|
// Consume the next run if it is in the given string.
|
||||||
|
|
@ -189,7 +193,7 @@ func (l *lexer) skipUntil(invalid string) {
|
||||||
|
|
||||||
// Start a new lexer to lex the given input.
|
// Start a new lexer to lex the given input.
|
||||||
func lex(input string) (*lexer, chan token) {
|
func lex(input string) (*lexer, chan token) {
|
||||||
l := &lexer{input: input, output: make(chan token), line: 1, indented: true}
|
l := &lexer{input: input, output: make(chan token), line: 1, col: 0, indented: true}
|
||||||
go l.run()
|
go l.run()
|
||||||
return l, l.output
|
return l, l.output
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
mk.go
30
mk.go
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// True if messages should be printed without fancy colors.
|
// True if messages should be printed without fancy colors.
|
||||||
|
|
@ -13,6 +14,9 @@ var nocolor bool = false
|
||||||
// True if we are no actualyl executing any recipes or updating any timestamps.
|
// True if we are no actualyl executing any recipes or updating any timestamps.
|
||||||
var dryrun bool = false
|
var dryrun bool = false
|
||||||
|
|
||||||
|
// Lock on standard out, messages don't get interleaved too much.
|
||||||
|
var mkMsgMutex sync.Mutex
|
||||||
|
|
||||||
// The maximum number of times an rule may be applied.
|
// The maximum number of times an rule may be applied.
|
||||||
const max_rule_cnt = 3
|
const max_rule_cnt = 3
|
||||||
|
|
||||||
|
|
@ -29,7 +33,9 @@ const (
|
||||||
|
|
||||||
func mk(rs *ruleSet, target string, dryrun bool) {
|
func mk(rs *ruleSet, target string, dryrun bool) {
|
||||||
g := buildgraph(rs, target)
|
g := buildgraph(rs, target)
|
||||||
//g.visualize(os.Stdout)
|
if g.root.exists {
|
||||||
|
return
|
||||||
|
}
|
||||||
mkNode(g, g.root)
|
mkNode(g, g.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,13 +135,13 @@ func mkNode(g *graph, u *node) {
|
||||||
|
|
||||||
// execute the recipe, unless the prereqs failed
|
// execute the recipe, unless the prereqs failed
|
||||||
if finalstatus != nodeStatusFailed {
|
if finalstatus != nodeStatusFailed {
|
||||||
mkPrintMessage("mking " + u.name)
|
//mkPrintMessage("mking " + u.name)
|
||||||
if !dorecipe(u.name, u, e) {
|
if !dorecipe(u.name, u, e) {
|
||||||
finalstatus = nodeStatusFailed
|
finalstatus = nodeStatusFailed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mkPrintSuccess("finished mking " + u.name)
|
//mkPrintSuccess("finished mking " + u.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mkError(msg string) {
|
func mkError(msg string) {
|
||||||
|
|
@ -158,26 +164,34 @@ func mkPrintSuccess(msg string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func mkPrintMessage(msg string) {
|
func mkPrintMessage(msg string) {
|
||||||
|
mkMsgMutex.Lock()
|
||||||
if nocolor {
|
if nocolor {
|
||||||
fmt.Println(msg)
|
fmt.Println(msg)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%s%s%s\n", colorBlue, msg, colorDefault)
|
fmt.Printf("%s%s%s\n", colorBlue, msg, colorDefault)
|
||||||
}
|
}
|
||||||
|
mkMsgMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func mkPrintRecipe(msg string) {
|
func mkPrintRecipe(target string, recipe string) {
|
||||||
if !nocolor {
|
mkMsgMutex.Lock()
|
||||||
os.Stdout.WriteString(colorYellow)
|
if nocolor {
|
||||||
|
fmt.Printf("%s: ", target)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s%s%s => %s", colorBlue, target, colorDefault, colorMagenta)
|
||||||
|
}
|
||||||
|
printIndented(os.Stdout, recipe, len(target)+4)
|
||||||
|
if len(recipe) == 0 {
|
||||||
|
os.Stdout.WriteString("\n")
|
||||||
}
|
}
|
||||||
printIndented(os.Stdout, msg)
|
|
||||||
if !nocolor {
|
if !nocolor {
|
||||||
os.Stdout.WriteString(colorDefault)
|
os.Stdout.WriteString(colorDefault)
|
||||||
}
|
}
|
||||||
|
mkMsgMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var mkfilepath string
|
var mkfilepath string
|
||||||
var dryrun bool
|
|
||||||
flag.StringVar(&mkfilepath, "f", "mkfile", "use the given file as mkfile")
|
flag.StringVar(&mkfilepath, "f", "mkfile", "use the given file as mkfile")
|
||||||
flag.BoolVar(&dryrun, "n", false, "print commands without actually executing")
|
flag.BoolVar(&dryrun, "n", false, "print commands without actually executing")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
|
||||||
4
parse.go
4
parse.go
|
|
@ -76,7 +76,7 @@ func parseInto(input string, name string, rules *ruleSet) {
|
||||||
|
|
||||||
// insert a dummy newline to allow parsing of any assignments or recipeless
|
// insert a dummy newline to allow parsing of any assignments or recipeless
|
||||||
// rules to finish.
|
// rules to finish.
|
||||||
state = state(p, token{tokenNewline, "\n", l.line})
|
state = state(p, token{tokenNewline, "\n", l.line, l.col})
|
||||||
|
|
||||||
// TODO: Error when state != parseTopLevel
|
// TODO: Error when state != parseTopLevel
|
||||||
}
|
}
|
||||||
|
|
@ -339,7 +339,7 @@ func parseRecipe(p *parser, t token) parserStateFun {
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.typ == tokenRecipe {
|
if t.typ == tokenRecipe {
|
||||||
r.recipe = t.val
|
r.recipe = stripIndentation(t.val, t.col)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.rules.add(r)
|
p.rules.add(r)
|
||||||
|
|
|
||||||
49
recipe.go
49
recipe.go
|
|
@ -10,28 +10,57 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Try to unindent a recipe, so that it begins an column 0. (This is mainly for
|
// Try to unindent a recipe, so that it begins an column 0. (This is mainly for
|
||||||
// recipes in python, or other indentation-significant languages.)
|
// recipes in python, or other indentation-significant languages.)
|
||||||
//func stripIndentation(s string) string {
|
func stripIndentation(s string, mincol int) string {
|
||||||
|
// trim leading whitespace
|
||||||
//}
|
|
||||||
|
|
||||||
// Indent each line of a recipe.
|
|
||||||
func printIndented(out io.Writer, s string) {
|
|
||||||
reader := bufio.NewReader(strings.NewReader(s))
|
reader := bufio.NewReader(strings.NewReader(s))
|
||||||
|
output := ""
|
||||||
for {
|
for {
|
||||||
line, err := reader.ReadString('\n')
|
line, err := reader.ReadString('\n')
|
||||||
if len(line) > 0 {
|
col := 0
|
||||||
io.WriteString(out, " ")
|
i := 0
|
||||||
io.WriteString(out, line)
|
for i < len(line) && col < mincol {
|
||||||
|
c, w := utf8.DecodeRuneInString(line[i:])
|
||||||
|
if strings.IndexRune(" \t\n", c) >= 0 {
|
||||||
|
col += 1
|
||||||
|
i += w
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output += line[i:]
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indent each line of a recipe.
|
||||||
|
func printIndented(out io.Writer, s string, ind int) {
|
||||||
|
indentation := strings.Repeat(" ", ind)
|
||||||
|
reader := bufio.NewReader(strings.NewReader(s))
|
||||||
|
firstline := true
|
||||||
|
for {
|
||||||
|
line, err := reader.ReadString('\n')
|
||||||
|
if len(line) > 0 {
|
||||||
|
if !firstline {
|
||||||
|
io.WriteString(out, indentation)
|
||||||
|
}
|
||||||
|
io.WriteString(out, line)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
firstline = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute a recipe.
|
// Execute a recipe.
|
||||||
|
|
@ -70,7 +99,7 @@ func dorecipe(target string, u *node, e *edge) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !e.r.attributes.quiet {
|
if !e.r.attributes.quiet {
|
||||||
mkPrintRecipe(input)
|
mkPrintRecipe(target, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dryrun {
|
if dryrun {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue