Use blackfriday LaTeX export for all values inserted in LaTeX.

master
Carl Kittelberger 2017-02-20 12:34:02 +01:00
parent 340b6f234e
commit 9a1ae642f9
Signed by: icedream
GPG Key ID: C1D30A06E6490C14
10 changed files with 110 additions and 36 deletions

View File

@ -40,8 +40,8 @@
"translation": "Berufsschule" "translation": "Berufsschule"
}, },
{ {
"id": "proof_of_education", "id": "proof_of_education_prefix",
"translation": "Ausbildungsnachweis Nr. {{.Count}}" "translation": "Ausbildungsnachweis Nr."
}, },
{ {
"id": "trainee", "id": "trainee",

View File

@ -40,8 +40,8 @@
"translation": "Professional school" "translation": "Professional school"
}, },
{ {
"id": "proof_of_education", "id": "proof_of_education_prefix",
"translation": "Proof of Education No. {{.Count}}" "translation": "Proof of Education No."
}, },
{ {
"id": "trainee", "id": "trainee",

View File

@ -71,7 +71,7 @@ func (fi bindataFileInfo) Sys() interface{} {
return nil 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) { func localizationDeDeAllJsonBytes() ([]byte, error) {
return bindataRead( return bindataRead(
@ -86,7 +86,7 @@ func localizationDeDeAllJson() (*asset, error) {
return nil, err 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} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -111,7 +111,7 @@ func localizationDeDeUntranslatedJson() (*asset, error) {
return a, nil 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) { func localizationEnUsAllJsonBytes() ([]byte, error) {
return bindataRead( return bindataRead(
@ -126,7 +126,7 @@ func localizationEnUsAllJson() (*asset, error) {
return nil, err 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} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }

View File

@ -1,5 +1,5 @@
package stringutil package stringutil
type converter interface { type Converter interface {
Process(text string) string Process(text string) string
} }

View File

@ -7,7 +7,7 @@ type simpleRegexConverter struct {
replacement string replacement string
} }
func newSimpleRegexConverter(regexStr string, replacementStr string) *simpleRegexConverter { func NewSimpleRegexConverter(regexStr string, replacementStr string) *simpleRegexConverter {
return &simpleRegexConverter{ return &simpleRegexConverter{
regex: regexp.MustCompile(regexStr), regex: regexp.MustCompile(regexStr),
replacement: replacementStr, replacement: replacementStr,

View File

@ -7,7 +7,7 @@ type stringConverter struct {
replacement string replacement string
} }
func newStringConverter(old string, replacementStr string) *stringConverter { func NewStringConverter(old string, replacementStr string) *stringConverter {
return &stringConverter{ return &stringConverter{
old: old, old: old,
replacement: replacementStr, replacement: replacementStr,

View File

@ -1,26 +1,20 @@
package stringutil package stringutil
var replacements = []converter{ // BackslashEscape modifies a string so any occurrences of given substrings
newStringConverter("{", "\\{"), // are prefixed with a backslash.
newStringConverter("}", "\\}"), func BackslashEscape(s string, substrings ...string) string {
newStringConverter("\\", "\\textbackslash{}"), replacements := []Converter{}
newStringConverter("&", "\\&"), for _, substring := range substrings {
newStringConverter("%", "\\%"), replacements = append(replacements, NewStringConverter(substring, "\\"+substring))
newStringConverter("$", "\\$"), }
newStringConverter("#", "\\#"),
newStringConverter("_", "\\_"),
newStringConverter("~", "\\textasciitilde{}"),
newStringConverter("^", "\\textasciicircum{}"),
newStringConverter("ß", "\\ss{}"),
newSimpleRegexConverter(`"([^"]+)"`, `\enquote{$1}`), return CustomEscape(s, replacements...)
newSimpleRegexConverter("`([^`]+)`", "\\verb`$1`"),
} }
// TexEscape modifies a string so it can be safely places in a LaTeX file // CustomEscape modifies a string according to the given conversion rules in
// without causing any errors due to special characters. // the exact given order.
func TexEscape(s string) string { func CustomEscape(s string, replacements ...Converter) string {
for _, replacer := range replacements { for _, replacer := range replacements {
s = replacer.Process(s) s = replacer.Process(s)
} }

View File

@ -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
}

View File

@ -23,10 +23,10 @@ var exportTemplate = template.Must(template.
"endofweek": func(date project.Date) project.Date { "endofweek": func(date project.Date) project.Date {
return project.Date{Time: now.New(date.Time).EndOfWeek()} return project.Date{Time: now.New(date.Time).EndOfWeek()}
}, },
"escape": stringutil.TexEscape,
"add": func(a, b int) int { "add": func(a, b int) int {
return a + b return a + b
}, },
"latexize": stringutil.Latexize,
}). }).
Delims("<", ">"). Delims("<", ">").
Parse(`% !TeX Parse(`% !TeX
@ -89,8 +89,8 @@ var exportTemplate = template.Must(template.
\setcounter{section}{\wrNumber} \setcounter{section}{\wrNumber}
\setcounter{subsection}{0} \setcounter{subsection}{0}
\section*{<T "proof_of_education" "\\wrNumber">} \section*{<T "proof_of_education_prefix"> \wrNumber}
\addcontentsline{toc}{section}{<T "proof_of_education" "\\wrNumber">} \addcontentsline{toc}{section}{<T "proof_of_education_prefix"> \wrNumber}
}{ }{
} }
@ -119,25 +119,25 @@ var exportTemplate = template.Must(template.
<with $week.WorkActivities> <with $week.WorkActivities>
\begin{itemize} \begin{itemize}
<range .> <range .>
\item <. | escape> \item <. | latexize>
<end> <end>
\end{itemize} \end{itemize}
<end> <end>
\weeklyreportsection{<T "operational_instruction">} \weeklyreportsection{<T "operational_instruction">}
<$week.WorkActivityDetails | escape> <$week.WorkActivityDetails | latexize>
\weeklyreportsection{<T "professional_school">} \weeklyreportsection{<T "professional_school">}
<if eq (len $week.Periods) 0> <if eq (len $week.Periods) 0>
<T "no_school_periods_this_week" | escape> <T "no_school_periods_this_week">
<else> <else>
\begin{itemize} \begin{itemize}
<range $week.Periods> <range $week.Periods>
\item{ \item{
<- .Subject | escape -> <- .Subject | latexize ->
<- with .Topics ->: <- with .Topics ->:
<range $index, $topic := . -> <range $index, $topic := . ->
<- if ne $index 0 ->, <end -><- $topic | escape -> <- if ne $index 0 ->, <end -><- $topic | latexize ->
<- end -> <- end ->
<- end -> <- end ->
} }

View File

@ -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) {
}