Skip to content
Snippets Groups Projects
Verified Commit 7693af6c authored by Volker Schukai's avatar Volker Schukai :alien:
Browse files

chore: commit save point

parent 3a97d95f
Branches
Tags
No related merge requests found
Showing
with 395 additions and 724 deletions
......@@ -2,7 +2,7 @@
<configuration default="false" name="document build pdf" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="documentation-manager" />
<working_directory value="$PROJECT_DIR$/development/examples/example1" />
<parameters value="document pdf " />
<parameters value="document pdf --verbose" />
<kind value="DIRECTORY" />
<directory value="$PROJECT_DIR$/application/source" />
<filePath value="$PROJECT_DIR$" />
......
......@@ -25,13 +25,17 @@ call
go generate translations/translations.go
```
show font directories
```bash
kpsepath mf | sed -e 's/:/\n/g'
```
### Awsome Boxes
* [Awesomebox](https://ftp.gwdg.de/pub/ctan/graphics/awesomebox/awesomebox.pdf)
### Circled numbers
......
......@@ -24,6 +24,7 @@ type DocumentPDFDefinition struct {
LatexTemplate string `long:"latex-template" short:"l"`
MarkdownTemplate string `long:"markdown-template" short:"m"`
OutputPath string `long:"output" short:"o"`
Verbose bool `long:"verbose" short:"v"`
}
func initDocumentPDF(command *flags.Command) {
......@@ -39,6 +40,8 @@ func initDocumentPDF(command *flags.Command) {
opt.Description = translations.T.Sprintf("directory in which the finished documentation is to be written")
case "format":
opt.Description = translations.T.Sprintf("format of the finished documentation")
case "verbose":
opt.Description = translations.T.Sprintf("verbose output")
}
}
......@@ -54,6 +57,7 @@ func runDocumentPDF(command *flags.Command) {
env.Templates.Latex = environment.State.GetPDFLatexTemplatePath(definition.Document.PDF.LatexTemplate)
env.Templates.Markdown = environment.State.GetPDFMarkdownTemplatePath(definition.Document.PDF.MarkdownTemplate)
env.Verbose = definition.Document.PDF.Verbose
document.BuildPDF(env)
......
package document
import (
"errors"
"io/ioutil"
"os"
"path"
......@@ -68,7 +69,7 @@ func getFiles(sourcePath string) ([]*SourceFile, error) {
err, p := evaluateDocumentContent(c)
if err != nil {
return err
return errors.New("Error while processing files: " + current + " (" + err.Error() + ")")
}
def = append(def, NewDefinition(sourcePath, current, info, p))
......
......@@ -36,113 +36,37 @@ var kbdMapping = map[string]string{
"pgdown": "\\LKeyPgDown",
}
/**
\DeclareRobustCommand*\LKeyStrg{\BiolinumKeyGlyph{Strg}}
\DeclareRobustCommand*\LKeyAlt{\BiolinumKeyGlyph{Alt}}
\DeclareRobustCommand*\LKeyAltApple{\biolinumKeyGlyph{"2325}}
\DeclareRobustCommand*\LKeyAltGr{\BiolinumKeyGlyph{AltGr}}
\DeclareRobustCommand*\LKeyShift{\BiolinumKeyGlyph{Shift}}
\DeclareRobustCommand*\LKeyTab{\BiolinumKeyGlyph{Tab}}
\DeclareRobustCommand*\LKeyEnter{\BiolinumKeyGlyph{Enter}}
\DeclareRobustCommand*\LKeyCapslock{\BiolinumKeyGlyph{Capslock}}
\DeclareRobustCommand*\LKeyPos{\BiolinumKeyGlyph{Pos1}}
\DeclareRobustCommand*\LKeyEntf{\BiolinumKeyGlyph{Entf}}
\DeclareRobustCommand*\LKeyEinf{\BiolinumKeyGlyph{Einf}}
\DeclareRobustCommand*\LKeyLeer{\BiolinumKeyGlyph{Leer}}
\let\LKeySpace\LKeyLeer
\DeclareRobustCommand*\LKeyEsc{\BiolinumKeyGlyph{Esc}}
\DeclareRobustCommand*\LKeyEnde{\BiolinumKeyGlyph{Ende}}
%\DeclareRobustCommand*\LKeyTux{\BiolinumKeyGlyph{Tux}}
\DeclareRobustCommand*\LKeyWin{\BiolinumKeyGlyph{Windows}}
\DeclareRobustCommand*\LKeyMenu{\biolinumKeyGlyph{"E104}}
\DeclareRobustCommand*\LKeyCtrl{\BiolinumKeyGlyph{Ctrl}}
\DeclareRobustCommand*\LKeyOptionKey{\BiolinumKeyGlyph{Fn}}
\DeclareRobustCommand*\LKeyBack{\BiolinumKeyGlyph{Back}}
\DeclareRobustCommand*\LKeyUp{\biolinumKeyGlyph{"2191}}
\DeclareRobustCommand*\LKeyDown{\biolinumKeyGlyph{"2193}}
\DeclareRobustCommand*\LKeyLeft{\biolinumKeyGlyph{"2190}}
\DeclareRobustCommand*\LKeyRight{\biolinumKeyGlyph{"2192}}
\DeclareRobustCommand*\LKeyBildUp{\BiolinumKeyGlyph{Buildup}}
\DeclareRobustCommand*\LKeyBildDown{\BiolinumKeyGlyph{Builddown}}
\DeclareRobustCommand*\LKeyAt{\biolinumKeyGlyph{"0040}}
\DeclareRobustCommand*\LKeyFn{\BiolinumKeyGlyph{Fn}}
\DeclareRobustCommand*\LKeyHome{\BiolinumKeyGlyph{Home}}
\DeclareRobustCommand*\LKeyDel{\BiolinumKeyGlyph{Del}}
\DeclareRobustCommand*\LKeyIns{\BiolinumKeyGlyph{Ins}}
\DeclareRobustCommand*\LKeyEnd{\BiolinumKeyGlyph{End}}
\DeclareRobustCommand*\LKeyGNU{\BiolinumKeyGlyph{GNU}}
\DeclareRobustCommand*\LKeyPageUp{\BiolinumKeyGlyph{Pageup}}
\DeclareRobustCommand*\LKeyPageDown{\BiolinumKeyGlyph{Pagedown}}
\DeclareRobustCommand*\LKeyWindows{\BiolinumKeyGlyph{Windows}}
func convertCircledNumbers(content string) string {
circleMap := map[string]string{
"➊": "\\large\\libertineGlyph{uni2776}\\normalsize",
"➋": "\\large\\libertineGlyph{uni2777}\\normalsize",
"➌": "\\large\\libertineGlyph{uni2778}\\normalsize",
"➍": "\\large\\libertineGlyph{uni2779}\\normalsize",
"➎": "\\large\\libertineGlyph{uni277A}\\normalsize",
"➏": "\\large\\libertineGlyph{uni277B}\\normalsize",
"➐": "\\large\\libertineGlyph{uni277C}\\normalsize",
"➑": "\\large\\libertineGlyph{uni277D}\\normalsize",
"➒": "\\large\\libertineGlyph{uni277E}\\normalsize",
"➓": "\\large\\libertineGlyph{uni277F}\\normalsize",
"⓫": "\\large\\libertineGlyph{uni24EB}\\normalsize",
"⓬": "\\large\\libertineGlyph{uni24EC}\\normalsize",
"⓭": "\\large\\libertineGlyph{uni24ED}\\normalsize",
"⓮": "\\large\\libertineGlyph{uni24EE}\\normalsize",
"⓯": "\\large\\libertineGlyph{uni24EF}\\normalsize",
"⓰": "\\large\\libertineGlyph{uni24F0}\\normalsize",
"⓱": "\\large\\libertineGlyph{uni24F1}\\normalsize",
"⓲": "\\large\\libertineGlyph{uni24F2}\\normalsize",
"⓳": "\\large\\libertineGlyph{uni24F3}\\normalsize",
"⓴": "\\large\\libertineGlyph{uni24F4}\\normalsize",
}
\@namedef{libertine@key@F@1}{\BiolinumKeyGlyph{F1}}
\@namedef{libertine@key@F@2}{\BiolinumKeyGlyph{F2}}
\@namedef{libertine@key@F@3}{\BiolinumKeyGlyph{F3}}
\@namedef{libertine@key@F@4}{\BiolinumKeyGlyph{F4}}
\@namedef{libertine@key@F@5}{\BiolinumKeyGlyph{F5}}
\@namedef{libertine@key@F@6}{\BiolinumKeyGlyph{F6}}
\@namedef{libertine@key@F@7}{\BiolinumKeyGlyph{F7}}
\@namedef{libertine@key@F@8}{\BiolinumKeyGlyph{F8}}
\@namedef{libertine@key@F@9}{\BiolinumKeyGlyph{F9}}
\@namedef{libertine@key@F@10}{\BiolinumKeyGlyph{F10}}
\@namedef{libertine@key@F@11}{\BiolinumKeyGlyph{F11}}
\@namedef{libertine@key@F@12}{\BiolinumKeyGlyph{F12}}
\@namedef{libertine@key@F@13}{\BiolinumKeyGlyph{F13}}
\@namedef{libertine@key@F@14}{\BiolinumKeyGlyph{F14}}
\@namedef{libertine@key@F@15}{\BiolinumKeyGlyph{F15}}
\@namedef{libertine@key@F@16}{\BiolinumKeyGlyph{F16}}
\DeclareRobustCommand*\LKeyF[1]{\@nameuse{libertine@key@F@#1}}
%
\DeclareRobustCommand*\LKeyAltF[1]{\LKeyAlt+\@nameuse{libertine@key@F@#1}}
\DeclareRobustCommand*\LKeyStrgAltF[1]{\LKeyStrg+\LKeyAlt+\@nameuse{libertine@key@F@#1}}
\DeclareRobustCommand*\LKeyStrgX[1]{\LKeyStrg+\LKey{#1}}
\DeclareRobustCommand*\LKeyShiftX[1]{\LKeyShift+\LKey{#1}}
\DeclareRobustCommand*\LKeyAltX[1]{\LKeyAlt+\LKey{#1}}
\DeclareRobustCommand*\LKeyAltAppleX[1]{\LKeyAltApple+\LKey{#1}}
\DeclareRobustCommand*\LKeyAltGrX[1]{\LKeyAltGr+\LKey{#1}}
\DeclareRobustCommand*\LKeyShiftStrgX[1]{\LKeyShift+\LKeyStrg+\LKey{#1}}
\DeclareRobustCommand*\LKeyShiftAltX[1]{\LKeyShift+\LKeyAlt+\LKey{#1}}
\DeclareRobustCommand*\LKeyShiftAltGrX[1]{\LKeyShift+\LKeyAltGr+\LKey{#1}}
\DeclareRobustCommand*\LKeyStrgAltX[1]{\LKeyStrg+\LKeyAlt+\LKey{#1}}
\DeclareRobustCommand*\LKeyStrgAltEntf{\LKeyStrg+\LKeyAlt+\LKeyEntf}
\let\LKeyReset\LKeyStrgAltEntf
%
\@namedef{libertine@key@Pad@0}{\BiolinumKeyGlyph{Pad0}}
\@namedef{libertine@key@Pad@1}{\BiolinumKeyGlyph{Pad1}}
\@namedef{libertine@key@Pad@2}{\BiolinumKeyGlyph{Pad2}}
\@namedef{libertine@key@Pad@3}{\BiolinumKeyGlyph{Pad3}}
\@namedef{libertine@key@Pad@4}{\BiolinumKeyGlyph{Pad4}}
\@namedef{libertine@key@Pad@5}{\BiolinumKeyGlyph{Pad5}}
\@namedef{libertine@key@Pad@6}{\BiolinumKeyGlyph{Pad6}}
\@namedef{libertine@key@Pad@7}{\BiolinumKeyGlyph{Pad7}}
\@namedef{libertine@key@Pad@8}{\BiolinumKeyGlyph{Pad8}}
\@namedef{libertine@key@Pad@9}{\BiolinumKeyGlyph{Pad9}}
%\@namedef{libertine@key@Pad@10}{\BiolinumKeyGlyph{"E1AA}}
%\@namedef{libertine@key@Pad@11}{\BiolinumKeyGlyph{"E1AB}}
%\@namedef{libertine@key@Pad@12}{\BiolinumKeyGlyph{"E1AC}}
%\@namedef{libertine@key@Pad@13}{\BiolinumKeyGlyph{"E1AD}}
%\@namedef{libertine@key@Pad@14}{\BiolinumKeyGlyph{"E1AE}}
\DeclareRobustCommand*\LKeyPad[1]{\@nameuse{libertine@key@Pad@#1}}
%
% Maus
%
\iffalse
\DeclareRobustCommand*\LMouseEmpty{\biolinumKeyGlyph{"E130}}
\DeclareRobustCommand*\LMouseN{\biolinumKeyGlyph{"E131}}
\DeclareRobustCommand*\LMouseL{\biolinumKeyGlyph{"E132}}
\DeclareRobustCommand*\LMouseM{\biolinumKeyGlyph{"E133}}
\DeclareRobustCommand*\LMouseR{\biolinumKeyGlyph{"E134}}
\DeclareRobustCommand*\LMouseLR{\biolinumKeyGlyph{"E135}}
\DeclareRobustCommand*\LMouseIIEmpty{\biolinumKeyGlyph{"E138}}
\DeclareRobustCommand*\LMouseIIN{\biolinumKeyGlyph{"E139}}
\DeclareRobustCommand*\LMouseIIL{\biolinumKeyGlyph{"E13A}}
\DeclareRobustCommand*\LMouseIIR{\biolinumKeyGlyph{"E13C}}
\DeclareRobustCommand*\LMouseIILR{\biolinumKeyGlyph{"E13D}}
\fi
%
for k, v := range circleMap {
content = strings.Replace(content, k, v, -1)
}
*/
return content
}
func replaceKbd(content string) string {
......@@ -165,9 +89,7 @@ func replaceKbd(content string) string {
if !ok {
runes := []rune(result["key"])
for _, k := range runes {
h := strings.ToUpper(fmt.Sprintf("%x", k))
h = "uni00" + h
h := strings.ToUpper(fmt.Sprintf("uni%04x", k))
r += fmt.Sprintf("\\biolinumKeyGlyph{%s}", h)
}
}
......@@ -177,24 +99,5 @@ func replaceKbd(content string) string {
}
return content
// result := make(map[string]string)
// for i, name := range todoRegEx.SubexpNames() {
// if i != 0 && name != "" {
// result[name] = match[i]
// }
// }
//
// if filepath.IsAbs(result["path"]) {
// continue
// }
//
//
//
//
//
//
//map[string]string{
//}
}
......@@ -3,10 +3,61 @@ package document
import (
"fmt"
"gitlab.schukai.com/oss/utilities/documentation-manager/environment"
"io/ioutil"
"os"
"os/exec"
)
func runPandoc(source string, outputName string, latexPath string, luaFilter string) error {
func runInlinePandoc(source string) string {
tmpSource, err := ioutil.TempFile(os.TempDir(), "inline-source")
if err != nil {
environment.ExitWithError(2, "A temporary file cannot be created", err.Error())
}
defer os.Remove(tmpSource.Name())
tmpResult, err := ioutil.TempFile(os.TempDir(), "inline-result")
if err != nil {
environment.ExitWithError(2, "A temporary file cannot be created", err.Error())
}
defer os.Remove(tmpResult.Name())
tmpSource.WriteString(source)
arguments := "/bin/env pandoc "
arguments += "--variable fontsize=12pt "
arguments += "--variable version=2.0 "
arguments += tmpSource.Name() + " "
arguments += "--from markdown "
arguments += "--to latex "
arguments += "--output=" + tmpResult.Name() + " "
cmd := exec.Command("bash", "-c", arguments)
_, err = cmd.Output()
if err != nil {
exitErr, ok := err.(*exec.ExitError)
if ok {
environment.ExitWithError(2, string(exitErr.Stderr))
} else {
environment.ExitWithError(2, err.Error())
}
}
content, err := os.ReadFile(tmpResult.Name())
checkError(err)
return string(content)
}
func runPandoc(source string, outputName string, latexPath string, luaFilter string, verbose bool) error {
arguments := "/bin/env pandoc "
......@@ -18,6 +69,9 @@ func runPandoc(source string, outputName string, latexPath string, luaFilter str
arguments += "--pdf-engine=xelatex "
arguments += "--from markdown "
arguments += "--to pdf "
if verbose {
arguments += "--verbose "
}
arguments += "--listings "
if latexPath != "" {
......@@ -33,12 +87,15 @@ func runPandoc(source string, outputName string, latexPath string, luaFilter str
arguments += "--toc "
arguments += "--output=" + outputName + " "
fmt.Println(arguments)
cmd := exec.Command("bash", "-c", arguments)
log, err := cmd.Output()
cmd, err := exec.Command("bash", "-c", arguments).Output()
fmt.Println(string(cmd))
if err != nil {
if verbose {
fmt.Println(string(log))
}
exitErr, ok := err.(*exec.ExitError)
if ok {
environment.ExitWithError(2, string(exitErr.Stderr))
......
......@@ -3,7 +3,9 @@ package document
import (
"fmt"
"gitlab.schukai.com/oss/utilities/documentation-manager/environment"
"gitlab.schukai.com/oss/utilities/documentation-manager/utils"
"io/ioutil"
"net/url"
"os"
"path"
"path/filepath"
......@@ -16,6 +18,7 @@ type BuildPdfEnvironment struct {
SourcePath string
DateFormat string
OutputPath string
Verbose bool
Templates struct {
Latex string
Markdown string
......@@ -41,7 +44,9 @@ func NewPdfDataset(env BuildPdfEnvironment) (*PdfDataset, error) {
for _, key := range keys {
text := mapFiles[key].textMeta.text
text = convertImages(text, env.SourcePath)
text = convertHeadlines(text, mapFiles[key].level)
text = convertAwesomeBoxes(text)
text = convertImages(text, mapFiles[key].baseDir)
text = convertCircledNumbers(text)
text = replaceKbd(text)
text = replaceRelativeLinks(text, mapFiles[key].hash, mapFiles)
......@@ -51,7 +56,9 @@ func NewPdfDataset(env BuildPdfEnvironment) (*PdfDataset, error) {
d.Documents = strings.Join(docs, "\n")
fmt.Println(d.Documents)
if env.Verbose {
fmt.Println(d.Documents)
}
return d, nil
}
......@@ -99,7 +106,11 @@ func BuildPDF(env BuildPdfEnvironment) error {
}
}()
runPandoc(file.Name(), output, env.Templates.Latex, luaFilter.Name())
c, _ := os.ReadFile(file.Name())
os.WriteFile("/tmp/debug.txt", c, 0644)
runPandoc(file.Name(), output, env.Templates.Latex, luaFilter.Name(), env.Verbose)
return nil
}
......@@ -128,6 +139,10 @@ func replaceRelativeLinks(content, hash string, fileMap SourceFileMap) string {
}
s := fileMap.findByRelativePath(result["path"])
if s == nil {
continue
}
replace := "\\hyperlink{link_" + s.hash + "}{" + result["label"] + "}"
content = strings.Replace(content, result["match"], replace, -1)
......@@ -138,15 +153,15 @@ func replaceRelativeLinks(content, hash string, fileMap SourceFileMap) string {
func createLuaFile() *os.File {
tmp, err := ioutil.TempFile(os.TempDir(), "lua-raw-block")
tmp, err := ioutil.TempFile(os.TempDir(), "lua-filter")
if err != nil {
environment.ExitWithError(2, "A temporary file cannot be created", err.Error())
}
tmp.WriteString(`
function RawBlock (raw)
return raw.format:match 'html'
and pandoc.read(raw.text, 'html').blocks
return raw.format:match "html"
and pandoc.read(raw.text, "html").blocks
or raw
end
`)
......@@ -155,125 +170,261 @@ end
}
func convertCircledNumbers(content string) string {
circleMap := map[string]string{
"➊": "\\large\\libertineGlyph{uni2776}\\normalsize",
"➋": "\\large\\libertineGlyph{uni2777}\\normalsize",
"➌": "\\large\\libertineGlyph{uni2778}\\normalsize",
"➍": "\\large\\libertineGlyph{uni2779}\\normalsize",
"➎": "\\large\\libertineGlyph{uni277A}\\normalsize",
"➏": "\\large\\libertineGlyph{uni277B}\\normalsize",
"➐": "\\large\\libertineGlyph{uni277C}\\normalsize",
"➑": "\\large\\libertineGlyph{uni277D}\\normalsize",
"➒": "\\large\\libertineGlyph{uni277E}\\normalsize",
"➓": "\\large\\libertineGlyph{uni277F}\\normalsize",
"⓫": "\\large\\libertineGlyph{uni24EB}\\normalsize",
"⓬": "\\large\\libertineGlyph{uni24EC}\\normalsize",
"⓭": "\\large\\libertineGlyph{uni24ED}\\normalsize",
"⓮": "\\large\\libertineGlyph{uni24EE}\\normalsize",
"⓯": "\\large\\libertineGlyph{uni24EF}\\normalsize",
"⓰": "\\large\\libertineGlyph{uni24F0}\\normalsize",
"⓱": "\\large\\libertineGlyph{uni24F1}\\normalsize",
"⓲": "\\large\\libertineGlyph{uni24F2}\\normalsize",
"⓳": "\\large\\libertineGlyph{uni24F3}\\normalsize",
"⓴": "\\large\\libertineGlyph{uni24F4}\\normalsize",
}
for k, v := range circleMap {
content = strings.Replace(content, k, v, -1)
}
func isUrl(str string) bool {
u, err := url.Parse(str)
return err == nil && u.Scheme != "" && u.Host != ""
}
return content
type foundedTitleInfoStruct struct {
level int
match string
title string
}
func convertImages(content string, absolute string) string {
type foundedTitleInfo []foundedTitleInfoStruct
todoRegEx := regexp.MustCompile(`(?P<match>\!\[(?P<label>[^]]*)\]\((?P<path>[^)]*)\))`)
func convertHeadlines(content string, level int) string {
matches := todoRegEx.FindAllStringSubmatch(content, -1)
regEx := regexp.MustCompile(`(?m)^(?P<match>(?P<level>#+)\s+(?P<title>[^\n]*))`)
matches := regEx.FindAllStringSubmatch(content, -1)
if matches == nil {
return content
}
info := foundedTitleInfo{}
smallestLevelInTheDoc := 999
for _, match := range matches {
result := make(map[string]string)
for i, name := range todoRegEx.SubexpNames() {
for i, name := range regEx.SubexpNames() {
if i != 0 && name != "" {
result[name] = match[i]
}
}
if filepath.IsAbs(result["path"]) {
continue
info = append(info, foundedTitleInfoStruct{
level: len(result["level"]),
match: result["match"],
title: result["title"],
})
if len(result["level"]) < smallestLevelInTheDoc {
smallestLevelInTheDoc = len(result["level"])
}
path := path.Clean(absolute + "/" + result["path"])
content = strings.Replace(content, result["match"], "!["+result["label"]+"]("+path+")", -1)
}
d := level - smallestLevelInTheDoc
if d < 0 {
d = 0
}
for _, i := range info {
fill := strings.Repeat("#", d+i.level)
nw := fill + " " + i.title + "\n"
content = strings.Replace(content, i.match, nw, 1)
}
return content
}
func convertTemplateLogo(content string, absolute string) string {
todoRegEx := regexp.MustCompile(`(?m)^(?P<match>logo:\s*"?(?P<path>[^"\n]*)"?\s*)$`)
// https://ftp.gwdg.de/pub/ctan/graphics/awesomebox/awesomebox.pdf
func convertAwesomeBoxes(content string) string {
regEx := regexp.MustCompile(`(?m)(?P<matches>!!!\s*(?P<type>[^\s]+)\s+?(?P<title>[^\n]*)\n(?P<lines>(?P<lastline>[[:blank:]]+[^\n]+\n)+))`)
matches := todoRegEx.FindAllStringSubmatch(content, -1)
matches := regEx.FindAllStringSubmatch(content, -1)
if matches == nil {
return content
}
for _, match := range matches {
result := make(map[string]string)
for i, name := range todoRegEx.SubexpNames() {
for i, name := range regEx.SubexpNames() {
if i != 0 && name != "" {
result[name] = match[i]
}
}
if filepath.IsAbs(result["path"]) {
continue
boxtype := "note"
switch {
case utils.Contains([]string{"notebox", "note", "info"}, result["type"]):
boxtype = "note"
case utils.Contains([]string{"tipbox", "tip", "hint"}, result["type"]):
boxtype = "tip"
case utils.Contains([]string{"warningbox", "warning", "warn"}, result["type"]):
boxtype = "warning"
case utils.Contains([]string{"cautionbox", "caution", "danger"}, result["type"]):
boxtype = "caution"
case utils.Contains([]string{"importantbox", "important"}, result["type"]):
boxtype = "important"
}
path := path.Clean(absolute + "/" + result["path"])
content = strings.Replace(content, result["match"], "logo: \""+path+"\"", -1)
c := ""
t := escapeLatexSpecialChars(result["title"])
if t != "" {
c += "\\textbf{" + utils.TrimQuotes(t) + "}\n"
}
lines := result["lines"]
lines = convertAwesomeBoxesMarkdown(lines)
c += "\n" + lines + "\n" //+escapeLatexSpecialChars(result["lastline"])) + "\n"
awesomebox := `\begin{` + boxtype + `block}` + c + "\n" + `\end{` + boxtype + `block}`
content = strings.Replace(content, result["matches"], "\n"+awesomebox+"\n", 1)
}
return content
}
func convertTemplateLatexLogo(content string, absolute string) string {
todoRegEx := regexp.MustCompile(`(?m)(?P<match>\\includegraphics[^{]*\{(?P<path>[^}]*)\})`)
func convertAwesomeBoxesMarkdown(content string) string {
output := runInlinePandoc(escapeLatexSpecialChars(utils.TrimLines(content)))
return output
}
matches := todoRegEx.FindAllStringSubmatch(content, -1)
// The following characters play a special role in LaTeX and are called special printing characters, or simply special characters.
//
// # $ % & ~ _ ^ \ { }
//
// Whenever you put one of these special characters into your file, you are doing something special. If you simply want the character
// to be printed just as any other letter, include a \ in front of the character. For example, \$ will produce $ in your output.
//
// The exception to the rule is the \ itself because \\ has its own special meaning. A \ is produced by typing $\backslash$ in your file.
//
// The meaning of these characters are:
//
// ~ (tilde) unbreakable space, use it whenever you want to leave a space which is unbreakable, and cannot expand or shrink, as e.q. in names: A.~U.~Thor.
// $ (dollar sign) to start an finish math mode.
// _ (underscore) for subscripts in math mode.
// ^ (hat) for superscripts in math mode.
// \ (backslash) starting commands, which extend until the first non-alphanumerical character. The space following the command is swallowed. The following line results in what expected:
// The \TeX nician is an expert in \TeX{} language.
// {} (curly brackets) to group and separate commands from its surroundings. Must appear in pairs.
func escapeLatexSpecialChars(content string) string {
result := ""
runes := []rune(content)
for i, k := range runes {
if k == '\\' {
result += "\\textbackslash{}"
continue
} else if utils.Contains([]string{"#", "$", "%", "&", "~", "_", "^", "\\", "{", "}"}, string(k)) {
if i == 0 || runes[i-1] != '\\' {
result += "\\"
}
}
result += string(k)
}
return result
}
func convertImages(content string, absolute string) string {
regEx := regexp.MustCompile(`(?P<match>\!\[(?P<label>[^]]*)\]\((?P<path>[^)]*)\))`)
matches := regEx.FindAllStringSubmatch(content, -1)
if matches == nil {
return content
}
for _, match := range matches {
result := make(map[string]string)
for i, name := range todoRegEx.SubexpNames() {
for i, name := range regEx.SubexpNames() {
if i != 0 && name != "" {
result[name] = match[i]
}
}
if filepath.IsAbs(result["path"]) {
if isUrl(result["path"]) {
continue
}
path := path.Clean(absolute + "/" + result["path"])
a := strings.Replace(result["match"], result["path"], path, -1)
if filepath.IsAbs(result["path"]) {
continue
}
content = strings.Replace(content, result["match"], a, -1)
p := filepath.Join(absolute, result["path"])
path := path.Clean(p)
content = strings.Replace(content, result["match"], "!["+result["label"]+"]("+path+")", -1)
}
return content
}
//func convertTemplateLogo(content string, absolute string) string {
// todoRegEx := regexp.MustCompile(`(?m)^(?P<match>logo:\s*"?(?P<path>[^"\n]*)"?\s*)$`)
//
// matches := todoRegEx.FindAllStringSubmatch(content, -1)
// if matches == nil {
// return content
// }
//
// for _, match := range matches {
// result := make(map[string]string)
// for i, name := range todoRegEx.SubexpNames() {
// if i != 0 && name != "" {
// result[name] = match[i]
// }
// }
//
// if filepath.IsAbs(result["path"]) {
// continue
// }
//
// path := path.Clean(absolute + "/" + result["path"])
// content = strings.Replace(content, result["match"], "logo: \""+path+"\"", -1)
//
// }
//
// return content
//}
//func convertTemplateLatexLogo(content string, absolute string) string {
// todoRegEx := regexp.MustCompile(`(?m)(?P<match>\\includegraphics[^{]*\{(?P<path>[^}]*)\})`)
//
// matches := todoRegEx.FindAllStringSubmatch(content, -1)
// if matches == nil {
// return content
// }
//
// for _, match := range matches {
// result := make(map[string]string)
// for i, name := range todoRegEx.SubexpNames() {
// if i != 0 && name != "" {
// result[name] = match[i]
// }
// }
//
// if filepath.IsAbs(result["path"]) {
// continue
// }
//
// path := path.Clean(absolute + "/" + result["path"])
// a := strings.Replace(result["match"], result["path"], path, -1)
//
// content = strings.Replace(content, result["match"], a, -1)
//
// }
//
// return content
//}
//
//func convertTemplateImages(content string, absolute string) string {
// content = convertTemplateLogo(content, absolute)
......
......@@ -5,16 +5,19 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
)
type SourceFile struct {
//dateFormat string
baseDir string
absSourcePath string
relSourcePath string
//targetPath string
fileInfo os.FileInfo
textMeta textMetaStruct
hash string
level int
}
func NewDefinition(root string, sourcePath string, info os.FileInfo, textMeta textMetaStruct) *SourceFile {
......@@ -29,6 +32,14 @@ func NewDefinition(root string, sourcePath string, info os.FileInfo, textMeta te
}
s.hash = fmt.Sprintf("%x", md5.Sum([]byte(r)))
s.baseDir = filepath.Dir(sourcePath)
d, _ := filepath.Split(s.relSourcePath)
if d != "" {
s.level = len(strings.Split(d, "/")) + 1
} else {
s.level = 1
}
return s
}
......
......@@ -47,41 +47,28 @@ func evaluateDocumentContent(content []byte) (error, textMetaStruct) {
meta := ""
text := ""
before, remaining, found := strings.Cut(origin, "---")
before, remaining, found := strings.Cut(origin, "\n---\n")
if !found {
req := textMetaStruct{}
req.text = origin
return nil, req
//t := strings.TrimSpace(origin)
//if len(t) == 0 {
// return errors.New("the file is empty"), textMetaStruct{
// text: origin,
// meta: document{},
// }
//}
//
//return errors.New("the file does not contain a definition block"), textMetaStruct{
// text: origin,
// meta: document{},
//}
return nil, req
}
text += before
a, b, found := strings.Cut(remaining, "\n...")
a, b, found := strings.Cut(remaining, "\n...\n")
if !found {
a, b, found = strings.Cut(remaining, "\n---")
a, b, found = strings.Cut(remaining, "\n---\n")
if !found {
a, b, found = strings.Cut(remaining, "...")
a, b, found = strings.Cut(remaining, "\n...\n")
if !found {
a, b, found = strings.Cut(remaining, "---")
a, b, found = strings.Cut(remaining, "\n---\n")
if !found {
return errors.New("the file does not contain a definition block"), textMetaStruct{}
......
package utils
func Contains(s []string, str string) bool {
for _, v := range s {
if v == str {
return true
}
}
return false
}
package utils
import "strings"
func TrimLines(s string) string {
flag := false
l := strings.Split(s, "\n")
r := []string{}
for _, v := range l {
m := strings.TrimSpace(v)
if m == "" {
flag = true
continue
}
if m != "" && flag {
m += "\n"
}
flag = false
r = append(r, m)
}
rs := strings.Join(r, "\n")
return rs
}
func TrimQuotes(s string) string {
if len(s) >= 2 {
if s[0] == '"' && s[len(s)-1] == '"' {
return s[1 : len(s)-1]
}
}
return s
}
No preview for this file type
......@@ -887,6 +887,8 @@ $endif$
\node[shape=circle,draw,text=white,fill=black,inner sep=2pt] (char) {#1};}}
\usepackage{libertine}
\usepackage{awesomebox}
\usepackage{dirtree}
......
......@@ -24,6 +24,21 @@ Last Update: 06.07.2022
Lorem ipsum dolor sit amet, consectetur [read sub](sub1/doc1.md) adipiscing elit.
!!! note "This is a note"
A-Lorem ipsum dolor sit amet, consectetur adipiscing elit.
B-Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Die Escape-Sequenz gilt für: \, `, *, _, {, }, [, ], (, ), #, +, -, ., !
D-Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
`text in html`{=html}
`text in pdf`{=latex}
--
HEUTE: <kbd>Ctrl</kbd>+<kbd>ShifT</kbd><kbd>AUTO123$_öäüP</kbd>
--
......
package main
import (
"fmt"
"sort"
"strings"
)
type logs []string
func buildChangelog(pageMap map[string]*documentContent) (error, string, bool) {
changelog := make(map[string]logs)
datemap := make(map[string]string)
for _, q := range pageMap {
s := *q
p := s.meta
title := strings.Trim(p.Title, " ")
if title == "" {
title = printer.Sprintf("Untitled")
}
e := title
d := p.Created.String()
datemap[d] = p.Created.Format(config.Locale.DateFormat)
if p.Created.Before(p.LastUpdate) {
d = p.LastUpdate.String()
datemap[d] = p.LastUpdate.Format(config.Locale.DateFormat)
}
changelog[d] = append(changelog[d], e)
}
hasChangelog := false
result := ""
var sortedKeys sort.StringSlice
for k := range changelog {
sortedKeys = append(sortedKeys, k)
}
sort.Sort(sort.Reverse(sortedKeys))
for _, k := range sortedKeys {
result += "### " + datemap[k] + "\n\n"
for _, m := range changelog[k] {
result += "- " + m + "\n"
}
result += "\n"
hasChangelog = true
}
return nil, result, hasChangelog
}
func printChangelog() error {
err, pageData := collectStructureFromFiles(config.Path)
if err != nil {
return err
}
err, table, _ := buildChangelog(pageData)
fmt.Println(table)
return err
}
package main
import (
"os"
"path"
"path/filepath"
"github.com/jessevdk/go-flags"
)
var (
config *Configuration
arguments *commandLineOptions
)
func executeCommand() {
arguments = new(commandLineOptions)
p := flags.NewParser(arguments, flags.Default)
_, err := p.Parse()
if err != nil {
os.Exit(-1)
}
config = NewConfiguration(arguments.Config)
if arguments.Path != "" {
config.Path = arguments.Path
}
arguments.Path, err = filepath.Abs(arguments.Path)
if err != nil {
printErrorAndExit(2, "Unknown Error", err.Error())
}
if arguments.DateFormat != "" {
config.Locale.DateFormat = arguments.DateFormat
}
activeCommand := p.Command.Active
if activeCommand == nil {
return
}
switch activeCommand.Name {
case "version":
printInfo("Version " + version + " (" + build + ")")
case "changelog":
subcommand := activeCommand.Active
switch subcommand.Name {
case "print":
err := printChangelog()
if err != nil {
printErrorAndExit(2, err.Error())
}
}
case "tasks":
subcommand := activeCommand.Active
switch subcommand.Name {
case "print":
err := printTaskTable()
if err != nil {
printErrorAndExit(2, err.Error())
}
}
case "add":
if config.Document.Template.Add == "" {
config.Document.Template.Add = defaultNewDocumentTemplate
}
err := addDocument()
if err != nil {
printErrorAndExit(2, err.Error())
}
case "build":
subcommand := activeCommand.Active
switch subcommand.Name {
case "html":
if arguments.Build.HTML.TemplatePath != "" {
config.HTML.Template.Internal.HTMLContent = readTemplate(arguments.Build.HTML.TemplatePath)
} else if config.HTML.Template.HTML != "" {
config.HTML.Template.Internal.HTMLContent = readTemplate(config.HTML.Template.HTML)
} else {
config.HTML.Template.Internal.HTMLContent = defaultHTMLTemplate
}
err := createHTML()
if err != nil {
printErrorAndExit(2, err.Error())
}
case "pdf":
if arguments.Build.PDF.TemplatePath != "" {
config.PDF.Template.Internal.MarkdownContent = readTemplate(arguments.Build.PDF.TemplatePath)
} else if config.PDF.Template.Markdown != "" {
config.PDF.Template.Internal.MarkdownContent = readTemplate(config.PDF.Template.Markdown)
} else {
config.PDF.Template.Internal.MarkdownContent = defaultPDFTemplate
}
if arguments.Build.PDF.LatexTemplatePath != "" {
config.PDF.Template.Latex = arguments.Build.PDF.LatexTemplatePath
}
err := CreatePDF()
if err != nil {
printErrorAndExit(2, err.Error())
}
}
}
}
func readTemplate(argPath string) string {
current, err := os.Getwd()
if err != nil {
printErrorAndExit(2, "Unknown Error", err.Error())
}
p := argPath
if !filepath.IsAbs(p) {
p = path.Clean(current + "/" + p)
}
template, err := os.ReadFile(p)
if err != nil {
printErrorAndExit(exitCodeCatchAll,
"the specified template", argPath)
}
return convertTemplateImages(string(template), path.Dir(p))
}
package main
type commandLineOptions struct {
Config string `short:"c" long:"config" description:"file with configuration values"`
Path string `short:"p" long:"path" description:"define the path where the specifications are located" default:"."`
DateFormat string `long:"date-format" description:"date format" default:"2006-01-02"`
Add struct {
Name string `short:"n" long:"name" description:"name of the document"`
} `command:"add"`
Tasks struct {
Print struct {
} `command:"print"`
} `command:"tasks"`
Changelog struct {
Print struct {
} `command:"print"`
} `command:"changelog"`
Build struct {
PDF struct {
TemplatePath string `short:"t" long:"template" description:"file name of the template of the pages"`
Output string `short:"o" long:"output" description:"output file name"`
LatexTemplatePath string `short:"l" long:"latex-template-path" description:"latex template"`
} `command:"pdf"`
HTML struct {
TemplatePath string `short:"t" long:"template" description:"file name of the template of a html page"`
Output string `short:"o" long:"output" description:"output directory"`
} `command:"html"`
} `command:"build"`
Version struct {
} `command:"version"`
}
package main
import (
"os"
"os/user"
"path"
)
type configPathsStruct struct {
argument string
current string
user string
main string
}
var (
configPaths = configPathsStruct{
main: "/etc/documentations-manager/config.yaml",
}
)
// Configuration
type Configuration struct {
Path string `yaml:"SourcePath"`
Locale struct {
DateFormat string `yaml:"DateFormat"`
} `yaml:"Locale"`
PDF struct {
Template struct {
Markdown string `yaml:"Markdown"`
Latex string `yaml:"Latex"`
Internal struct {
MarkdownContent string
} `yaml:"-"`
} `yaml:"Template"`
} `yaml:"PDF"`
HTML struct {
Template struct {
HTML string `yaml:"HTML"`
Internal struct {
HTMLContent string
} `yaml:"-"`
} `yaml:"Template"`
}
Document struct {
Template struct {
Add string `yaml:"Add"`
} `yaml:"Template"`
} `yaml:"Document"`
}
func fileExists(name string) (found bool) {
if f, err := os.Stat(name); err == nil {
return f.Mode().IsRegular()
}
return false
}
// NewConfiguration
func NewConfiguration(argConfigPath string) *Configuration {
current, err := os.Getwd()
if err != nil {
panic(err)
}
filename := path.Clean(current + "/config.yaml")
cfg := Configuration{}
usr, err := user.Current()
if err == nil {
configPaths.user = usr.HomeDir + "/.config/documentations-manager/config.yaml"
}
if argConfigPath != "" {
configPaths.argument = argConfigPath
}
switch {
case fileExists(configPaths.argument):
readFile(&cfg, configPaths.argument)
case fileExists(filename):
readFile(&cfg, filename)
case fileExists(current):
readFile(&cfg, current)
case fileExists(configPaths.user):
readFile(&cfg, configPaths.user)
case fileExists(configPaths.main):
readFile(&cfg, configPaths.main)
}
return &cfg
}
func readFile(cfg *Configuration, filename string) {
f, err := os.Open(filename)
if err != nil {
printErrorAndExit(2, err.Error())
}
defer f.Close()
decoder := yaml.NewDecoder(f)
err = decoder.Decode(cfg)
if err != nil {
printErrorAndExit(2, err.Error())
}
}
package main
import (
"sort"
"time"
)
type Dataset struct {
Config *Configuration
Meta string
HasMeta bool
HasChangelog bool
Changelog string
Tasks string
HasTasks bool
Documents string
HasDocuments bool
Created time.Time
CreatedFormat string
Description string
HasDescription bool
Title string
HasTitle bool
keys []string
}
const flagInitChangelog = 1
const flagInitTasks = 2
const flagInitDocuments = 4
func getDataset(pageData map[string]*documentContent, flags int) (*Dataset, error) {
keys := make([]string, 0, len(pageData))
for k := range pageData {
keys = append(keys, k)
}
sort.Strings(keys)
d := &Dataset{}
d.keys = keys
if flags&flagInitChangelog != 0 {
err, changelog, hasChangelog := buildChangelog(pageData)
if err != nil {
return nil, err
}
d.Changelog = changelog
d.HasChangelog = hasChangelog
}
if flags&flagInitTasks != 0 {
err, tasks, hasTasks := buildTasksTable(pageData, false)
if err != nil {
return nil, err
}
d.Tasks = tasks
d.HasTasks = hasTasks
}
if flags&flagInitDocuments != 0 {
documents := ""
for _, k := range d.keys {
d.HasDocuments = true
p := pageData[k].meta
documents = documents + convertToHtml(getAdjustedContent(p.Absolute))
}
d.Documents = documents
}
d.Config = config
d.Created = time.Now()
d.CreatedFormat = time.Now().Format(config.Locale.DateFormat)
return d, nil
}
package main
const exitOK = 0
const exitCodeCatchAll = 1
// language: html
const defaultHTMLTemplate = `<!DOCTYPE html>
{{ if .HasLanguage }}
<html lang="{{.Language}}">
{{ else }}
<html>
{{ end }}
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name='viewport'
content='width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no'>
<title>{{.Title}}</title>
{{if .HasCanonical }}
<link rel="canonical" href="{{.Canonical}}">
{{end}}
{{if .HasDescription }}
<meta name="description" content="{{.Description}}">
{{end}}
<style>
body {
padding: 0px;
margin: 0px;
}
</style>
</head>
<body>
{{ if .HasBody }}{{.Body}}{{ end }}
</body>
</html>`
const defaultPDFTemplate = `
<!DOCTYPE html>
<html lang="de">
<head>
<body>
---
block-headings: true
...
{{ if .HasChangelog }}
## Changelog
{{.Changelog}}
{{ end}}{{ if .HasTasks }}
## Tasks
{{.Tasks}}
{{ end}}{{ if .HasDocuments }}
## Documents
{{.Documents}}
{{ end}}
</body>
</html>
`
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment