From 9a1ae642f96a0fc42917c704d3417a323d3d3840 Mon Sep 17 00:00:00 2001 From: Carl Kittelberger Date: Mon, 20 Feb 2017 12:34:02 +0100 Subject: [PATCH] Use blackfriday LaTeX export for all values inserted in LaTeX. --- export/latex/localization/de-de.all.json | 4 +- export/latex/localization/en-us.all.json | 4 +- export/latex/localization_assets.go | 8 +-- export/latex/stringutil/converter.go | 2 +- .../latex/stringutil/converter_simpleregex.go | 2 +- export/latex/stringutil/converter_string.go | 2 +- export/latex/stringutil/escape.go | 28 ++++------ export/latex/stringutil/latexize.go | 51 +++++++++++++++++++ export/latex/template.go | 16 +++--- internal/util/documentless_renderer.go | 29 +++++++++++ 10 files changed, 110 insertions(+), 36 deletions(-) create mode 100644 export/latex/stringutil/latexize.go create mode 100644 internal/util/documentless_renderer.go diff --git a/export/latex/localization/de-de.all.json b/export/latex/localization/de-de.all.json index 48c9692..0db3927 100644 --- a/export/latex/localization/de-de.all.json +++ b/export/latex/localization/de-de.all.json @@ -40,8 +40,8 @@ "translation": "Berufsschule" }, { - "id": "proof_of_education", - "translation": "Ausbildungsnachweis Nr. {{.Count}}" + "id": "proof_of_education_prefix", + "translation": "Ausbildungsnachweis Nr." }, { "id": "trainee", diff --git a/export/latex/localization/en-us.all.json b/export/latex/localization/en-us.all.json index 408af71..8b9f9ba 100644 --- a/export/latex/localization/en-us.all.json +++ b/export/latex/localization/en-us.all.json @@ -40,8 +40,8 @@ "translation": "Professional school" }, { - "id": "proof_of_education", - "translation": "Proof of Education No. {{.Count}}" + "id": "proof_of_education_prefix", + "translation": "Proof of Education No." }, { "id": "trainee", diff --git a/export/latex/localization_assets.go b/export/latex/localization_assets.go index d1843fd..a7c9068 100644 --- a/export/latex/localization_assets.go +++ b/export/latex/localization_assets.go @@ -71,7 +71,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _localizationDeDeAllJson = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x84\xd2\xc1\x6a\xdb\x40\x10\x06\xe0\x73\xfc\x14\x83\xce\xc1\xb9\xf7\x96\xf6\xd0\x42\x21\xa7\xb6\x81\x96\x22\xd6\xab\x5f\xd2\x90\xf5\xac\x98\x99\x8d\x21\xc6\x6f\xd3\x37\xe9\x8b\x15\xc9\x31\xb4\x45\xeb\x9c\x77\xff\x6f\xa5\x99\xff\xc7\x86\xe8\xb8\x21\x22\x6a\xb8\x6b\xde\x51\x13\x43\x82\x74\x41\xdb\x03\xf0\xd4\xdc\x9e\x8f\x5c\x83\x58\x0a\xce\x59\xe6\x3b\x9f\x97\x3b\xd0\x43\x8e\x23\x9a\x0d\xd1\xe9\xf6\x2a\xd3\xda\x98\xd5\x6b\xd8\xe3\xba\xd0\x61\x0a\xea\x7b\x48\x2d\x78\xbf\x73\x70\x2a\x32\xac\xe7\x59\xcc\xb5\x44\xcf\x5a\xcb\x17\xdb\x71\xea\xa0\x77\x2c\xeb\x44\xc2\x10\x52\xab\x98\x14\x06\xf1\xe0\xfc\x8c\x0a\xf6\x11\x06\x7f\x49\x1c\x47\x28\x7d\x83\xba\xc2\xa1\xeb\xac\x84\x7d\x8d\x79\x98\x8f\xd6\x43\xb9\xb5\x38\xe6\x9c\xda\x09\xca\xb9\xb3\xd6\x47\xb6\x6b\x5b\xfa\x14\x9c\x58\xa8\x63\x18\x94\x1e\xe7\x5d\x91\xe4\x38\x92\x70\x1c\x9d\xcc\x83\xfb\x80\xbe\x48\x07\xd9\xae\x3f\x9a\x27\xe8\xe2\x85\xd4\x86\xe8\xfc\xcc\xce\xb0\xca\x7b\xef\xe1\xca\xd8\x2d\x33\xa0\x2f\xbf\x7f\x39\x0f\x4f\x60\x47\x65\xb8\x7f\xdb\x97\x5d\xcd\xd2\xdb\xb8\xd2\x57\x71\xa8\xce\xbf\xb1\x6e\x4f\x9a\x7b\x98\x9d\xf1\xf3\xd8\xaa\xae\x96\xde\x2c\x8e\x25\x55\x06\x3f\x69\xce\x7d\x9b\xfb\x16\x5d\x89\xe1\xca\x27\xbe\xf6\xa9\xc8\x60\x12\xe2\x78\x00\x1b\x3d\xe8\x96\x8e\xc7\xed\x87\x5c\xc4\x4f\xa7\xf5\x07\x5c\x03\x0b\x6a\x8d\xb8\x2f\xf6\x52\x96\x9e\x4a\x87\xbb\x7f\x1b\x75\x73\x11\x78\x8f\xd7\x5a\x2c\xca\xcd\xff\xc8\x77\xb0\x6b\x28\xfb\x25\xbd\xf9\xf9\x27\x00\x00\xff\xff\x2b\xa3\xd3\x89\xf5\x03\x00\x00") +var _localizationDeDeAllJson = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x84\xd2\xc1\x8a\x14\x31\x10\x06\xe0\xf3\xce\x53\x14\x73\x5e\xdc\xbb\xb7\xf5\xa2\x20\xec\x49\x5d\x50\x24\x64\xd2\x7f\x77\x8a\xcd\x54\x9a\xaa\xca\x8e\xac\xf8\x36\xbe\x89\x2f\x26\xdd\xe3\x82\x4a\x67\xf6\x9c\xfc\x5f\x48\xd5\xff\x65\x47\xf4\x7d\x47\x44\xb4\xe7\x61\xff\x9a\xf6\x29\x16\xc8\x10\x35\x9c\x80\x87\xfd\xf5\xf9\xc8\x35\x8a\x95\xe8\x5c\x65\xb9\xf3\x7e\xbd\x03\x3d\xd5\x94\xb1\xdf\x11\xfd\xb8\xbe\xc8\x04\xcb\x55\xbd\x87\xdd\x6f\x0b\x03\xe6\xa8\x7e\x84\xf4\x82\xb7\x07\x07\x97\x26\xd3\x76\x9e\xc5\x5c\x5b\xf2\xaa\xbd\x7c\xb3\x03\x97\x01\x7a\xc3\xb2\x4d\x14\x4c\xb1\x04\xc5\xac\x30\x88\x47\xe7\x47\x74\xb0\xb7\x30\xf8\x53\xe1\x94\xa1\xf4\x09\xea\x0a\x87\x6e\xb3\x12\x8f\x3d\xe6\x6e\x39\xda\x0e\xd5\x60\x29\xd7\x5a\xc2\x0c\xe5\x3a\x58\xf0\xcc\x76\x69\x4b\xef\xa2\x13\x0b\x0d\x0c\x83\xd2\xfd\xb2\x2b\x92\x9a\x32\x09\xa7\xec\x64\x1e\xdd\x27\x8c\x4d\x06\xc8\xab\xed\x47\xeb\x0c\x5d\xbd\x58\x42\x4c\xce\x8f\xec\x0c\xeb\xbc\xf7\x06\xae\x8c\xc3\x3a\x03\xfa\xf0\xeb\xa7\xf3\xf4\x00\x76\x74\x86\xfb\xb7\xfd\xbc\xab\x45\x7a\x19\x57\xfa\x28\x0e\xd5\xe5\x1b\xdb\xf6\xac\x75\x84\xd9\x19\x3f\x8f\xad\xeb\x6a\x1b\xcd\x52\x6e\xa5\x33\xf8\x59\x6b\x1d\x43\x1d\x03\x86\x96\xd6\x5c\x98\x15\x23\x7f\xbb\x5c\xab\x26\x93\x49\x4c\xf9\x04\x36\xba\xd3\xce\x80\x5d\x23\x0b\x7a\x6d\xb8\x6d\xf6\xd4\xd6\x8e\xca\x80\x9b\x7f\xdb\x74\xf5\x2c\xf0\x11\x7f\x2a\xb1\x2a\x57\xff\x23\x9f\xc1\xae\xb1\x1d\xd7\xf4\xee\xeb\xef\x00\x00\x00\xff\xff\x1a\x3c\x3d\x00\xf1\x03\x00\x00") func localizationDeDeAllJsonBytes() ([]byte, error) { return bindataRead( @@ -86,7 +86,7 @@ func localizationDeDeAllJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "localization/de-de.all.json", size: 1013, mode: os.FileMode(436), modTime: time.Unix(1486647823, 0)} + info := bindataFileInfo{name: "localization/de-de.all.json", size: 1009, mode: os.FileMode(436), modTime: time.Unix(1487590241, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -111,7 +111,7 @@ func localizationDeDeUntranslatedJson() (*asset, error) { return a, nil } -var _localizationEnUsAllJson = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x84\x92\xc1\x4a\xc3\x40\x10\x86\xcf\xcd\x53\x0c\x39\x97\x3e\x80\xd7\xea\x41\x90\xda\x83\xe0\x41\x64\x19\x92\x89\x1d\x4c\x76\xc2\xec\xb4\x1e\x4a\xdf\x5d\x92\x6c\x69\xd0\xdd\xf4\x3c\xdf\xf7\xb5\xc9\x9f\x8f\x02\xe0\x5c\x00\x00\x94\x5c\x97\x0f\x50\x56\xd8\x92\xaf\x51\xdd\x0f\xd1\x77\xb9\x9e\x4e\xa6\xe8\x43\x8b\xc6\xe2\x07\x66\x1b\x19\x18\x99\x02\xe0\xb2\x5e\xcc\xb8\x70\x10\xb5\x5c\xec\x3d\x5d\xa8\xa9\x47\xb5\x8e\x7c\x4e\x7c\xbc\x01\xc9\x00\xfb\x60\x7a\xac\x4c\x34\x13\x78\xbe\x01\xc9\x40\x4b\x5f\xd8\x3a\xa5\x5e\x29\x90\x37\x34\x3e\x51\x26\xf5\x32\xa0\xf0\x07\x4d\x46\x3d\x76\xb9\xc8\x6e\x38\xa5\x25\x71\xa1\x3a\x88\xb4\xae\x27\x65\xa9\x83\xb3\x03\x87\xa5\x89\x76\x02\x93\x01\xd1\x80\xc1\x18\x07\xdb\xa4\x7f\x43\x7a\xd2\x51\xc7\xd6\x61\x65\x7c\x62\x63\x0a\x99\xfc\xeb\x0d\x86\x19\x7c\x37\x7c\xdd\x64\xc8\xdc\x2f\xcf\xe9\x64\xba\x57\x69\x28\x84\xa9\x3d\x3d\x6f\x26\xbb\x9f\x91\xf1\xcd\x64\x93\xd2\x38\x69\x1c\xd5\xc7\x0a\x17\xfe\xe8\x7e\x00\x41\x1a\x78\xba\x82\xb0\x93\x0d\x9c\xcf\x9b\xad\x1c\xbd\x5d\x2e\xe9\xbe\x29\xb2\xa7\xdc\x27\xf0\x16\xaf\x73\x75\x75\x35\xb9\xa3\xb8\xff\x68\xaf\xfe\xc9\xdc\x51\x9c\x7b\x0c\x14\x9f\xbf\x01\x00\x00\xff\xff\x24\x12\x73\xee\xde\x03\x00\x00") +var _localizationEnUsAllJson = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x84\x91\xc1\x4a\xc4\x30\x10\x86\xcf\xdb\xa7\x18\x7a\x5e\x7c\x00\xaf\xea\x41\x90\xd5\x83\xe0\x41\x24\x84\x76\xea\x0e\xa6\x99\x30\x99\x5d\x05\xf1\xdd\xa5\x69\x96\x16\x4d\x76\xcf\xf3\x7d\x5f\x69\xfe\xd7\x06\xe0\xbb\x01\x00\x68\xa9\x6f\xaf\xa1\xed\xac\x43\xdf\x5b\x31\x9f\x88\x1f\xed\x76\x3e\xa9\x58\x1f\x9d\x55\x62\x3f\x31\x37\x99\x81\xc4\x34\x00\x3f\xdb\xb3\x19\x13\xf7\x2c\x5a\x8b\xbd\x94\x0b\x3d\x06\x2b\x3a\xa2\xaf\x89\xb7\x0b\x50\x0c\x90\x8f\x2a\x87\x4e\x59\x2a\x81\xfb\x05\x28\x06\x1c\xbe\x5b\x67\x04\x83\x60\x44\xaf\x56\xe9\x88\x95\xd4\xc3\x84\xc2\x1f\xb4\x18\xf5\x76\xac\x45\x76\xd3\xa9\x2c\xb1\x89\xdd\x9e\xd9\x99\x80\x42\xdc\x47\xa3\x7b\x8a\xe7\x26\xda\x31\xcc\x06\x64\x03\x26\x23\x0d\x76\x55\xfe\x06\x07\x94\xa4\x5b\x67\x6c\xa7\x74\x24\x25\x8c\x95\xfc\xe3\x02\xc3\x0a\xbe\x18\x3e\x6d\x32\x65\x2e\x97\xd7\x74\x31\x1d\x84\x07\x8c\x71\x6e\xcf\xff\x5b\xc9\x3e\xad\xc8\xfc\x32\xd5\x24\x0f\x86\x07\x83\xfd\xa1\x4b\xba\x09\x82\x03\x7d\xd5\xc3\x3c\x00\x0f\x70\x77\xe2\x61\xc7\x95\x27\x56\xb1\xe4\xb1\x36\xff\x73\xbe\xae\xd5\xcd\xc9\xa4\x11\xf3\xf6\xc9\xde\xfc\x93\x69\xc4\x3c\x75\x0a\x34\x6f\xbf\x01\x00\x00\xff\xff\x30\x60\x8b\xd1\xda\x03\x00\x00") func localizationEnUsAllJsonBytes() ([]byte, error) { return bindataRead( @@ -126,7 +126,7 @@ func localizationEnUsAllJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "localization/en-us.all.json", size: 990, mode: os.FileMode(436), modTime: time.Unix(1486647790, 0)} + info := bindataFileInfo{name: "localization/en-us.all.json", size: 986, mode: os.FileMode(436), modTime: time.Unix(1487590250, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/export/latex/stringutil/converter.go b/export/latex/stringutil/converter.go index f6085fd..1926449 100644 --- a/export/latex/stringutil/converter.go +++ b/export/latex/stringutil/converter.go @@ -1,5 +1,5 @@ package stringutil -type converter interface { +type Converter interface { Process(text string) string } diff --git a/export/latex/stringutil/converter_simpleregex.go b/export/latex/stringutil/converter_simpleregex.go index ff9d857..14e23ea 100644 --- a/export/latex/stringutil/converter_simpleregex.go +++ b/export/latex/stringutil/converter_simpleregex.go @@ -7,7 +7,7 @@ type simpleRegexConverter struct { replacement string } -func newSimpleRegexConverter(regexStr string, replacementStr string) *simpleRegexConverter { +func NewSimpleRegexConverter(regexStr string, replacementStr string) *simpleRegexConverter { return &simpleRegexConverter{ regex: regexp.MustCompile(regexStr), replacement: replacementStr, diff --git a/export/latex/stringutil/converter_string.go b/export/latex/stringutil/converter_string.go index 4909784..30aa23e 100644 --- a/export/latex/stringutil/converter_string.go +++ b/export/latex/stringutil/converter_string.go @@ -7,7 +7,7 @@ type stringConverter struct { replacement string } -func newStringConverter(old string, replacementStr string) *stringConverter { +func NewStringConverter(old string, replacementStr string) *stringConverter { return &stringConverter{ old: old, replacement: replacementStr, diff --git a/export/latex/stringutil/escape.go b/export/latex/stringutil/escape.go index 6653594..827080b 100644 --- a/export/latex/stringutil/escape.go +++ b/export/latex/stringutil/escape.go @@ -1,26 +1,20 @@ package stringutil -var replacements = []converter{ - newStringConverter("{", "\\{"), - newStringConverter("}", "\\}"), - newStringConverter("\\", "\\textbackslash{}"), +// BackslashEscape modifies a string so any occurrences of given substrings +// are prefixed with a backslash. +func BackslashEscape(s string, substrings ...string) string { + replacements := []Converter{} - newStringConverter("&", "\\&"), - newStringConverter("%", "\\%"), - newStringConverter("$", "\\$"), - newStringConverter("#", "\\#"), - newStringConverter("_", "\\_"), - newStringConverter("~", "\\textasciitilde{}"), - newStringConverter("^", "\\textasciicircum{}"), - newStringConverter("ß", "\\ss{}"), + for _, substring := range substrings { + replacements = append(replacements, NewStringConverter(substring, "\\"+substring)) + } - newSimpleRegexConverter(`"([^"]+)"`, `\enquote{$1}`), - newSimpleRegexConverter("`([^`]+)`", "\\verb`$1`"), + return CustomEscape(s, replacements...) } -// TexEscape modifies a string so it can be safely places in a LaTeX file -// without causing any errors due to special characters. -func TexEscape(s string) string { +// CustomEscape modifies a string according to the given conversion rules in +// the exact given order. +func CustomEscape(s string, replacements ...Converter) string { for _, replacer := range replacements { s = replacer.Process(s) } diff --git a/export/latex/stringutil/latexize.go b/export/latex/stringutil/latexize.go new file mode 100644 index 0000000..70d68f3 --- /dev/null +++ b/export/latex/stringutil/latexize.go @@ -0,0 +1,51 @@ +package stringutil + +import ( + "strings" + + "git.dekart811.net/icedream/workreportmgr/internal/util" + "github.com/russross/blackfriday" +) + +const ( + enabledExtensions = 0 | + blackfriday.EXTENSION_NO_INTRA_EMPHASIS | + blackfriday.EXTENSION_TABLES | + blackfriday.EXTENSION_FENCED_CODE | + blackfriday.EXTENSION_AUTOLINK | + blackfriday.EXTENSION_STRIKETHROUGH | + blackfriday.EXTENSION_SPACE_HEADERS | + blackfriday.EXTENSION_HEADER_IDS | + blackfriday.EXTENSION_BACKSLASH_LINE_BREAK | + blackfriday.EXTENSION_DEFINITION_LISTS +) + +var additionalTexReplacements = []Converter{ + // NewStringConverter("{", "\\{"), + // NewStringConverter("}", "\\}"), + // NewStringConverter("\\", "\\textbackslash{}"), + // + // NewStringConverter("&", "\\&"), + // NewStringConverter("%", "\\%"), + // NewStringConverter("$", "\\$"), + // NewStringConverter("#", "\\#"), + // NewStringConverter("_", "\\_"), + // NewStringConverter("~", "\\textasciitilde{}"), + // NewStringConverter("^", "\\textasciicircum{}"), + // NewStringConverter("ß", "\\ss{}"), + + NewSimpleRegexConverter(`"([^"]+)"`, `\enquote{$1}`), + // NewSimpleRegexConverter("`([^`]+)`", "\\verb`$1`"), +} + +/* +Latexize takes an input text as parsed from the value of any field in a project +file and turns it into LaTeX code. +*/ +func Latexize(input string) string { + renderer := util.DocumentlessRenderer{Renderer: blackfriday.LatexRenderer(0)} + renderedString := string(blackfriday.Markdown([]byte(input), renderer, enabledExtensions)) + renderedString = CustomEscape(renderedString, additionalTexReplacements...) + renderedString = strings.TrimSpace(renderedString) + return renderedString +} diff --git a/export/latex/template.go b/export/latex/template.go index 899d625..02fd259 100644 --- a/export/latex/template.go +++ b/export/latex/template.go @@ -23,10 +23,10 @@ var exportTemplate = template.Must(template. "endofweek": func(date project.Date) project.Date { return project.Date{Time: now.New(date.Time).EndOfWeek()} }, - "escape": stringutil.TexEscape, "add": func(a, b int) int { return a + b }, + "latexize": stringutil.Latexize, }). Delims("<", ">"). Parse(`% !TeX @@ -89,8 +89,8 @@ var exportTemplate = template.Must(template. \setcounter{section}{\wrNumber} \setcounter{subsection}{0} - \section*{} - \addcontentsline{toc}{section}{} + \section*{ \wrNumber} + \addcontentsline{toc}{section}{ \wrNumber} }{ } @@ -119,25 +119,25 @@ var exportTemplate = template.Must(template. \begin{itemize} - \item <. | escape> + \item <. | latexize> \end{itemize} \weeklyreportsection{} - <$week.WorkActivityDetails | escape> + <$week.WorkActivityDetails | latexize> \weeklyreportsection{} - + \begin{itemize} \item{ - <- .Subject | escape -> + <- .Subject | latexize -> <- with .Topics ->: - <- if ne $index 0 ->, <- $topic | escape -> + <- if ne $index 0 ->, <- $topic | latexize -> <- end -> <- end -> } diff --git a/internal/util/documentless_renderer.go b/internal/util/documentless_renderer.go new file mode 100644 index 0000000..a1ef49d --- /dev/null +++ b/internal/util/documentless_renderer.go @@ -0,0 +1,29 @@ +package util + +import ( + "bytes" + + "github.com/russross/blackfriday" +) + +/* +DocumentlessRenderer wraps an actual renderer and suppresses full-document +output. +*/ +type DocumentlessRenderer struct { + blackfriday.Renderer +} + +/* +DocumentHeader does nothing as it is a bogus implementation to avoid full- +document output. +*/ +func (r DocumentlessRenderer) DocumentHeader(out *bytes.Buffer) { +} + +/* +DocumentFooter does nothing as it is a bogus implementation to avoid full- +document output. +*/ +func (r DocumentlessRenderer) DocumentFooter(out *bytes.Buffer) { +}