summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoop Kiefte <ikojba@gmail.com>2021-10-15 00:11:12 +0100
committerJoop Kiefte <ikojba@gmail.com>2021-10-15 00:11:12 +0100
commit3509ac11c07477c86c67aedfed31ed22a18c5022 (patch)
tree63321074fbf189ac093d2015c5765ff5148e7db0
parent7bf1944b6d142e11886b685da3cb235571264310 (diff)
Correct paths
-rw-r--r--fountain/example.fountain20
-rw-r--r--fountain/parse.go202
-rw-r--r--fountain/write.go65
-rw-r--r--go.mod2
-rw-r--r--lex/type.go2
-rw-r--r--main.go94
-rw-r--r--pdf/create.go12
-rw-r--r--readme.md18
-rw-r--r--rules/rules.go60
9 files changed, 29 insertions, 446 deletions
diff --git a/fountain/example.fountain b/fountain/example.fountain
deleted file mode 100644
index 14ec4f8..0000000
--- a/fountain/example.fountain
+++ /dev/null
@@ -1,20 +0,0 @@
-INT. HOUSE - DAY
-
-MARY
-I can't believe how easy it is to write in Fountain.
-
-TOM
-(typing)
-Look! I just made a parenthetical!
-
-SOMETHING HAPPENS!
-
-(what? I don't know...)
-
-EXT. GARDEN
-
-TOM
-What am I doing here now?
-To be honest, I have absolutely no idea!
-
-And that means really no idea!
diff --git a/fountain/parse.go b/fountain/parse.go
deleted file mode 100644
index 161a611..0000000
--- a/fountain/parse.go
+++ /dev/null
@@ -1,202 +0,0 @@
-// Fountain is a Markdown-like language for screenplays and the main inspiration for this tool.
-// Read more at fountain.io
-package fountain
-
-import (
- "bufio"
- "github.com/lapingvino/lexington/lex"
- "io"
- "strings"
-)
-
-// Scene contains all the prefixes the scene detection looks for.
-// This can be changed with the toml configuration in the rules package.
-var Scene = []string{"INT", "EXT", "EST", "INT./EXT", "INT/EXT", "EXT/INT", "EXT./INT", "I/E"}
-
-func last(out *lex.Screenplay, i int) *lex.Line {
- if len(*out) >= i {
- return &(*out)[len(*out)-i]
- } else {
- line := lex.Line{Type: "empty"}
- return &line
- }
-}
-
-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
- }
- }
- if strings.HasPrefix(row, ".") && !strings.HasPrefix(row, "..") {
- row = row[1:]
- scene = true
- }
- return scene, "scene", row
-}
-
-func CheckCrow(row string) (bool, string, string) {
- var crow bool
- var el string
- row = strings.ToUpper(row)
- if strings.HasPrefix(row, ">") || strings.HasSuffix(row, " TO:") {
- crow = true
- el = "trans"
- }
- if strings.HasPrefix(row, ">") && strings.HasSuffix(row, "<") {
- el = "center"
- }
- return crow, el, strings.Trim(row, ">< ")
-}
-
-func CheckEqual(row string) (bool, string, string) {
- var equal bool
- var el string
- if strings.HasPrefix(row, "=") {
- equal = true
- el = "synopse"
- }
- if len(row) >= 3 && strings.Trim(row, "=") == "" {
- el = "newpage"
- }
- return equal, el, strings.TrimLeft(row, "= ")
-}
-
-func CheckSection(row string) (bool, string, string) {
- var section bool
- if strings.HasPrefix(row, "#") {
- section = true
- }
- return section, "section", row
-}
-
-func CheckForce(row string) (bool, string, string) {
- var force = true
- var ftype string
- if len(row) < 1 {
- return false, "", ""
- }
- switch row[0] {
- case '@':
- ftype = "speaker"
- case '~':
- ftype = "lyrics"
- case '!':
- ftype = "action"
- default:
- force = false
- }
- if force {
- row = row[1:]
- }
- return force, ftype, 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.
-func Parse(scenes []string, file io.Reader) (out lex.Screenplay) {
- Scene = scenes
- var err error
- var titlepage, dialog bool = true, false
- var s, titletag string
- var toParse []string
- 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
- for _, row := range toParse {
- if titlepage && !strings.Contains(toParse[0], ":") {
- out = append(out, lex.Line{Type: "titlepage"})
- out = append(out, lex.Line{Type: "Title", Contents: "Untitled"})
- out = append(out, lex.Line{Type: "newpage"})
- titlepage = false
- }
- row = strings.TrimRight(row, "\n\r")
- action := "action"
- if row == "" {
- action = "empty"
- if titlepage {
- titlepage = false
- out = append(out, lex.Line{Type: "newpage"})
- continue
- }
- }
- if last(&out, 1).Type != "action" {
- last(&out, 1).Contents = strings.TrimSpace(last(&out, 1).Contents)
- }
-
- // Backtracking to check for dialog sequence
- if dialog {
- if row == "" {
- dialog = false
- action = "empty"
- if last(&out, 1).Type == "speaker" {
- last(&out, 1).Type = "action"
- }
- } else {
- if row[0] == '(' && row[len(row)-1] == ')' {
- action = "paren"
- } else {
- action = "dialog"
- }
- }
- }
- charcheck := strings.Split(row, "(")
- if charcheck[0] == strings.ToUpper(charcheck[0]) && action == "action" {
- action = "speaker"
- dialog = true
- }
-
- checkfuncs := []func(string) (bool, string, string){
- CheckScene, // should actually check for empty lines, but doing that creates more problems than it solves
- CheckCrow,
- CheckEqual,
- CheckSection,
- CheckForce,
- }
- for _, checkfunc := range checkfuncs {
- check, element, contents := checkfunc(row)
- if check {
- action = element
- row = contents
- if action == "speaker" {
- dialog = true
- }
- break
- }
- }
-
- if titlepage {
- if titletag == "" {
- out = append(out, lex.Line{Type: "titlepage"})
- }
- split := strings.SplitN(row, ":", 2)
- if len(split) == 2 && !strings.HasPrefix(row, " ") {
- action = split[0]
- switch strings.ToLower(action) {
- case "title", "credit", "author", "authors":
- titletag = "title"
- default:
- if titletag == "title" {
- out = append(out, lex.Line{Type: "metasection"})
- }
- titletag = action
- }
- row = strings.TrimSpace(split[1])
- if row == "" {
- continue
- }
- } else {
- action = titletag
- row = strings.TrimSpace(row)
- }
- }
- out = append(out, lex.Line{action, row})
- }
- return out
-}
diff --git a/fountain/write.go b/fountain/write.go
deleted file mode 100644
index 25eb41b..0000000
--- a/fountain/write.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package fountain
-
-import (
- "github.com/lapingvino/lexington/lex"
- "io"
- "fmt"
- "strings"
-)
-
-func Write(f io.Writer, scene []string, screenplay lex.Screenplay) {
- var titlepage = "start"
- for _, line := range screenplay {
- element := line.Type
- if titlepage == "start" && line.Type != "titlepage" {
- titlepage = ""
- }
- if titlepage != "" {
- element = titlepage
- }
- switch element {
- case "start":
- titlepage = "titlepage"
- case "titlepage":
- if line.Type == "metasection" {
- continue
- }
- if line.Type == "newpage" {
- fmt.Fprintln(f, "")
- titlepage = ""
- continue
- }
- fmt.Fprintf(f, "%s: %s\n", line.Type, line.Contents)
- case "newpage":
- fmt.Fprintln(f, "===")
- case "empty":
- fmt.Fprintln(f, "")
- case "speaker":
- if line.Contents != strings.ToUpper(line.Contents) {
- fmt.Fprint(f, "@")
- }
- fmt.Fprintln(f, line.Contents)
- case "scene":
- var supported bool
- for _, prefix := range scene {
- if strings.HasPrefix(line.Contents, prefix+" ") ||
- strings.HasPrefix(line.Contents, prefix+".") {
- supported = true
- }
- }
- if !supported {
- fmt.Fprint(f, ".")
- }
- fmt.Fprintln(f, line.Contents)
- case "lyrics":
- fmt.Fprintf(f, "~%s\n", line.Contents)
- case "action":
- if line.Contents == strings.ToUpper(line.Contents) {
- fmt.Fprint(f, "!")
- }
- fmt.Fprintln(f, line.Contents)
- default:
- fmt.Fprintln(f, line.Contents)
- }
- }
-}
diff --git a/go.mod b/go.mod
index 10d03e1..616ca7b 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module github.com/lapingvino/lexington
+module github.com/lapingvino/printdraftfast
require (
github.com/BurntSushi/toml v0.3.1
diff --git a/lex/type.go b/lex/type.go
index a906ac2..b4aae0f 100644
--- a/lex/type.go
+++ b/lex/type.go
@@ -1,7 +1,7 @@
// The lex format is basically a parse tree for screenplays, which enables quick debugging.
package lex
-type Screenplay []Line
+type Document []Line
type Line struct {
Type string
diff --git a/main.go b/main.go
index 009cb76..a604e06 100644
--- a/main.go
+++ b/main.go
@@ -5,10 +5,8 @@
package main
import (
- "github.com/lapingvino/lexington/fountain"
- "github.com/lapingvino/lexington/lex"
- "github.com/lapingvino/lexington/pdf"
- "github.com/lapingvino/lexington/rules"
+ "git.kiefte.eu/lapingvino/printdraftfast/pdf"
+ "git.kiefte.eu/lapingvino/printdraftfast/rules"
"flag"
"io"
@@ -16,7 +14,6 @@ import (
"os"
"strings"
"time"
-
)
func main() {
@@ -24,15 +21,11 @@ func main() {
defer func() {
log.Printf("Conversion took %v", time.Since(start))
}()
- config := flag.String("config", "lexington.toml", "Configuration file to use.")
+ config := flag.String("config", "printdraftfast.toml", "Configuration file to use.")
dump := flag.Bool("dumpconfig", false, "Dump the default configuration to the location of --config to be adapted manually.")
- scenein := flag.String("scenein", "", "Configuration to use for scene header detection on input.")
- sceneout := flag.String("sceneout", "", "Configuration to use for scene header detection on output.")
elements := flag.String("e", "default", "Element settings from settings file to use.")
input := flag.String("i", "-", "Input from provided filename. - means standard input.")
- output := flag.String("o", "-", "Output to provided filename. - means standard output.")
- from := flag.String("from", "", "Input file type. Choose from fountain, lex [, fdx]. Formats between angle brackets are planned to be supported, but are not supported by this binary.")
- to := flag.String("to", "", "Output file type. Choose from pdf (built-in, doesn't support inline markup), lex (helpful for troubleshooting and correcting fountain parsing), fountain, [html, epub*, mobi*, docx*, odt*, fdx]. Formats marked with a little star need an additional external tool to work. Formats between angle brackets are planned to be supported, but are not supported by this binary.")
+ output := flag.String("o", "-", "Output to provided filename.")
help := flag.Bool("help", false, "Show this help message")
flag.Parse()
@@ -50,40 +43,8 @@ func main() {
return
}
- ins := strings.Split(*input, ".")
- if len(ins) > 1 && *from == "" {
- *from = ins[len(ins)-1]
- }
- if len(ins) > 2 && *scenein == "" {
- *scenein = ins[len(ins)-2]
- }
-
- outs := strings.Split(*output, ".")
- if len(outs) > 1 && *to == "" {
- *to = outs[len(outs)-1]
- }
- if len(outs) > 2 && *sceneout == "" {
- *sceneout = outs[len(outs)-2]
- }
-
- if *from == "" {
- *from = "fountain"
- }
- if *to == "" && *output == "-" {
- *to = "lex"
- }
- if *scenein == "" {
- *scenein = "en"
- }
- if *sceneout == "" {
- *sceneout = "en"
- }
-
- log.Printf("Scenein: %s ; Sceneout: %s ;\n", *scenein, *sceneout)
-
var infile io.Reader
var outfile io.Writer
- var i lex.Screenplay
conf := rules.GetConf(*config)
@@ -99,47 +60,14 @@ func main() {
}
}
- if *output == "-" {
- outfile = os.Stdout
- log.Println("Writing to Stdout")
- } else {
- if *output == "" && len(ins) > 0 && ins[0] != "" {
- *output = ins[0] + "." + *to
- }
- var err error
- outfile, err = os.Create(*output)
- if err != nil {
- log.Println("Error creating output file: ", err)
- return
- }
- }
+ // TODO: Parser goes here
- log.Println("Input type is ", *from)
- switch *from {
- case "lex":
- i = lex.Parse(infile)
- case "fountain":
- i = fountain.Parse(conf.Scenes[*scenein], infile)
- default:
- log.Printf("%s is not a valid input type", *from)
+ if *output == "-" && len(ins) > 0 && ins[0] != "" {
+ *output = ins[0] + ".pdf"
}
-
- log.Println("Output type is ", *to)
- switch *to {
- case "pdf":
- if *output == "-" && len(ins) > 0 && ins[0] != "" {
- *output = ins[0] + ".pdf"
- }
- if *output == "-" {
- log.Println("Cannot write PDF to standard output")
- return
- }
- pdf.Create(*output, conf.Elements[*elements], i)
- case "lex":
- lex.Write(i, outfile)
- case "fountain":
- fountain.Write(outfile, conf.Scenes[*sceneout], i)
- default:
- log.Printf("%s is not a valid output type", *to)
+ if *output == "-" {
+ log.Println("Cannot write PDF to standard output")
+ return
}
+ pdf.Create(*output, conf.Elements[*elements], i)
}
diff --git a/pdf/create.go b/pdf/create.go
index 3a65984..943c5ce 100644
--- a/pdf/create.go
+++ b/pdf/create.go
@@ -1,10 +1,10 @@
-// The PDF package of Lexington creates a Screenplay PDF out of the Lex screenplay parsetree. This can be generated with the several other packages, e.g. the fountain package that parses fountain to lex in preparation.
+// The PDF package of PrintDraftFast creates a PDF out of the Lex markdown parsetree.
package pdf
import (
- "github.com/lapingvino/lexington/lex"
- "github.com/lapingvino/lexington/rules"
- "github.com/lapingvino/lexington/font"
+ "git.kiefte.eu/lapingvino/printdraftfast/lex"
+ "git.kiefte.eu/lapingvino/printdraftfast/rules"
+ "git.kiefte.eu/lapingvino/printdraftfast/font"
"strconv"
"strings"
@@ -15,7 +15,7 @@ import (
type Tree struct {
PDF *gofpdf.Fpdf
Rules rules.Set
- F lex.Screenplay
+ F lex.Document
HTML gofpdf.HTMLBasicType
}
@@ -34,7 +34,7 @@ func (t Tree) Render() {
t.PDF.SetHeaderFuncMode(func() {
t.PDF.SetFont("CourierPrime", "", 12)
t.PDF.SetXY(-1, 0.5)
- t.PDF.Cell(0, 0, strconv.Itoa(t.PDF.PageNo()-1)+".")
+ t.PDF.Cell(0, 0, strconv.Itoa(t.PDF.PageNo())+".")
}, true)
continue
case "titlepage":
diff --git a/readme.md b/readme.md
index 2ade31a..3b4b9e6 100644
--- a/readme.md
+++ b/readme.md
@@ -1,16 +1,4 @@
-Lexington commandline tool for screenwriters
-============================================
+Print Draft Fast
+================
-Lexington helps you convert between Final Draft, Fountain and its own lex file formats, and output to PDF, HTML and ebook formats.
-
-At the moment the Fountain parser should be pretty decent, although still lacking features like simultaneous dialog, and inline markup is not yet supported and might never be. Also the PDF output doesn't do anything to keep pieces from your screenplay together. Feel free to contribute and help me out in knowing how best to handle this!
-
-To run the tool, make sure to have Go installed first and then run
-
-`go get github.com/lapingvino/lexington`
-
-to install Lexington to your go/bin directory. If this directory is in your execution path, you can then run it like
-
-`lexington -i inputfile.fountain -o outputfile.pdf -to pdf`
-
-For a more complete overview of the command line options, use `lexington -help`.
+Based on my work on [lexington](https://github.com/lapingvino/lexington) and a question on Reddit about having a fast Markdown to PDF conversion, here is my attempt to create a quick and dirty PDF creation tool for Markdown source files.
diff --git a/rules/rules.go b/rules/rules.go
index ee84dbb..4a86820 100644
--- a/rules/rules.go
+++ b/rules/rules.go
@@ -1,4 +1,4 @@
-// The rules package of Lexington provides the tools around configuration of how a screenplay should look. The default should work but can be adjusted for a personal touch..
+// The rules package of PrintDraftFast provides the tools around configuration of how a draft should look. The default should work but can be adjusted for a personal touch..
package rules
type Format struct {
@@ -15,10 +15,10 @@ type Format struct {
type Set map[string]Format
-func (s Set) Get(action string) (f Format) {
- f, ok := s[action]
+func (s Set) Get(style string) (f Format) {
+ f, ok := s[style]
if !ok {
- f = s["action"]
+ f = s["default"]
f.Hide = true
}
if f.Font == "" {
@@ -34,62 +34,16 @@ func (s Set) Get(action string) (f Format) {
}
var Default = Set{
- "action": {
+ "default": {
Left: 1.5,
Right: 1,
},
- "speaker": {
- Left: 3.7,
- Right: 1.5,
- },
- "dialog": {
- Left: 2.5,
- Right: 1.5,
- },
- "scene": {
- Left: 1.5,
- Right: 1,
- Style: "b",
- },
- "paren": {
- Left: 3.1,
- Right: 1.5,
- },
- "trans": {
- Left: 1.5,
- Right: 1,
- Align: "R",
- },
- "note": {
- Left: 1.5,
- Right: 1,
- },
- "allcaps": {
- Left: 1.5,
- Right: 1,
- },
- "empty": {
- Left: 1.5,
- Right: 1,
- },
- "title": {
- Left: 1.5,
- Right: 1,
- Align: "C",
- },
- "meta": {
- Left: 1.5,
- Right: 1,
+ "h1": {
+ Size: 2,
},
"center": {
Left: 1.5,
Right: 1,
Align: "C",
},
- "lyrics": {
- Left: 2,
- Right: 2,
- Style: "i",
- Font: "Helvetica",
- },
}