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

chore: commit save point

parent 7693af6c
No related branches found
No related tags found
No related merge requests found
......@@ -3,6 +3,7 @@
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/documentation-manager.iml" filepath="$PROJECT_DIR$/.idea/documentation-manager.iml" />
<module fileurl="file://$PROJECT_DIR$/../../../schukai/manual/manual.iml" filepath="$PROJECT_DIR$/../../../schukai/manual/manual.iml" />
</modules>
</component>
</project>
\ No newline at end of file
......@@ -61,4 +61,8 @@ func runDocumentPDF(command *flags.Command) {
document.BuildPDF(env)
if environment.State.HasErrorsWarningsOrMessages() {
environment.PrintMessages()
}
}
......@@ -21,4 +21,5 @@ type document struct {
Created LocaleTime `yaml:"Created"`
LastUpdate LocaleTime `yaml:"Last Update"`
Language string `yaml:"Language"`
Level int `yaml:"Level"`
}
......@@ -25,8 +25,26 @@ func (m SourceFileMap) findByRelativePath(rel string) *SourceFile {
return nil
}
func (m SourceFileMap) findByHash(hash string) *SourceFile {
for _, v := range m {
if v.hash == hash {
return v
break
}
}
return nil
}
func buildFileMap(files []*SourceFile) (SourceFileMap, []string) {
sort.Slice(files, func(i, j int) bool {
if files[i].level == files[j].level {
return files[i].relSourcePath < files[j].relSourcePath
}
return files[i].level < files[j].level
})
keys := make([]string, 0, len(files))
mapFiles := make(map[string]*SourceFile)
for _, file := range files {
......@@ -34,8 +52,6 @@ func buildFileMap(files []*SourceFile) (SourceFileMap, []string) {
mapFiles[file.absSourcePath] = file
}
sort.Strings(keys)
return mapFiles, keys
}
......
......@@ -3,9 +3,9 @@ package document
import (
"fmt"
"gitlab.schukai.com/oss/utilities/documentation-manager/environment"
"gitlab.schukai.com/oss/utilities/documentation-manager/translations"
"gitlab.schukai.com/oss/utilities/documentation-manager/utils"
"io/ioutil"
"net/url"
"os"
"path"
"path/filepath"
......@@ -44,14 +44,21 @@ func NewPdfDataset(env BuildPdfEnvironment) (*PdfDataset, error) {
for _, key := range keys {
text := mapFiles[key].textMeta.text
text = convertHeadlines(text, mapFiles[key].level)
text, s1Map := utils.MaskCodeBlocks(text, mapFiles[key].relSourcePath, 3)
text, s2Map := utils.MaskCodeBlocks(text, mapFiles[key].relSourcePath, 1)
text = convertHeadlines(text, mapFiles[key].level, mapFiles[key].textMeta.meta.Level)
text = convertAwesomeBoxes(text)
text = convertImages(text, mapFiles[key].baseDir)
text = convertCircledNumbers(text)
text = replaceKbd(text)
text = replaceRelativeLinks(text, mapFiles[key].hash, mapFiles)
text = replaceRelativeLinks(text, mapFiles[key], mapFiles)
text = utils.InsertCodeBlocks(text, s2Map)
text = utils.InsertCodeBlocks(text, s1Map)
docs = append(docs, "\\newpage"+text)
docs = append(docs, "\\newpage{}"+text)
}
d.Documents = strings.Join(docs, "\n")
......@@ -115,9 +122,9 @@ func BuildPDF(env BuildPdfEnvironment) error {
}
func replaceRelativeLinks(content, hash string, fileMap SourceFileMap) string {
func replaceRelativeLinks(content string, f *SourceFile, fileMap SourceFileMap) string {
label := "link_" + hash
label := "link_" + f.hash
content = "\\hypertarget{" + label + "}{ } \n" + strings.TrimSpace(content) + "\n"
regEx := regexp.MustCompile(`(?:^|[^!])(?P<match>\[(?P<label>[^]]*)\]\((?P<path>[^)]*)\))`)
......@@ -135,15 +142,32 @@ func replaceRelativeLinks(content, hash string, fileMap SourceFileMap) string {
}
if filepath.IsAbs(result["path"]) {
//environment.State.AddWarning(translations.T.Sprintf("Absolute path not found: %s", result["path"]))
continue
}
if utils.IsUrl(result["path"]) {
continue
}
d := filepath.Dir(f.relSourcePath)
p := filepath.Join(d, result["path"])
p = strings.Split(p, "#")[0]
ext := filepath.Ext(p)
if ext != ".md" && ext != ".markdown" {
environment.State.AddWarning(translations.T.Sprintf("file extension %s, in file %s, not supported for relative links", ext, f.absSourcePath))
continue
}
s := fileMap.findByRelativePath(result["path"])
s := fileMap.findByRelativePath(p)
if s == nil {
environment.State.AddWarning(translations.T.Sprintf("relative path %s, in file %s, cannot be resolved", result["path"], f.absSourcePath))
continue
}
replace := "\\hyperlink{link_" + s.hash + "}{" + result["label"] + "}"
replace := "\\hyperlink{link_" + s.hash + "}{" + escapeLatexSpecialChars(result["label"]) + "}"
content = strings.Replace(content, result["match"], replace, -1)
}
......@@ -170,11 +194,6 @@ end
}
func isUrl(str string) bool {
u, err := url.Parse(str)
return err == nil && u.Scheme != "" && u.Host != ""
}
type foundedTitleInfoStruct struct {
level int
match string
......@@ -183,15 +202,36 @@ type foundedTitleInfoStruct struct {
type foundedTitleInfo []foundedTitleInfoStruct
func convertHeadlines(content string, level int) string {
func convertHeadlines(content string, level, startLevel int) string {
d := 0
info, smallestLevelInTheDoc := calculateLevel(content)
if startLevel == 0 {
d = level - smallestLevelInTheDoc
} else {
d = startLevel - 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 calculateLevel(content string) (foundedTitleInfo, int) {
regEx := regexp.MustCompile(`(?m)^(?P<match>(?P<level>#+)\s+(?P<title>[^\n]*))`)
matches := regEx.FindAllStringSubmatch(content, -1)
info := foundedTitleInfo{}
if matches == nil {
return content
return info, -1
}
info := foundedTitleInfo{}
smallestLevelInTheDoc := 999
for _, match := range matches {
......@@ -214,18 +254,7 @@ func convertHeadlines(content string, level int) string {
}
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
return info, smallestLevelInTheDoc
}
// https://ftp.gwdg.de/pub/ctan/graphics/awesomebox/awesomebox.pdf
......@@ -350,7 +379,7 @@ func convertImages(content string, absolute string) string {
}
}
if isUrl(result["path"]) {
if utils.IsUrl(result["path"]) {
continue
}
......
......@@ -47,6 +47,10 @@ func evaluateDocumentContent(content []byte) (error, textMetaStruct) {
meta := ""
text := ""
if strings.Index(origin, "---") == 0 {
origin = "\n" + origin
}
before, remaining, found := strings.Cut(origin, "\n---\n")
if !found {
......
......@@ -33,6 +33,10 @@ func init() {
State = &stateStruct{}
}
func (e *stateStruct) HasErrorsWarningsOrMessages() bool {
return len(e.errors) > 0 || len(e.warnings) > 0 || len(e.messages) > 0
}
func (e *stateStruct) SetParser(parser *flags.Parser) *stateStruct {
e.parser = parser
return e
......
package utils
import "strings"
import (
"crypto/md5"
"fmt"
"gitlab.schukai.com/oss/utilities/documentation-manager/environment"
"gitlab.schukai.com/oss/utilities/documentation-manager/translations"
"regexp"
"strconv"
"strings"
)
func Substring(input string, start int, length int) string {
runes := []rune(input)
if start >= len(runes) {
return ""
}
if start+length > len(runes) {
length = len(runes) - start
}
return string(runes[start : start+length])
}
func TrimLines(s string) string {
......@@ -34,3 +56,59 @@ func TrimQuotes(s string) string {
}
return s
}
func InsertCodeBlocks(s string, m map[string]string) string {
for k, v := range m {
s = strings.Replace(s, k, v, -1)
}
return s
}
func MaskCodeBlocks(s, file string, count int) (string, map[string]string) {
const marker = "__X42_2342XXY_CCX_"
s = strings.Replace(s, "\\`", marker, -1)
regEx := regexp.MustCompile(`(?m)(?P<match>((?P<open>[\x60]{` + strconv.Itoa(count) + `})(?P<code>[^\x60]+))(?P<close>[\x60]{` + strconv.Itoa(count) + `}))`)
matches := regEx.FindAllStringSubmatch(s, -1)
m := map[string]string{}
for _, match := range matches {
result := make(map[string]string)
for i, name := range regEx.SubexpNames() {
if i != 0 && name != "" {
result[name] = match[i]
}
}
if result["open"] != result["close"] {
environment.State.AddWarning(translations.T.Sprintf("Code block %s, in file %s, is not closed", result["match"], file))
continue
}
//i := strings.Index(s, result["match"])
//if i != -1 {
// q2 := Substring(s, i-20, 40)
// fmt.Println(q2)
// q := Substring(s, i-1, 1)
// if q == "\"" {
// continue
// }
//}
k := fmt.Sprintf("%x", md5.Sum([]byte(result["code"])))
m[k] = result["match"]
s = strings.Replace(s, result["match"], k, -1)
}
s = strings.Replace(s, marker, "\\`", -1)
return s, m
}
package utils
import (
"os"
"path/filepath"
"testing"
)
func TestMaskCodeBlocks(t *testing.T) {
tables := []struct {
input string
file string
count int
expected int
}{
{"/development/testing/asstes/code1.md", "code1.md", 3, 9},
}
for _, table := range tables {
p, _ := os.Getwd()
p = filepath.Dir(p) // go to parent directory
p = filepath.Dir(p) // go to parent directory
p = filepath.Dir(p) // go to parent directory
p = filepath.Join(p, table.input)
code, err := os.ReadFile(p)
if err != nil {
t.Errorf("Error reading file %s", table.input)
}
s, m := MaskCodeBlocks(string(code), table.file, table.count)
if len(m) != table.expected {
t.Errorf("Expected %d code blocks, got %d", table.expected, len(m))
}
if s == string(code) {
t.Errorf("Expected %s, got %s", string(code), s)
}
}
}
func TestSubstring(t *testing.T) {
tables := []struct {
input string
start int
length int
expected string
}{
{"abcdefg", 0, 0, ""},
{"abcdefg", 0, 1, "a"},
{"abcdefg", 0, 2, "ab"},
{"abcdefg", 0, 3, "abc"},
{"abcdefg", 0, 4, "abcd"},
{"abcdefg", 0, 5, "abcde"},
{"abcdefg", 0, 6, "abcdef"},
{"abcdefg", 0, 7, "abcdefg"},
{"abcdefg", 0, 8, "abcdefg"},
{"abcdefg", 0, 9, "abcdefg"},
{"abcdefg", 1, 6, "bcdefg"},
{"abcdefg", 3, 6, "defg"},
{"abcdefg", 3, 5, "defg"},
{"abcdefg", 3, 4, "defg"},
{"abcdefg", 3, 3, "def"},
{"abcdefg", 3, 2, "de"},
{"abcdefg", 3, 1, "d"},
{"abcdefg", 3, 0, ""},
} // end of tables
for _, table := range tables {
actual := Substring(table.input, table.start, table.length)
if actual != table.expected {
t.Errorf("Substring(%s, %d, %d) = %s, expected %s", table.input, table.start, table.length, actual, table.expected)
}
}
}
package utils
import "net/url"
func IsUrl(str string) bool {
u, err := url.Parse(str)
return err == nil && u.Scheme != "" && u.Host != ""
}
File deleted
code samples
Source text can be represented either by indentation or by single quotes.
If the marking is done with single quotes, the language to be used should be labeled after the
Quotation marks are displayed.
\`\`\`php
\`\`\`javascript
When using indentation, the language can be marked with three colons `:::php`
If no language is selected, the script tries to guess the language.
If no syntax highlighting is to take place, this must be specified explicitly with `nohighlight`.
\`\`\`nohighlight
Documentation of code examples should always be on executable
code based. For this reason, a program should always be developed independently
will. The integration takes place via this marking: ![](imagecomment1.png)
__Example__
In the example, the sample file `test.php` is created with the following code.
```php
<?php
a=0;
a+=1;
echo a;
```
If you want to add the first and second line to the documentation and then
the third line, you have to enter the following markings in the file.
```php
<?php
EXAMPLE:START
SNIPPET:PART1:START
a=0;
a+=1;
SNIPPET:PART1:END
SNIPPET:PART2:START
echo a;
SNIPPET:PART2:END
EXAMPLE:END
```
The integration into the documentation then takes place as follows:
![](imagecomment2.png)
```php
example 1
```
and for the second part
![](imagecomment3.png)
```php
example2
```
The __result__ is then:
a=0;
a+=1;
and
echo a;
tabs
Tabs can be used to integrate examples for different languages into a code block.
``` bash tab="Bash"
!binbash
echo "Hello world!"
```
```c tab="C"
include <stdio.h>
int main(void) {
printf("Hello world!\n");
}
```
``` c++ tab="C++"
include <iostream>
int main() {
std::cout << "Hello world!" << std::endl;
return 0;
}
```
```c tab="C"
using System;
class Program {
static void Main(string[] args) {
Console. WriteLine("Hello world!");
}
}
```
``` bash tab="Bash"
!binbash
echo "Hello world!"
```
```c tab="C"
include <stdio.h>
int main(void) {
printf("Hello world!\n");
}
```
``` c++ tab="C++"
include <iostream>
int main() {
std::cout << "Hello world!" << std::endl;
return 0;
}
```
```c tab="C"
using System;
class Program {
static void Main(string[] args) {
Console. WriteLine("Hello world!");
}
}
```
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment