diff --git a/plab/flatten/flatten.go b/plab/flatten/flatten.go index 7f4e6168f96407fd3cb09a30cdaeaf6ae7081389..af95aa8ac5f0baedc44cf22382f448f990aab093 100644 --- a/plab/flatten/flatten.go +++ b/plab/flatten/flatten.go @@ -3,6 +3,8 @@ package flatten import ( "fmt" "git.sch.bme.hu/insert-epic-projlab-team-name-here/tooling/plab/helpers" + "io/ioutil" + "os" ) var Flatten = helpers.Subcommand{ @@ -26,7 +28,18 @@ var Flatten = helpers.Subcommand{ panic(e) } } - fmt.Println("flattened") + b, e := ioutil.ReadFile(entry) + if e != nil { + panic(e) + } + o, e := InlineAllFuncs(string(b)) + if e != nil { + panic(e) + } + e = ioutil.WriteFile(out, []byte(o), os.ModePerm) + if e != nil { + panic(e) + } }, Help: "flaten a .tex file", } diff --git a/plab/flatten/flattenable.go b/plab/flatten/flattenable.go index b84178b213a47061711f0127b2035bf91d53fdb5..090c552daf4234a7f1a346c2cccdbaefd4a83f9b 100644 --- a/plab/flatten/flattenable.go +++ b/plab/flatten/flattenable.go @@ -1,5 +1,7 @@ package flatten type flattenable interface { - Flatten() string + Name() string + Inline(args ...string) string + ArgNum() int } diff --git a/plab/flatten/function.go b/plab/flatten/function.go index 2bc80526d9fe9155ae107812052e7247190efbb5..e04e12010a84c92ac29a62988894d6995ee96602 100644 --- a/plab/flatten/function.go +++ b/plab/flatten/function.go @@ -2,8 +2,8 @@ package flatten import ( "bytes" - "errors" "fmt" + "git.sch.bme.hu/insert-epic-projlab-team-name-here/tooling/plab/helpers" "io/ioutil" "regexp" "strconv" @@ -11,15 +11,25 @@ import ( ) type FunctionImplementation struct { - Name string - Body string - ArgNum int + flattenable + name string + body string + argNum int +} + +func (f *FunctionImplementation) Name() string { + return f.name +} + +func (f *FunctionImplementation) ArgNum() int { + return f.argNum } func InlineAllFuncs(str string) (string, error) { for _, f := range funcs { var soFar bytes.Buffer - tmpRegexp, e := regexp.Compile(fmt.Sprintf(`\\%s`, f.Name)) + rx := helpers.Escape(f.Name()) + "{" + tmpRegexp, e := regexp.Compile(rx) if e != nil { return "", e } @@ -29,44 +39,65 @@ func InlineAllFuncs(str string) (string, error) { nameStart := i[0] argsStart := i[1] - name := str[nameStart:argsStart] - var fi *FunctionImplementation = nil - for fidx, f := range funcs { - if f.Name == name { - fi = &funcs[fidx] - } - } - if fi == nil { - continue - } - soFar.WriteString(str[prevStop:nameStart]) + prevStop = nameStart args := make([]string, 0) - for i := 0; i < fi.ArgNum; i++ { + argStop := argsStart + for i := 0; i < f.ArgNum(); i++ { depth := 0 var arg string - for + for i, c := range str[argStop:] { + switch c { + case '{': + depth++ + case '}': + depth-- + default: + arg += string(c) + } + if depth < 0 { + argStop += i + break + } + } + args = append(args, arg) + argStop++ } + + inlined := f.Inline(args...) + soFar.WriteString("\n") + soFar.WriteString(inlined) + soFar.WriteString("\n") + prevStop = argStop } + soFar.WriteString(str[prevStop:]) + str = soFar.String() } - return str + return str, nil } func (f *FunctionImplementation) Inline(args ...string) string { const canary = "🙂🙃🙂" str := "{" - str = f.Body + str += f.body str = strings.ReplaceAll(str, `\#`, canary) for i, a := range args { - str = strings.ReplaceAll(str, fmt.Sprintf("#%d", i), a) + str = strings.ReplaceAll(str, fmt.Sprintf("#%d", i+1), a) } str = strings.ReplaceAll(str, canary, `\#`) str += "}" + var e error + str, e = InlineAllFuncs(str) + if e != nil { + panic(e) + } return str } -var funcs = make([]FunctionImplementation, 0) +var funcs = []flattenable{ + &Input, +} var cmdRegex = regexp.MustCompile(`\\newcommand{`) @@ -82,10 +113,10 @@ func ParseFile(filename string) error { for _, i := range idx { nameStart := i[1] - nameStop := strings.Index(str[nameStart:], "}")+nameStart + nameStop := strings.Index(str[nameStart:], "}") + nameStart name := str[nameStart:nameStop] - bodystart := strings.Index(str[nameStop:], "{")+nameStop+1 + bodystart := strings.Index(str[nameStop:], "{") + nameStop + 1 var depth = 0 var bodyend = 0 for i, r := range str[bodystart:] { @@ -121,14 +152,13 @@ func ParseFile(filename string) error { } fi := FunctionImplementation{ - Name: name, - Body: body, - ArgNum: argNum, + name: name, + body: body, + argNum: argNum, } - funcs = append(funcs, fi) + funcs = append(funcs, &fi) } return nil } - diff --git a/plab/flatten/input.go b/plab/flatten/input.go new file mode 100644 index 0000000000000000000000000000000000000000..e9032221cc3f773d1adc3e34c5ff502b840c5223 --- /dev/null +++ b/plab/flatten/input.go @@ -0,0 +1,55 @@ +package flatten + +import ( + "bytes" + "fmt" + "git.sch.bme.hu/insert-epic-projlab-team-name-here/tooling/plab/helpers" + "io" + "io/ioutil" + "os" + "os/exec" +) + +type input struct { + flattenable +} + +func (i *input) Inline(args ...string) string { + arg := args[0] + + if arg[0] == '|' { + cmd := exec.Command("sh", "-c", helpers.Unescape(arg[1:])) + out, e := cmd.Output() + if e != nil { + _, _ = fmt.Fprint(os.Stderr, "error running command:", helpers.Unescape(arg[1:]), "\n") + var stde bytes.Buffer + rd, er := cmd.StderrPipe() + if er == nil { + _, _ = io.Copy(&stde, rd) + _, _ = fmt.Fprint(os.Stderr, stde.String(), "\n") + } + panic(e) + } + return string(out) + } else { + by, e := ioutil.ReadFile(arg) + if e != nil { + panic(e) + } + in, e := InlineAllFuncs(string(by)) + if e != nil { + panic(e) + } + return in + } +} + +func (i *input) Name() string { + return "\\input" +} + +func (i *input) ArgNum() int { + return 1 +} + +var Input = input{} diff --git a/plab/helpers/unescape.go b/plab/helpers/unescape.go index 0e8fc623780464c54fcd1596f322515d240c0e8c..b4f3ff753fcd51495e68c85d7b510d6a791614f4 100644 --- a/plab/helpers/unescape.go +++ b/plab/helpers/unescape.go @@ -7,3 +7,9 @@ func Unescape(s string) string { _ = json.Unmarshal([]byte(s), &ret) return ret } + +func Escape(s string) string { + ret, _ := json.Marshal(s) + ret = ret[1 : len(ret)-1] + return string(ret) +}