Add support for code appendices: enable code blocks with language labels, line-number gutter, and directive-based integration.
This commit is contained in:
Generated
+6
-7
@@ -4,14 +4,10 @@
|
|||||||
<option name="autoReloadType" value="ALL" />
|
<option name="autoReloadType" value="ALL" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="c64f46d5-641a-468c-8fc1-94edec1f2deb" name="Changes" comment="Refactor PDF content rendering: improve list indentation logic, add numbered code block rendering with gutter, and update text wrapping alignment.">
|
<list default="true" id="c64f46d5-641a-468c-8fc1-94edec1f2deb" name="Changes" comment="Update MarkdownToIHKChemnitz: modify core functionality for improved PDF rendering">
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/MarkdownToIHKChemnits" beforeDir="false" afterPath="$PROJECT_DIR$/MarkdownToIHKChemnits" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/MarkdownToIHKChemnits" beforeDir="false" afterPath="$PROJECT_DIR$/MarkdownToIHKChemnits" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/diagram.go" beforeDir="false" afterPath="$PROJECT_DIR$/diagram.go" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/main.go" beforeDir="false" afterPath="$PROJECT_DIR$/main.go" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/markdown_parser.go" beforeDir="false" afterPath="$PROJECT_DIR$/markdown_parser.go" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/markdown_parser.go" beforeDir="false" afterPath="$PROJECT_DIR$/markdown_parser.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/pdf_content.go" beforeDir="false" afterPath="$PROJECT_DIR$/pdf_content.go" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/pdf_pages.go" beforeDir="false" afterPath="$PROJECT_DIR$/pdf_pages.go" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/pdf_pages.go" beforeDir="false" afterPath="$PROJECT_DIR$/pdf_pages.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/pdf_renderer.go" beforeDir="false" afterPath="$PROJECT_DIR$/pdf_renderer.go" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/pdf_renderer.go" beforeDir="false" afterPath="$PROJECT_DIR$/pdf_renderer.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/projektarbeit.pdf" beforeDir="false" afterPath="$PROJECT_DIR$/projektarbeit.pdf" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/projektarbeit.pdf" beforeDir="false" afterPath="$PROJECT_DIR$/projektarbeit.pdf" afterDir="false" />
|
||||||
@@ -23,7 +19,7 @@
|
|||||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
</component>
|
</component>
|
||||||
<component name="EmbeddingIndexingInfo">
|
<component name="EmbeddingIndexingInfo">
|
||||||
<option name="cachedIndexableFilesCount" value="22" />
|
<option name="cachedIndexableFilesCount" value="23" />
|
||||||
<option name="fileBasedEmbeddingIndicesEnabled" value="true" />
|
<option name="fileBasedEmbeddingIndicesEnabled" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="GOROOT" url="file:///usr/lib/go" />
|
<component name="GOROOT" url="file:///usr/lib/go" />
|
||||||
@@ -103,7 +99,10 @@
|
|||||||
<MESSAGE value="Remove outdated `toc_pages.txt`, add new Go modules for IHK Chemnitz PDF rendering including diagrams, tables, and TOC functionality." />
|
<MESSAGE value="Remove outdated `toc_pages.txt`, add new Go modules for IHK Chemnitz PDF rendering including diagrams, tables, and TOC functionality." />
|
||||||
<MESSAGE value="Refactor PDF content rendering: improve list indentation logic, add numbered code block rendering with gutter, and update text wrapping alignment." />
|
<MESSAGE value="Refactor PDF content rendering: improve list indentation logic, add numbered code block rendering with gutter, and update text wrapping alignment." />
|
||||||
<MESSAGE value="Add table annex handling, update diagram rendering with configurable Kroki URL, and improve Markdown directive parsing" />
|
<MESSAGE value="Add table annex handling, update diagram rendering with configurable Kroki URL, and improve Markdown directive parsing" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="Add table annex handling, update diagram rendering with configurable Kroki URL, and improve Markdown directive parsing" />
|
<MESSAGE value="Add new features: diagram rendering via Kroki, table handling improvements including appendices, and Docker Compose setup for self-hosted Kroki." />
|
||||||
|
<MESSAGE value="Add support for appendices: landscape diagrams, tables, and images; implement Kroki URL configurability; enhance directive parsing logic." />
|
||||||
|
<MESSAGE value="Update MarkdownToIHKChemnitz: modify core functionality for improved PDF rendering" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="Update MarkdownToIHKChemnitz: modify core functionality for improved PDF rendering" />
|
||||||
</component>
|
</component>
|
||||||
<component name="XDebuggerManager">
|
<component name="XDebuggerManager">
|
||||||
<breakpoint-manager>
|
<breakpoint-manager>
|
||||||
|
|||||||
Binary file not shown.
@@ -47,6 +47,8 @@ type parserState struct {
|
|||||||
nextCodeIsAppendix bool
|
nextCodeIsAppendix bool
|
||||||
nextAppendixLandscape bool // set by @AnhangUMLQuer: — landscape for diagram appendix
|
nextAppendixLandscape bool // set by @AnhangUMLQuer: — landscape for diagram appendix
|
||||||
appendixTitle string
|
appendixTitle string
|
||||||
|
nextCodeBlockAppendix bool // set by @AnhangCode: — next non-diagram code block → appendix
|
||||||
|
codeBlockAppendixTitle string
|
||||||
nextTableCaption string // set by @Tabelle: directive
|
nextTableCaption string // set by @Tabelle: directive
|
||||||
nextTableIsAppendix bool // set by @TabelleAnhang: or @TabelleAnhangQuer:
|
nextTableIsAppendix bool // set by @TabelleAnhang: or @TabelleAnhangQuer:
|
||||||
nextTableIsLandscape bool // set by @TabelleAnhangQuer:
|
nextTableIsLandscape bool // set by @TabelleAnhangQuer:
|
||||||
@@ -142,6 +144,12 @@ func RenderAST(doc ast.Node, content []byte, r *IHKRenderer) error {
|
|||||||
}
|
}
|
||||||
// Fall through: render as plain code block on error
|
// Fall through: render as plain code block on error
|
||||||
}
|
}
|
||||||
|
if state.nextCodeBlockAppendix {
|
||||||
|
r.AddCodeAppendix(state.codeBlockAppendixTitle, lang, code)
|
||||||
|
state.nextCodeBlockAppendix = false
|
||||||
|
state.codeBlockAppendixTitle = ""
|
||||||
|
return ast.WalkSkipChildren, nil
|
||||||
|
}
|
||||||
// Render as a numbered code block (gutter + monospace body).
|
// Render as a numbered code block (gutter + monospace body).
|
||||||
r.RenderCodeBlock(lang, code)
|
r.RenderCodeBlock(lang, code)
|
||||||
return ast.WalkSkipChildren, nil
|
return ast.WalkSkipChildren, nil
|
||||||
@@ -264,6 +272,10 @@ func handleDirectives(text string, state *parserState, r *IHKRenderer) bool {
|
|||||||
case strings.HasPrefix(line, "@Quelle:"):
|
case strings.HasPrefix(line, "@Quelle:"):
|
||||||
r.AddSource(strings.TrimSpace(strings.TrimPrefix(line, "@Quelle:")))
|
r.AddSource(strings.TrimSpace(strings.TrimPrefix(line, "@Quelle:")))
|
||||||
handled = true
|
handled = true
|
||||||
|
case strings.HasPrefix(line, "@AnhangCode:"):
|
||||||
|
state.nextCodeBlockAppendix = true
|
||||||
|
state.codeBlockAppendixTitle = strings.TrimSpace(strings.TrimPrefix(line, "@AnhangCode:"))
|
||||||
|
handled = true
|
||||||
case strings.HasPrefix(line, "@Anhang:"):
|
case strings.HasPrefix(line, "@Anhang:"):
|
||||||
r.AddAppendix(strings.TrimSpace(strings.TrimPrefix(line, "@Anhang:")))
|
r.AddAppendix(strings.TrimSpace(strings.TrimPrefix(line, "@Anhang:")))
|
||||||
handled = true
|
handled = true
|
||||||
|
|||||||
+2
-1
@@ -171,8 +171,9 @@ func (r *IHKRenderer) RenderAppendices() {
|
|||||||
case AppendixKindImage:
|
case AppendixKindImage:
|
||||||
r.renderAppendixImage(app.Path)
|
r.renderAppendixImage(app.Path)
|
||||||
case AppendixKindTable:
|
case AppendixKindTable:
|
||||||
// Render without numbering/recording; the annex header already identifies the table.
|
|
||||||
r.renderTableBody(app.TableData, "")
|
r.renderTableBody(app.TableData, "")
|
||||||
|
case AppendixKindCode:
|
||||||
|
r.RenderCodeBlock(app.Lang, app.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
if app.Landscape {
|
if app.Landscape {
|
||||||
|
|||||||
+14
-3
@@ -38,9 +38,7 @@ const (
|
|||||||
dinSpaceAfterHeading = dinLineHtBody // ≈ 6.35 mm
|
dinSpaceAfterHeading = dinLineHtBody // ≈ 6.35 mm
|
||||||
dinSpaceAfterParagraph = 4.0 // between body paragraphs
|
dinSpaceAfterParagraph = 4.0 // between body paragraphs
|
||||||
|
|
||||||
// List items use tighter line spacing than body text (1.2× instead of 1.5×).
|
dinLineHtList = dinLineHtBody // 1.5× IHK standard, same as body text
|
||||||
// This keeps lists compact while remaining legible at 12 pt.
|
|
||||||
dinLineHtList = 5.0 // 12 pt × 1.2 ≈ 5.08 mm, rounded to 5.0
|
|
||||||
dinSpaceAfterList = 3.0 // gap inserted after the outermost list exits
|
dinSpaceAfterList = 3.0 // gap inserted after the outermost list exits
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -50,6 +48,7 @@ type AppendixKind int
|
|||||||
const (
|
const (
|
||||||
AppendixKindImage AppendixKind = iota
|
AppendixKindImage AppendixKind = iota
|
||||||
AppendixKindTable
|
AppendixKindTable
|
||||||
|
AppendixKindCode
|
||||||
)
|
)
|
||||||
|
|
||||||
// Appendix holds the content for one annex entry.
|
// Appendix holds the content for one annex entry.
|
||||||
@@ -59,6 +58,8 @@ type Appendix struct {
|
|||||||
Title string
|
Title string
|
||||||
Path string // image path (Kind == AppendixKindImage)
|
Path string // image path (Kind == AppendixKindImage)
|
||||||
TableData [][]string // table rows (Kind == AppendixKindTable)
|
TableData [][]string // table rows (Kind == AppendixKindTable)
|
||||||
|
Lang string // language label (Kind == AppendixKindCode)
|
||||||
|
Code string // source code (Kind == AppendixKindCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IHKRenderer is the central PDF generator for IHK Chemnitz project documentation.
|
// IHKRenderer is the central PDF generator for IHK Chemnitz project documentation.
|
||||||
@@ -183,6 +184,16 @@ func (r *IHKRenderer) AddTableAppendix(title string, data [][]string) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddCodeAppendix registers a source-code annex rendered with line-number gutter.
|
||||||
|
func (r *IHKRenderer) AddCodeAppendix(title, lang, code string) {
|
||||||
|
r.appendices = append(r.appendices, Appendix{
|
||||||
|
Kind: AppendixKindCode,
|
||||||
|
Title: title,
|
||||||
|
Lang: lang,
|
||||||
|
Code: code,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// AddLandscapeAppendix registers an image annex in "Title | /path/to/image" format
|
// AddLandscapeAppendix registers an image annex in "Title | /path/to/image" format
|
||||||
// that will be rendered on a landscape A4 page with 15 mm symmetric margins.
|
// that will be rendered on a landscape A4 page with 15 mm symmetric margins.
|
||||||
func (r *IHKRenderer) AddLandscapeAppendix(titlePath string) {
|
func (r *IHKRenderer) AddLandscapeAppendix(titlePath string) {
|
||||||
|
|||||||
Binary file not shown.
@@ -282,6 +282,38 @@ eine konfigurierbare Spaltenbreite für Tabellen umfassen.
|
|||||||
| Bildanhang | @Anhang: Titel \| Pfad | Fügt ein Bild als nummerierte Anlage in den Anhang ein |
|
| Bildanhang | @Anhang: Titel \| Pfad | Fügt ein Bild als nummerierte Anlage in den Anhang ein |
|
||||||
| Diagrammanhang | @AnhangUML: Titel | Rendert den folgenden Mermaid/PlantUML-Block als Anlage |
|
| Diagrammanhang | @AnhangUML: Titel | Rendert den folgenden Mermaid/PlantUML-Block als Anlage |
|
||||||
|
|
||||||
|
@AnhangCode: Implementierung – Tabellen-Renderer (prepareRow)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *IHKRenderer) prepareRow(rawCells []string, numCols int,
|
||||||
|
colW, lineHt float64, bold bool) tableRowData {
|
||||||
|
|
||||||
|
r.pdf.SetFont("Helvetica", map[bool]string{true: "B", false: ""}[bold], dinFontCaption)
|
||||||
|
|
||||||
|
cells := make([][]string, numCols)
|
||||||
|
maxLines := 0
|
||||||
|
for j := 0; j < numCols; j++ {
|
||||||
|
raw := ""
|
||||||
|
if j < len(rawCells) {
|
||||||
|
raw = rawCells[j]
|
||||||
|
}
|
||||||
|
split := r.pdf.SplitLines([]byte(r.tr(raw)), colW-2)
|
||||||
|
lines := make([]string, len(split))
|
||||||
|
for k, b := range split {
|
||||||
|
lines[k] = string(b)
|
||||||
|
}
|
||||||
|
if len(lines) == 0 {
|
||||||
|
lines = []string{""}
|
||||||
|
}
|
||||||
|
cells[j] = lines
|
||||||
|
if len(lines) > maxLines {
|
||||||
|
maxLines = len(lines)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tableRowData{cells: cells, height: float64(maxLines) * lineHt}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
@AnhangUML: Systemarchitektur – Datenflussdiagramm
|
@AnhangUML: Systemarchitektur – Datenflussdiagramm
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
|
|||||||
Reference in New Issue
Block a user