diff options
-rw-r--r-- | fountain/parse.go | 100 | ||||
-rw-r--r-- | lex/parse.go | 8 | ||||
-rw-r--r-- | lex/type.go | 5 | ||||
-rw-r--r-- | main.go | 5 | ||||
-rw-r--r-- | pdf/create.go | 8 | ||||
-rw-r--r-- | rules/rules.go | 44 |
6 files changed, 117 insertions, 53 deletions
diff --git a/fountain/parse.go b/fountain/parse.go index a3e1747..c0fff65 100644 --- a/fountain/parse.go +++ b/fountain/parse.go @@ -1,46 +1,112 @@ +// Fountain is a Markdown-like language for screenplays and the main inspiration for this tool. +// Read more at fountain.io package fountain import ( - "github.com/lapingvino/lexington/lex" - "strings" "bufio" + "github.com/lapingvino/lexington/lex" "io" + "strings" ) +var Scene = []string{"INT", "EXT", "EST", "INT./EXT", "INT/EXT", "I/E"} + +func CheckScene(row string) (bool, string, string) { + var scene bool + row = strings.ToUpper(row) + for _, prefix := range Scene { + if strings.HasPrefix(row, prefix+" ") || + strings.HasPrefix(row, prefix+".") { + scene = true + } + } + return scene, "scene", row +} + +func CheckTransition(row string) (bool, string, string) { + var trans bool + row = strings.ToUpper(row) + if strings.HasPrefix(row, ">") || strings.HasSuffix(row, " TO:") { + trans = true + } + return trans, "trans", strings.Trim(row, ">< ") +} + +func CheckSynopse(row string) (bool, string, string) { + var synopse bool + if strings.HasPrefix(row, "=") { + synopse = true + } + return synopse, "synopse", strings.TrimLeft(row, "= ") +} + +func CheckSection(row string) (bool, string, string) { + var section bool + if strings.HasPrefix(row, "#") { + section = true + } + return section, "section", row +} + +// This is a Fountain parser, trying to be as close as possible to the description +// found at https://fountain.io/syntax but it can be incomplete. +// Over time more and more parts should be configurable here, e.g. INT/EXT translatable to other languages. func Parse(file io.Reader) (out lex.Screenplay) { var err error var s string - var toParse []string + var toParse []string // Fill with two to avoid out of bounds when backtracking f := bufio.NewReader(file) for err == nil { s, err = f.ReadString('\n') toParse = append(toParse, s) } + toParse = append(toParse, "") // Trigger the backtracking also for the last line + out = make(lex.Screenplay, 2, len(toParse)) for i, row := range toParse { - row = strings.TrimSpace(row) + i += 2 + row = strings.TrimRight(row, "\n\r") action := "action" if row == strings.ToUpper(row) { action = "allcaps" } if row == "" { action = "empty" - continue + + // Backtracking for elements that need a following empty line + checkfuncs := []func(string) (bool, string, string){ + CheckScene, + CheckTransition, + CheckSynopse, + CheckSection, + } + for _, checkfunc := range checkfuncs { + check, element, contents := checkfunc(out[i-1].Contents) + if check && out[i-2].Contents == "" { + out[i-1].Type = element + out[i-1].Contents = contents + break + } + } } - if i <= 0 { - continue + if out[i-1].Type != "action" { + out[i-1].Contents = strings.TrimSpace(out[i-1].Contents) } - switch out[i-1].Type { - case "allcaps": - out[i-1].Type = "speaker" - if row[0] == '(' && row[len(row)-1] == ')' { - action = "paren" - } else { - action = "dialog" + + // Backtracking to check for dialog sequence + if row != "" { + switch out[i-1].Type { + case "allcaps": + out[i-1].Type = "speaker" + fallthrough + case "paren", "dialog": + if row[0] == '(' && row[len(row)-1] == ')' { + action = "paren" + } else { + action = "dialog" + } } - case "paren", "dialog": - action = "dialog" } out = append(out, lex.Line{action, row}) } - return out + return out[2:] // Remove the safety empty rows } diff --git a/lex/parse.go b/lex/parse.go index e105a22..00a6cbd 100644 --- a/lex/parse.go +++ b/lex/parse.go @@ -1,8 +1,8 @@ package lex import ( - "io" "bufio" + "io" "strings" ) @@ -18,9 +18,9 @@ func Parse(file io.Reader) (out Screenplay) { var line Line s, err = f.ReadString('\n') split := strings.SplitN(s, ":", 2) - switch len(split){ - case 0,1: - line.Type = strings.Trim(s,": \n\r") + switch len(split) { + case 0, 1: + line.Type = strings.Trim(s, ": \n\r") case 2: line.Type = split[0] line.Contents = strings.TrimSpace(split[1]) diff --git a/lex/type.go b/lex/type.go index eec2f3e..a906ac2 100644 --- a/lex/type.go +++ b/lex/type.go @@ -3,8 +3,7 @@ package lex type Screenplay []Line -type Line struct{ - Type string +type Line struct { + Type string Contents string } - @@ -3,15 +3,15 @@ package main import ( - "github.com/lapingvino/lexington/lex" "github.com/lapingvino/lexington/fountain" + "github.com/lapingvino/lexington/lex" "github.com/lapingvino/lexington/pdf" "github.com/lapingvino/lexington/rules" "flag" + "io" "log" "os" - "io" ) func main() { @@ -55,7 +55,6 @@ func main() { } } - log.Println("Input type is ", *from) switch *from { case "lex": diff --git a/pdf/create.go b/pdf/create.go index 05cc871..52c3122 100644 --- a/pdf/create.go +++ b/pdf/create.go @@ -10,9 +10,9 @@ import ( var tr func(string) string type Tree struct { - PDF *gofpdf.Fpdf + PDF *gofpdf.Fpdf Rules rules.Set - F lex.Screenplay + F lex.Screenplay } func (t Tree) pr(a string, text string) { @@ -50,9 +50,9 @@ func Create(file string, format rules.Set, contents lex.Screenplay) { pdf.SetMargins(1, 1, 1) pdf.SetXY(1, 1) f := Tree{ - PDF: pdf, + PDF: pdf, Rules: format, - F: contents, + F: contents, } f.Render() err := pdf.OutputFileAndClose(file) diff --git a/rules/rules.go b/rules/rules.go index 030fcb0..775142f 100644 --- a/rules/rules.go +++ b/rules/rules.go @@ -1,12 +1,12 @@ package rules -type Format struct{ +type Format struct { Width float64 - Left float64 - Font string + Left float64 + Font string Style string - Size float64 - Hide bool + Size float64 + Hide bool Align string } @@ -31,51 +31,51 @@ func (s Set) Get(action string) (f Format) { } var Default = Set{ - "action": { - Left: 1.5, + "action": { + Left: 1.5, Width: 6, }, "speaker": { - Left: 4.2, + Left: 4.2, Width: 3.3, }, - "dialog": { - Left: 2.9, + "dialog": { + Left: 2.9, Width: 3.3, }, - "scene": { - Left: 1.5, + "scene": { + Left: 1.5, Width: 6, Style: "b", }, - "paren": { - Left: 3.6, + "paren": { + Left: 3.6, Width: 4, }, - "trans": { - Left: 1.5, + "trans": { + Left: 1.5, Width: 6, Align: "R", }, - "note": { - Left: 1.5, + "note": { + Left: 1.5, Width: 6, }, "allcaps": { - Left: 1.5, + Left: 1.5, Width: 6, }, "empty": { - Left: 1.5, + Left: 1.5, Width: 6, }, "title": { - Left: 1.5, + Left: 1.5, Width: 6, Align: "C", }, "meta": { - Left: 1.5, + Left: 1.5, Width: 3, }, } |