add renderers
This commit is contained in:
97
CHECKLIST.md
Normal file
97
CHECKLIST.md
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
# RST Feature Implementation Checklist
|
||||||
|
|
||||||
|
## ✅ Basic Document Structure
|
||||||
|
- [x] Headings/Sections
|
||||||
|
- [x] Paragraphs
|
||||||
|
- [x] Nesting/Hierarchy support
|
||||||
|
- [x] Basic content management
|
||||||
|
- [ ] Document title/subtitle
|
||||||
|
- [ ] Transitions (horizontal lines)
|
||||||
|
|
||||||
|
## ✅ Text Styling
|
||||||
|
- [x] Strong (bold) text
|
||||||
|
- [x] Emphasis (italic) text
|
||||||
|
- [ ] Interpreted text
|
||||||
|
- [ ] Inline literals
|
||||||
|
|
||||||
|
## ✅ Lists
|
||||||
|
- [x] Ordered lists
|
||||||
|
- [x] Unordered lists
|
||||||
|
- [x] List items
|
||||||
|
- [ ] Definition lists
|
||||||
|
- [ ] Field lists
|
||||||
|
- [ ] Option lists
|
||||||
|
|
||||||
|
## ✅ Links and References
|
||||||
|
- [x] Hyperlinks (explicit)
|
||||||
|
- [ ] Anonymous hyperlinks
|
||||||
|
- [ ] Internal references
|
||||||
|
- [ ] Footnotes
|
||||||
|
- [ ] Citations
|
||||||
|
|
||||||
|
## ✅ Code Blocks
|
||||||
|
- [x] Basic code blocks
|
||||||
|
- [x] Language specification
|
||||||
|
- [x] Line number support
|
||||||
|
- [ ] Code block options
|
||||||
|
- [ ] Line highlighting
|
||||||
|
|
||||||
|
## ✅ Tables
|
||||||
|
- [x] Basic table structure
|
||||||
|
- [x] Headers
|
||||||
|
- [x] Rows
|
||||||
|
- [ ] Grid tables
|
||||||
|
- [ ] Simple tables
|
||||||
|
- [ ] CSV tables
|
||||||
|
|
||||||
|
## ✅ Directives
|
||||||
|
- [x] Basic directive support
|
||||||
|
- [x] Directive arguments
|
||||||
|
- [x] Raw content handling
|
||||||
|
- [ ] Image directives
|
||||||
|
- [ ] Figure directives
|
||||||
|
- [ ] Include directives
|
||||||
|
- [ ] Admonitions
|
||||||
|
- [ ] Topic directives
|
||||||
|
- [ ] Sidebar directives
|
||||||
|
|
||||||
|
## ✅ Metadata
|
||||||
|
- [x] Basic metadata support
|
||||||
|
- [x] Key-value pairs
|
||||||
|
- [ ] Document metadata
|
||||||
|
- [ ] Role definitions
|
||||||
|
|
||||||
|
## Missing Features
|
||||||
|
### Document Components
|
||||||
|
- [ ] Block quotes
|
||||||
|
- [ ] Doctest blocks
|
||||||
|
- [ ] Line blocks
|
||||||
|
- [ ] Comments
|
||||||
|
|
||||||
|
### Advanced Features
|
||||||
|
- [ ] Substitutions
|
||||||
|
- [ ] Roles
|
||||||
|
- [ ] Math support
|
||||||
|
- [ ] Custom roles
|
||||||
|
- [ ] Raw input
|
||||||
|
- [ ] Container directives
|
||||||
|
|
||||||
|
### Specialized Elements
|
||||||
|
- [ ] Tables of contents
|
||||||
|
- [ ] Index entries
|
||||||
|
- [ ] Bibliography
|
||||||
|
- [ ] Glossary
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
The current implementation provides a solid foundation with:
|
||||||
|
- A flexible node-based architecture
|
||||||
|
- Strong type hierarchy
|
||||||
|
- Clean interface definitions
|
||||||
|
- Good support for basic RST features
|
||||||
|
- Extensible structure for future additions
|
||||||
|
|
||||||
|
## Development Status
|
||||||
|
- Core Features: ~40% complete
|
||||||
|
- Basic Text Processing: ~70% complete
|
||||||
|
- Advanced Features: ~20% complete
|
||||||
|
- Overall Completion: ~45%
|
7
Makefile
Normal file
7
Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
docs: format
|
||||||
|
find pkg -type d -exec bash -c "ls {}/*.go && godocdown -o ./{}/doc.md ./{}" \;
|
||||||
|
|
||||||
|
format:
|
||||||
|
find . -name '*.go' -exec gofumpt -w -s {} \;
|
@ -1,6 +1,7 @@
|
|||||||
# go-rst
|
# go-rst
|
||||||
|
|
||||||
A Go library for parsing and rendering reStructuredText (RST) documents with translation support.
|
A Go library for parsing and rendering reStructuredText (RST) documents with translation support.
|
||||||
|
Supports only a subset of restructuredText for now, but relatively easy to expand compared to other attempts.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
1
go.mod
1
go.mod
@ -3,6 +3,7 @@ module i2pgit.org/idk/go-rst
|
|||||||
go 1.23.1
|
go 1.23.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/jung-kurt/gofpdf v1.16.2
|
||||||
github.com/leonelquinteros/gotext v1.7.0
|
github.com/leonelquinteros/gotext v1.7.0
|
||||||
github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4
|
github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4
|
||||||
)
|
)
|
||||||
|
11
go.sum
11
go.sum
@ -1,10 +1,21 @@
|
|||||||
|
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||||
|
github.com/jung-kurt/gofpdf v1.16.2 h1:jgbatWHfRlPYiK85qgevsZTHviWXKwB1TTiKdz5PtRc=
|
||||||
|
github.com/jung-kurt/gofpdf v1.16.2/go.mod h1:1hl7y57EsiPAkLbOwzpzqgx1A30nQCk/YmFV8S2vmK0=
|
||||||
github.com/leonelquinteros/gotext v1.7.0 h1:jcJmF4AXqyamP7vuw2MMIKs+O3jAEmvrc5JQiI8Ht/8=
|
github.com/leonelquinteros/gotext v1.7.0 h1:jcJmF4AXqyamP7vuw2MMIKs+O3jAEmvrc5JQiI8Ht/8=
|
||||||
github.com/leonelquinteros/gotext v1.7.0/go.mod h1:qJdoQuERPpccw7L70uoU+K/BvTfRBHYsisCQyFLXyvw=
|
github.com/leonelquinteros/gotext v1.7.0/go.mod h1:qJdoQuERPpccw7L70uoU+K/BvTfRBHYsisCQyFLXyvw=
|
||||||
|
github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4 h1:0sw0nJM544SpsihWx1bkXdYLQDlzRflMgFJQ4Yih9ts=
|
github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4 h1:0sw0nJM544SpsihWx1bkXdYLQDlzRflMgFJQ4Yih9ts=
|
||||||
github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4/go.mod h1:+ccdNT0xMY1dtc5XBxumbYfOUhmduiGudqaDgD2rVRE=
|
github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4/go.mod h1:+ccdNT0xMY1dtc5XBxumbYfOUhmduiGudqaDgD2rVRE=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
32
main.go
32
main.go
@ -15,7 +15,8 @@ func main() {
|
|||||||
// CLI flags
|
// CLI flags
|
||||||
rstFile := flag.String("rst", "", "Input RST file path")
|
rstFile := flag.String("rst", "", "Input RST file path")
|
||||||
poFile := flag.String("po", "", "Input PO file path for translations")
|
poFile := flag.String("po", "", "Input PO file path for translations")
|
||||||
outFile := flag.String("out", "", "Output HTML file path")
|
outFileFormat := flag.String("out-format", "html", "Output file format (html, pdf, markdown)")
|
||||||
|
outFile := flag.String("out", "", "Output file path")
|
||||||
debug := flag.Bool("debug", false, "Enable debug logging")
|
debug := flag.Bool("debug", false, "Enable debug logging")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@ -65,17 +66,40 @@ func main() {
|
|||||||
log.Printf("Parsed %d nodes", len(nodes))
|
log.Printf("Parsed %d nodes", len(nodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch *outFileFormat {
|
||||||
|
case "html":
|
||||||
// Initialize HTML renderer
|
// Initialize HTML renderer
|
||||||
r := renderer.NewHTMLRenderer()
|
r := renderer.NewHTMLRenderer()
|
||||||
|
|
||||||
// Render HTML
|
// Render HTML
|
||||||
html := r.RenderPretty(nodes)
|
html := r.RenderPretty(nodes)
|
||||||
|
WriteRendered(*outFile, []byte(html))
|
||||||
|
case "pdf":
|
||||||
|
// Initialize PDF renderer
|
||||||
|
r := renderer.NewPDFRenderer()
|
||||||
|
// Render PDF
|
||||||
|
err := r.Render(nodes)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to render PDF: %v", err)
|
||||||
|
}
|
||||||
|
r.SaveToFile(*outFile)
|
||||||
|
case "markdown":
|
||||||
|
// Initialize Markdown renderer
|
||||||
|
r := renderer.NewMarkdownRenderer()
|
||||||
|
// Render Markdown
|
||||||
|
err := r.Render(nodes)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to render Markdown: %v", err)
|
||||||
|
}
|
||||||
|
WriteRendered(*outFile, []byte(r.String()))
|
||||||
|
}
|
||||||
|
fmt.Printf("Successfully converted %s to %s\n", *rstFile, *outFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteRendered(outFile string, doc []byte) {
|
||||||
// Write output
|
// Write output
|
||||||
err = ioutil.WriteFile(*outFile, []byte(html), 0o644)
|
err := ioutil.WriteFile(outFile, []byte(doc), 0o644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to write HTML file: %v", err)
|
log.Fatalf("Failed to write HTML file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Successfully converted %s to %s\n", *rstFile, *outFile)
|
|
||||||
}
|
}
|
||||||
|
469
pkg/nodes/doc.md
Normal file
469
pkg/nodes/doc.md
Normal file
@ -0,0 +1,469 @@
|
|||||||
|
# nodes
|
||||||
|
--
|
||||||
|
import "i2pgit.org/idk/go-rst/pkg/nodes"
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
#### func GetIndentedContent
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetIndentedContent(node Node) string
|
||||||
|
```
|
||||||
|
GetIndentedContent Utility function to get node content with proper indentation
|
||||||
|
|
||||||
|
#### type BaseNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
type BaseNode struct {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
BaseNode provides the basic implementation of the Node interface that other node
|
||||||
|
types can embed
|
||||||
|
|
||||||
|
#### func NewBaseNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewBaseNode(nodeType NodeType) *BaseNode
|
||||||
|
```
|
||||||
|
NewBaseNode creates a new BaseNode with the specified node type
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- nodeType: The type of node to create
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
- *BaseNode: A new base node instance
|
||||||
|
|
||||||
|
#### func (*BaseNode) AddChild
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *BaseNode) AddChild(child Node)
|
||||||
|
```
|
||||||
|
AddChild adds a child node to this node
|
||||||
|
|
||||||
|
#### func (*BaseNode) Children
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *BaseNode) Children() []Node
|
||||||
|
```
|
||||||
|
Children returns the node's child nodes
|
||||||
|
|
||||||
|
#### func (*BaseNode) Content
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *BaseNode) Content() string
|
||||||
|
```
|
||||||
|
Content returns the textual content of the node
|
||||||
|
|
||||||
|
#### func (*BaseNode) Level
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *BaseNode) Level() int
|
||||||
|
```
|
||||||
|
Level returns the nesting level of the node
|
||||||
|
|
||||||
|
#### func (*BaseNode) SetContent
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *BaseNode) SetContent(content string)
|
||||||
|
```
|
||||||
|
SetContent sets the node's textual content
|
||||||
|
|
||||||
|
#### func (*BaseNode) SetLevel
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *BaseNode) SetLevel(level int)
|
||||||
|
```
|
||||||
|
SetLevel sets the nesting level of the node
|
||||||
|
|
||||||
|
#### func (*BaseNode) Type
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *BaseNode) Type() NodeType
|
||||||
|
```
|
||||||
|
Type returns the NodeType
|
||||||
|
|
||||||
|
#### type CodeNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
type CodeNode struct {
|
||||||
|
*BaseNode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
CodeNode represents a code block
|
||||||
|
|
||||||
|
#### func NewCodeNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewCodeNode(language string, content string, lineNumbers bool) *CodeNode
|
||||||
|
```
|
||||||
|
NewCodeNode creates a new CodeNode with the given language and content
|
||||||
|
|
||||||
|
#### func (*CodeNode) Language
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *CodeNode) Language() string
|
||||||
|
```
|
||||||
|
Language returns the language of the code block
|
||||||
|
|
||||||
|
#### func (*CodeNode) LineNumbers
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *CodeNode) LineNumbers() bool
|
||||||
|
```
|
||||||
|
LineNumbers returns the line numbers flag of the code block
|
||||||
|
|
||||||
|
#### func (*CodeNode) String
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *CodeNode) String() string
|
||||||
|
```
|
||||||
|
String representation for debugging
|
||||||
|
|
||||||
|
#### type DirectiveNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
type DirectiveNode struct {
|
||||||
|
*BaseNode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
DirectiveNode represents an RST directive
|
||||||
|
|
||||||
|
#### func NewDirectiveNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewDirectiveNode(name string, args []string) *DirectiveNode
|
||||||
|
```
|
||||||
|
NewDirectiveNode creates a new DirectiveNode with the given name and arguments
|
||||||
|
|
||||||
|
#### func (*DirectiveNode) Arguments
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *DirectiveNode) Arguments() []string
|
||||||
|
```
|
||||||
|
Arguments returns the arguments of the directive
|
||||||
|
|
||||||
|
#### func (*DirectiveNode) Name
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *DirectiveNode) Name() string
|
||||||
|
```
|
||||||
|
Name returns the name of the directive
|
||||||
|
|
||||||
|
#### func (*DirectiveNode) RawContent
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *DirectiveNode) RawContent() string
|
||||||
|
```
|
||||||
|
RawContent returns the raw content of the directive
|
||||||
|
|
||||||
|
#### func (*DirectiveNode) SetRawContent
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *DirectiveNode) SetRawContent(content string)
|
||||||
|
```
|
||||||
|
SetRawContent sets the raw content of the directive
|
||||||
|
|
||||||
|
#### func (*DirectiveNode) String
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *DirectiveNode) String() string
|
||||||
|
```
|
||||||
|
String representation for debugging
|
||||||
|
|
||||||
|
#### type EmphasisNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
type EmphasisNode struct {
|
||||||
|
*BaseNode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
EmphasisNode represents emphasized text (italic)
|
||||||
|
|
||||||
|
#### func NewEmphasisNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewEmphasisNode(content string) *EmphasisNode
|
||||||
|
```
|
||||||
|
NewEmphasisNode creates a new EmphasisNode with the given content
|
||||||
|
|
||||||
|
#### type HeadingNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
type HeadingNode struct {
|
||||||
|
*BaseNode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
HeadingNode represents a section heading in RST
|
||||||
|
|
||||||
|
#### func NewHeadingNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewHeadingNode(content string, level int) *HeadingNode
|
||||||
|
```
|
||||||
|
NewHeadingNode creates a new HeadingNode with the given content and level
|
||||||
|
|
||||||
|
#### func (*HeadingNode) String
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *HeadingNode) String() string
|
||||||
|
```
|
||||||
|
String representations for debugging
|
||||||
|
|
||||||
|
#### type LinkNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
type LinkNode struct {
|
||||||
|
*BaseNode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
LinkNode represents a hyperlink
|
||||||
|
|
||||||
|
#### func NewLinkNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewLinkNode(text, url, title string) *LinkNode
|
||||||
|
```
|
||||||
|
NewLinkNode creates a new LinkNode with the given text, URL, and title
|
||||||
|
|
||||||
|
#### func (*LinkNode) String
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *LinkNode) String() string
|
||||||
|
```
|
||||||
|
String representation for debugging
|
||||||
|
|
||||||
|
#### func (*LinkNode) Title
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *LinkNode) Title() string
|
||||||
|
```
|
||||||
|
Title returns the URL of the link
|
||||||
|
|
||||||
|
#### func (*LinkNode) URL
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *LinkNode) URL() string
|
||||||
|
```
|
||||||
|
URL returns the URL of the link
|
||||||
|
|
||||||
|
#### type ListItemNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ListItemNode struct {
|
||||||
|
*BaseNode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
ListItemNode represents an individual list item
|
||||||
|
|
||||||
|
#### func NewListItemNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewListItemNode(content string) *ListItemNode
|
||||||
|
```
|
||||||
|
NewListItemNode creates a new ListItemNode with the given content
|
||||||
|
|
||||||
|
#### type ListNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ListNode struct {
|
||||||
|
*BaseNode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
ListNode represents an ordered or unordered list
|
||||||
|
|
||||||
|
#### func NewListNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewListNode(ordered bool) *ListNode
|
||||||
|
```
|
||||||
|
NewListNode creates a new ListNode with the given ordered flag
|
||||||
|
|
||||||
|
#### func (*ListNode) IsOrdered
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *ListNode) IsOrdered() bool
|
||||||
|
```
|
||||||
|
IsOrdered returns true if the list is ordered, false otherwise
|
||||||
|
|
||||||
|
#### func (*ListNode) String
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *ListNode) String() string
|
||||||
|
```
|
||||||
|
String representation for debugging
|
||||||
|
|
||||||
|
#### type MetaNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
type MetaNode struct {
|
||||||
|
*BaseNode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
MetaNode represents metadata information
|
||||||
|
|
||||||
|
#### func NewMetaNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewMetaNode(key, value string) *MetaNode
|
||||||
|
```
|
||||||
|
NewMetaNode creates a new MetaNode with the given key and value
|
||||||
|
|
||||||
|
#### func (*MetaNode) Key
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *MetaNode) Key() string
|
||||||
|
```
|
||||||
|
Key returns the key of the metadata
|
||||||
|
|
||||||
|
#### type Node
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Node interface {
|
||||||
|
// Type returns the NodeType of this node
|
||||||
|
Type() NodeType
|
||||||
|
// Content returns the textual content of the node
|
||||||
|
Content() string
|
||||||
|
// SetContent sets the node's textual content
|
||||||
|
SetContent(string)
|
||||||
|
// Level returns the nesting level of the node
|
||||||
|
Level() int
|
||||||
|
// SetLevel sets the nesting level of the node
|
||||||
|
SetLevel(int)
|
||||||
|
// Children returns the node's child nodes
|
||||||
|
Children() []Node
|
||||||
|
// AddChild adds a child node to this node
|
||||||
|
AddChild(Node)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Node interface defines the common behavior for all RST document nodes
|
||||||
|
|
||||||
|
#### type NodeType
|
||||||
|
|
||||||
|
```go
|
||||||
|
type NodeType int
|
||||||
|
```
|
||||||
|
|
||||||
|
NodeType represents the type of a node in the RST document structure
|
||||||
|
|
||||||
|
```go
|
||||||
|
const (
|
||||||
|
NodeHeading NodeType = iota // Represents a section heading
|
||||||
|
NodeParagraph // Represents a text paragraph
|
||||||
|
NodeList // Represents an ordered or unordered list
|
||||||
|
NodeListItem // Represents an item within a list
|
||||||
|
NodeLink // Represents a hyperlink
|
||||||
|
NodeEmphasis // Represents emphasized (italic) text
|
||||||
|
NodeStrong // Represents strong (bold) text
|
||||||
|
NodeMeta // Represents metadata information
|
||||||
|
NodeDirective // Represents an RST directive
|
||||||
|
NodeCode // Represents a code block
|
||||||
|
NodeTable // Represents a table structure
|
||||||
|
)
|
||||||
|
```
|
||||||
|
Node type constants define the possible types of nodes in the RST document tree
|
||||||
|
|
||||||
|
#### type ParagraphNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ParagraphNode struct {
|
||||||
|
*BaseNode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
ParagraphNode represents a text paragraph
|
||||||
|
|
||||||
|
#### func NewParagraphNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewParagraphNode(content string) *ParagraphNode
|
||||||
|
```
|
||||||
|
NewParagraphNode creates a new ParagraphNode with the given content
|
||||||
|
|
||||||
|
#### func (*ParagraphNode) String
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *ParagraphNode) String() string
|
||||||
|
```
|
||||||
|
String representation for debugging
|
||||||
|
|
||||||
|
#### type StrongNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
type StrongNode struct {
|
||||||
|
*BaseNode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
StrongNode represents strong text (bold)
|
||||||
|
|
||||||
|
#### func NewStrongNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewStrongNode(content string) *StrongNode
|
||||||
|
```
|
||||||
|
NewStrongNode creates a new StrongNode with the given content
|
||||||
|
|
||||||
|
#### type TableNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
type TableNode struct {
|
||||||
|
*BaseNode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
TableNode represents a table structure
|
||||||
|
|
||||||
|
#### func NewTableNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewTableNode() *TableNode
|
||||||
|
```
|
||||||
|
NewTableNode creates a new TableNode
|
||||||
|
|
||||||
|
#### func (*TableNode) AddRow
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *TableNode) AddRow(row []string)
|
||||||
|
```
|
||||||
|
AddRow adds a row to the table
|
||||||
|
|
||||||
|
#### func (*TableNode) Headers
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *TableNode) Headers() []string
|
||||||
|
```
|
||||||
|
Headers returns the headers of the table
|
||||||
|
|
||||||
|
#### func (*TableNode) Rows
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *TableNode) Rows() [][]string
|
||||||
|
```
|
||||||
|
Rows returns the rows of the table
|
||||||
|
|
||||||
|
#### func (*TableNode) SetHeaders
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *TableNode) SetHeaders(headers []string)
|
||||||
|
```
|
||||||
|
SetHeaders sets the headers of the table
|
||||||
|
|
||||||
|
#### func (*TableNode) String
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (n *TableNode) String() string
|
||||||
|
```
|
||||||
|
String representation for debugging
|
126
pkg/parser/doc.md
Normal file
126
pkg/parser/doc.md
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
# parser
|
||||||
|
--
|
||||||
|
import "i2pgit.org/idk/go-rst/pkg/parser"
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
#### type Lexer
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Lexer struct {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Lexer represents a lexer for the input text.
|
||||||
|
|
||||||
|
#### func NewLexer
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewLexer() *Lexer
|
||||||
|
```
|
||||||
|
NewLexer creates a new Lexer instance.
|
||||||
|
|
||||||
|
#### func (*Lexer) Tokenize
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (l *Lexer) Tokenize(line string) Token
|
||||||
|
```
|
||||||
|
Tokenize tokenizes a single line of input text.
|
||||||
|
|
||||||
|
#### type Parser
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Parser struct {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Parser is a struct that holds the state of the parser.
|
||||||
|
|
||||||
|
#### func NewParser
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewParser(trans translator.Translator) *Parser
|
||||||
|
```
|
||||||
|
NewParser creates a new Parser instance.
|
||||||
|
|
||||||
|
#### func (*Parser) Parse
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (p *Parser) Parse(content string) []nodes.Node
|
||||||
|
```
|
||||||
|
Parse takes a string of reStructuredText content and returns a slice of Node
|
||||||
|
instances.
|
||||||
|
|
||||||
|
#### type ParserContext
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ParserContext struct {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
ParserContext represents the current state of the parser.
|
||||||
|
|
||||||
|
#### func NewParserContext
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewParserContext() *ParserContext
|
||||||
|
```
|
||||||
|
NewParserContext creates a new ParserContext instance.
|
||||||
|
|
||||||
|
#### func (*ParserContext) Reset
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (c *ParserContext) Reset()
|
||||||
|
```
|
||||||
|
Reset resets the parser context to its initial state.
|
||||||
|
|
||||||
|
#### type Patterns
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Patterns struct {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Patterns holds compiled regular expressions for parsing Markdown syntax.
|
||||||
|
|
||||||
|
#### func NewPatterns
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewPatterns() *Patterns
|
||||||
|
```
|
||||||
|
NewPatterns initializes and returns a new instance of Patterns with compiled
|
||||||
|
regular expressions.
|
||||||
|
|
||||||
|
#### type Token
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Token struct {
|
||||||
|
Type TokenType
|
||||||
|
Content string
|
||||||
|
Args []string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Token represents a single token in the input text.
|
||||||
|
|
||||||
|
#### type TokenType
|
||||||
|
|
||||||
|
```go
|
||||||
|
type TokenType int
|
||||||
|
```
|
||||||
|
|
||||||
|
TokenType represents the type of a token.
|
||||||
|
|
||||||
|
```go
|
||||||
|
const (
|
||||||
|
TokenText TokenType = iota // TokenText represents a regular text token.
|
||||||
|
TokenHeadingUnderline // TokenHeadingUnderline represents a heading underline token.
|
||||||
|
TokenTransBlock // TokenTransBlock represents a transition block token.
|
||||||
|
TokenMeta // TokenMeta represents a metadata token.
|
||||||
|
TokenDirective // TokenDirective represents a directive token.
|
||||||
|
TokenCodeBlock // TokenCodeBlock represents a code block token.
|
||||||
|
TokenBlankLine // TokenBlankLine represents a blank line token.
|
||||||
|
TokenIndent // TokenIndent represents an indent token.
|
||||||
|
)
|
||||||
|
```
|
188
pkg/renderer/doc.md
Normal file
188
pkg/renderer/doc.md
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
# renderer
|
||||||
|
--
|
||||||
|
import "i2pgit.org/idk/go-rst/pkg/renderer"
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
#### type HTMLRenderer
|
||||||
|
|
||||||
|
```go
|
||||||
|
type HTMLRenderer struct {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
HTMLRederer is a renderer that renders nodes to HTML.
|
||||||
|
|
||||||
|
#### func NewHTMLRenderer
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewHTMLRenderer() *HTMLRenderer
|
||||||
|
```
|
||||||
|
NewHTMLRederer creates a new HTMLRederer.
|
||||||
|
|
||||||
|
#### func (*HTMLRenderer) Render
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *HTMLRenderer) Render(nodes []nodes.Node) string
|
||||||
|
```
|
||||||
|
Render renders nodes to HTML.
|
||||||
|
|
||||||
|
#### func (*HTMLRenderer) RenderPretty
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *HTMLRenderer) RenderPretty(nodes []nodes.Node) string
|
||||||
|
```
|
||||||
|
RenderPretty renders the given nodes as pretty-formatted HTML.
|
||||||
|
|
||||||
|
#### type MarkdownRenderer
|
||||||
|
|
||||||
|
```go
|
||||||
|
type MarkdownRenderer struct {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
MarkdownRenderer implements a Markdown renderer with the same interface as
|
||||||
|
HTMLRenderer
|
||||||
|
|
||||||
|
#### func NewMarkdownRenderer
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewMarkdownRenderer() *MarkdownRenderer
|
||||||
|
```
|
||||||
|
NewMarkdownRenderer creates a new Markdown renderer
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) Render
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) Render(nodes []nodes.Node) error
|
||||||
|
```
|
||||||
|
Render renders a slice of nodes to Markdown
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) RenderChildren
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) RenderChildren(node nodes.Node) error
|
||||||
|
```
|
||||||
|
RenderChildren renders child nodes
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) RenderCode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) RenderCode(node *nodes.CodeNode) error
|
||||||
|
```
|
||||||
|
RenderCode renders a code node
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) RenderDirective
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) RenderDirective(node *nodes.DirectiveNode) error
|
||||||
|
```
|
||||||
|
RenderDirective renders a directive node
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) RenderEmphasis
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) RenderEmphasis(node *nodes.EmphasisNode) error
|
||||||
|
```
|
||||||
|
RenderEmphasis renders an emphasis node
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) RenderHeading
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) RenderHeading(node *nodes.HeadingNode) error
|
||||||
|
```
|
||||||
|
RenderHeading renders a heading node
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) RenderLink
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) RenderLink(node *nodes.LinkNode) error
|
||||||
|
```
|
||||||
|
RenderLink renders a link node
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) RenderList
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) RenderList(node *nodes.ListNode) error
|
||||||
|
```
|
||||||
|
RenderList renders a list node
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) RenderListItem
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) RenderListItem(node *nodes.ListItemNode) error
|
||||||
|
```
|
||||||
|
RenderListItem renders a list item node
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) RenderMeta
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) RenderMeta(node *nodes.MetaNode) error
|
||||||
|
```
|
||||||
|
RenderMeta renders a meta node
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) RenderNode
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) RenderNode(node nodes.Node) error
|
||||||
|
```
|
||||||
|
RenderNode renders a single node to Markdown
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) RenderParagraph
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) RenderParagraph(node *nodes.ParagraphNode) error
|
||||||
|
```
|
||||||
|
RenderParagraph renders a paragraph node
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) RenderStrong
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) RenderStrong(node *nodes.StrongNode) error
|
||||||
|
```
|
||||||
|
RenderStrong renders a strong node
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) RenderTable
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) RenderTable(node *nodes.TableNode) error
|
||||||
|
```
|
||||||
|
RenderTable renders a table node
|
||||||
|
|
||||||
|
#### func (*MarkdownRenderer) String
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *MarkdownRenderer) String() string
|
||||||
|
```
|
||||||
|
String returns the rendered markdown as a string
|
||||||
|
|
||||||
|
#### type PDFRenderer
|
||||||
|
|
||||||
|
```go
|
||||||
|
type PDFRenderer struct {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
PDFRenderer implements rendering RST nodes to PDF format
|
||||||
|
|
||||||
|
#### func NewPDFRenderer
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewPDFRenderer() *PDFRenderer
|
||||||
|
```
|
||||||
|
NewPDFRenderer creates a new PDF renderer
|
||||||
|
|
||||||
|
#### func (*PDFRenderer) Render
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *PDFRenderer) Render(nodes []nodes.Node) error
|
||||||
|
```
|
||||||
|
Render renders a slice of nodes to PDF
|
||||||
|
|
||||||
|
#### func (*PDFRenderer) SaveToFile
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *PDFRenderer) SaveToFile(filename string) error
|
||||||
|
```
|
||||||
|
SaveToFile saves the PDF to a file
|
214
pkg/renderer/markdown.go
Normal file
214
pkg/renderer/markdown.go
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
// pkg/renderer/markdown.go
|
||||||
|
|
||||||
|
package renderer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"i2pgit.org/idk/go-rst/pkg/nodes"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MarkdownRenderer implements a Markdown renderer with the same interface as HTMLRenderer
|
||||||
|
type MarkdownRenderer struct {
|
||||||
|
output bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMarkdownRenderer creates a new Markdown renderer
|
||||||
|
func NewMarkdownRenderer() *MarkdownRenderer {
|
||||||
|
return &MarkdownRenderer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pkg/renderer/markdown.go
|
||||||
|
|
||||||
|
// ... (previous imports and struct definition remain the same)
|
||||||
|
|
||||||
|
// Render renders a slice of nodes to Markdown
|
||||||
|
func (r *MarkdownRenderer) Render(nodes []nodes.Node) error {
|
||||||
|
for _, node := range nodes {
|
||||||
|
if err := r.RenderNode(node); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderNode renders a single node to Markdown
|
||||||
|
func (r *MarkdownRenderer) RenderNode(node nodes.Node) error {
|
||||||
|
switch n := node.(type) {
|
||||||
|
case *nodes.HeadingNode:
|
||||||
|
return r.RenderHeading(n)
|
||||||
|
case *nodes.ParagraphNode:
|
||||||
|
return r.RenderParagraph(n)
|
||||||
|
case *nodes.ListNode:
|
||||||
|
return r.RenderList(n)
|
||||||
|
case *nodes.ListItemNode:
|
||||||
|
return r.RenderListItem(n)
|
||||||
|
case *nodes.EmphasisNode:
|
||||||
|
return r.RenderEmphasis(n)
|
||||||
|
case *nodes.StrongNode:
|
||||||
|
return r.RenderStrong(n)
|
||||||
|
case *nodes.LinkNode:
|
||||||
|
return r.RenderLink(n)
|
||||||
|
case *nodes.CodeNode:
|
||||||
|
return r.RenderCode(n)
|
||||||
|
case *nodes.TableNode:
|
||||||
|
return r.RenderTable(n)
|
||||||
|
case *nodes.DirectiveNode:
|
||||||
|
return r.RenderDirective(n)
|
||||||
|
case *nodes.MetaNode:
|
||||||
|
return r.RenderMeta(n)
|
||||||
|
default:
|
||||||
|
return r.RenderChildren(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderHeading renders a heading node
|
||||||
|
func (r *MarkdownRenderer) RenderHeading(node *nodes.HeadingNode) error {
|
||||||
|
r.output.WriteString("\n")
|
||||||
|
r.output.WriteString(strings.Repeat("#", node.Level()))
|
||||||
|
r.output.WriteString(" ")
|
||||||
|
r.output.WriteString(node.Content())
|
||||||
|
r.output.WriteString("\n")
|
||||||
|
return r.RenderChildren(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderParagraph renders a paragraph node
|
||||||
|
func (r *MarkdownRenderer) RenderParagraph(node *nodes.ParagraphNode) error {
|
||||||
|
r.output.WriteString("\n")
|
||||||
|
r.output.WriteString(node.Content())
|
||||||
|
r.output.WriteString("\n")
|
||||||
|
return r.RenderChildren(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderList renders a list node
|
||||||
|
func (r *MarkdownRenderer) RenderList(node *nodes.ListNode) error {
|
||||||
|
r.output.WriteString("\n")
|
||||||
|
return r.RenderChildren(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderListItem renders a list item node
|
||||||
|
func (r *MarkdownRenderer) RenderListItem(node *nodes.ListItemNode) error {
|
||||||
|
// Default to unordered list items with "-"
|
||||||
|
r.output.WriteString("- ")
|
||||||
|
r.output.WriteString(node.Content())
|
||||||
|
r.output.WriteString("\n")
|
||||||
|
return r.RenderChildren(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderEmphasis renders an emphasis node
|
||||||
|
func (r *MarkdownRenderer) RenderEmphasis(node *nodes.EmphasisNode) error {
|
||||||
|
r.output.WriteString("*")
|
||||||
|
r.output.WriteString(node.Content())
|
||||||
|
r.output.WriteString("*")
|
||||||
|
return r.RenderChildren(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderStrong renders a strong node
|
||||||
|
func (r *MarkdownRenderer) RenderStrong(node *nodes.StrongNode) error {
|
||||||
|
r.output.WriteString("**")
|
||||||
|
r.output.WriteString(node.Content())
|
||||||
|
r.output.WriteString("**")
|
||||||
|
return r.RenderChildren(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderLink renders a link node
|
||||||
|
func (r *MarkdownRenderer) RenderLink(node *nodes.LinkNode) error {
|
||||||
|
if title := node.Title(); title != "" {
|
||||||
|
r.output.WriteString(fmt.Sprintf("[%s](%s \"%s\")", node.Content(), node.URL(), title))
|
||||||
|
} else {
|
||||||
|
r.output.WriteString(fmt.Sprintf("[%s](%s)", node.Content(), node.URL()))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderCode renders a code node
|
||||||
|
func (r *MarkdownRenderer) RenderCode(node *nodes.CodeNode) error {
|
||||||
|
r.output.WriteString("\n```")
|
||||||
|
if node.Language() != "" {
|
||||||
|
r.output.WriteString(node.Language())
|
||||||
|
}
|
||||||
|
r.output.WriteString("\n")
|
||||||
|
r.output.WriteString(node.Content())
|
||||||
|
r.output.WriteString("\n```\n")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderTable renders a table node
|
||||||
|
func (r *MarkdownRenderer) RenderTable(node *nodes.TableNode) error {
|
||||||
|
headers := node.Headers()
|
||||||
|
rows := node.Rows()
|
||||||
|
|
||||||
|
// Headers
|
||||||
|
r.output.WriteString("\n|")
|
||||||
|
for _, header := range headers {
|
||||||
|
r.output.WriteString(fmt.Sprintf(" %s |", header))
|
||||||
|
}
|
||||||
|
r.output.WriteString("\n|")
|
||||||
|
|
||||||
|
// Separator
|
||||||
|
for range headers {
|
||||||
|
r.output.WriteString(" --- |")
|
||||||
|
}
|
||||||
|
r.output.WriteString("\n")
|
||||||
|
|
||||||
|
// Rows
|
||||||
|
for _, row := range rows {
|
||||||
|
r.output.WriteString("|")
|
||||||
|
for _, cell := range row {
|
||||||
|
r.output.WriteString(fmt.Sprintf(" %s |", cell))
|
||||||
|
}
|
||||||
|
r.output.WriteString("\n")
|
||||||
|
}
|
||||||
|
r.output.WriteString("\n")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderDirective renders a directive node
|
||||||
|
func (r *MarkdownRenderer) RenderDirective(node *nodes.DirectiveNode) error {
|
||||||
|
switch node.Name() {
|
||||||
|
case "image":
|
||||||
|
if len(node.Arguments()) > 0 {
|
||||||
|
r.output.WriteString(fmt.Sprintf("\n\n", node.Content(), node.Arguments()[0]))
|
||||||
|
}
|
||||||
|
case "note":
|
||||||
|
r.output.WriteString("\n> **Note**\n")
|
||||||
|
r.output.WriteString("> " + strings.Replace(node.RawContent(), "\n", "\n> ", -1) + "\n")
|
||||||
|
case "warning":
|
||||||
|
r.output.WriteString("\n> **Warning**\n")
|
||||||
|
r.output.WriteString("> " + strings.Replace(node.RawContent(), "\n", "\n> ", -1) + "\n")
|
||||||
|
default:
|
||||||
|
r.output.WriteString(fmt.Sprintf("\n<!-- %s: %s -->\n", node.Name(), node.RawContent()))
|
||||||
|
}
|
||||||
|
return r.RenderChildren(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderMeta renders a meta node
|
||||||
|
func (r *MarkdownRenderer) RenderMeta(node *nodes.MetaNode) error {
|
||||||
|
if r.output.Len() == 0 {
|
||||||
|
// If at start of document, use YAML front matter
|
||||||
|
r.output.WriteString("---\n")
|
||||||
|
r.output.WriteString(fmt.Sprintf("%s: %s\n", node.Key(), node.Content()))
|
||||||
|
r.output.WriteString("---\n")
|
||||||
|
} else {
|
||||||
|
// Otherwise use HTML comment
|
||||||
|
r.output.WriteString(fmt.Sprintf("\n<!-- %s: %s -->\n", node.Key(), node.Content()))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderChildren renders child nodes
|
||||||
|
func (r *MarkdownRenderer) RenderChildren(node nodes.Node) error {
|
||||||
|
for _, child := range node.Children() {
|
||||||
|
if err := r.RenderNode(child); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the rendered markdown as a string
|
||||||
|
func (r *MarkdownRenderer) String() string {
|
||||||
|
return r.output.String()
|
||||||
|
}
|
218
pkg/renderer/pdf.go
Normal file
218
pkg/renderer/pdf.go
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
// pkg/renderer/pdf.go
|
||||||
|
|
||||||
|
package renderer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jung-kurt/gofpdf"
|
||||||
|
"i2pgit.org/idk/go-rst/pkg/nodes"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PDFRenderer implements rendering RST nodes to PDF format
|
||||||
|
type PDFRenderer struct {
|
||||||
|
pdf *gofpdf.Fpdf
|
||||||
|
marginLeft float64
|
||||||
|
marginTop float64
|
||||||
|
fontSize float64
|
||||||
|
lineHeight float64
|
||||||
|
indent float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPDFRenderer creates a new PDF renderer
|
||||||
|
func NewPDFRenderer() *PDFRenderer {
|
||||||
|
pdf := gofpdf.New("P", "mm", "A4", "")
|
||||||
|
pdf.AddPage()
|
||||||
|
pdf.SetFont("Arial", "", 12)
|
||||||
|
|
||||||
|
return &PDFRenderer{
|
||||||
|
pdf: pdf,
|
||||||
|
marginLeft: 20,
|
||||||
|
marginTop: 20,
|
||||||
|
fontSize: 12,
|
||||||
|
lineHeight: 6,
|
||||||
|
indent: 10,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render renders a slice of nodes to PDF
|
||||||
|
func (r *PDFRenderer) Render(nodes []nodes.Node) error {
|
||||||
|
for _, node := range nodes {
|
||||||
|
if err := r.renderNode(node); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// renderNode handles individual node rendering
|
||||||
|
func (r *PDFRenderer) renderNode(node nodes.Node) error {
|
||||||
|
switch n := node.(type) {
|
||||||
|
case *nodes.HeadingNode:
|
||||||
|
return r.renderHeading(n)
|
||||||
|
case *nodes.ParagraphNode:
|
||||||
|
return r.renderParagraph(n)
|
||||||
|
case *nodes.ListNode:
|
||||||
|
return r.renderList(n)
|
||||||
|
case *nodes.CodeNode:
|
||||||
|
return r.renderCode(n)
|
||||||
|
case *nodes.TableNode:
|
||||||
|
return r.renderTable(n)
|
||||||
|
case *nodes.DirectiveNode:
|
||||||
|
return r.renderDirective(n)
|
||||||
|
default:
|
||||||
|
return r.renderChildren(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveToFile saves the PDF to a file
|
||||||
|
func (r *PDFRenderer) SaveToFile(filename string) error {
|
||||||
|
return r.pdf.OutputFileAndClose(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PDFRenderer) renderHeading(node *nodes.HeadingNode) error {
|
||||||
|
// Calculate font size based on heading level
|
||||||
|
fontSize := r.fontSize + (6 - float64(node.Level())*2)
|
||||||
|
r.pdf.SetFont("Arial", "B", fontSize)
|
||||||
|
|
||||||
|
// Add some spacing before heading
|
||||||
|
r.pdf.Ln(r.lineHeight)
|
||||||
|
|
||||||
|
r.pdf.Cell(0, r.lineHeight, node.Content())
|
||||||
|
r.pdf.Ln(r.lineHeight * 1.5)
|
||||||
|
|
||||||
|
// Reset font
|
||||||
|
r.pdf.SetFont("Arial", "", r.fontSize)
|
||||||
|
return r.renderChildren(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PDFRenderer) renderParagraph(node *nodes.ParagraphNode) error {
|
||||||
|
r.pdf.MultiCell(0, r.lineHeight, node.Content(), "", "", false)
|
||||||
|
r.pdf.Ln(r.lineHeight)
|
||||||
|
return r.renderChildren(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PDFRenderer) renderList(node *nodes.ListNode) error {
|
||||||
|
currentX := r.pdf.GetX()
|
||||||
|
currentY := r.pdf.GetY()
|
||||||
|
|
||||||
|
for i, child := range node.Children() {
|
||||||
|
if node.IsOrdered() {
|
||||||
|
// Ordered list: use numbers
|
||||||
|
r.pdf.SetXY(currentX, currentY)
|
||||||
|
r.pdf.Cell(10, r.lineHeight, fmt.Sprintf("%d.", i+1))
|
||||||
|
r.pdf.SetX(currentX + r.indent)
|
||||||
|
} else {
|
||||||
|
// Unordered list: use bullets
|
||||||
|
r.pdf.SetXY(currentX, currentY)
|
||||||
|
r.pdf.Cell(10, r.lineHeight, "•")
|
||||||
|
r.pdf.SetX(currentX + r.indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
if listItem, ok := child.(*nodes.ListItemNode); ok {
|
||||||
|
r.pdf.MultiCell(0, r.lineHeight, listItem.Content(), "", "", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentY = r.pdf.GetY() + r.lineHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
r.pdf.Ln(r.lineHeight)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PDFRenderer) renderCode(node *nodes.CodeNode) error {
|
||||||
|
// Set monospace font for code
|
||||||
|
r.pdf.SetFont("Courier", "", r.fontSize)
|
||||||
|
|
||||||
|
// Add a light gray background
|
||||||
|
startY := r.pdf.GetY()
|
||||||
|
content := node.Content()
|
||||||
|
lines := strings.Split(content, "\n")
|
||||||
|
|
||||||
|
// Calculate height
|
||||||
|
height := float64(len(lines)) * r.lineHeight
|
||||||
|
|
||||||
|
// Draw background
|
||||||
|
r.pdf.SetFillColor(240, 240, 240)
|
||||||
|
r.pdf.Rect(r.marginLeft-2, startY-2, 170, height+4, "F")
|
||||||
|
|
||||||
|
// Add language identifier if present
|
||||||
|
if node.Language() != "" {
|
||||||
|
r.pdf.SetFont("Arial", "I", r.fontSize-2)
|
||||||
|
r.pdf.Text(r.marginLeft, startY-4, node.Language())
|
||||||
|
r.pdf.SetFont("Courier", "", r.fontSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render code content
|
||||||
|
for _, line := range lines {
|
||||||
|
if node.LineNumbers() {
|
||||||
|
// Add line numbers if enabled
|
||||||
|
lineNum := fmt.Sprintf("%3d ", r.pdf.PageCount())
|
||||||
|
r.pdf.Text(r.marginLeft, r.pdf.GetY(), lineNum)
|
||||||
|
r.pdf.SetX(r.marginLeft + 15)
|
||||||
|
}
|
||||||
|
r.pdf.MultiCell(0, r.lineHeight, line, "", "", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset font
|
||||||
|
r.pdf.SetFont("Arial", "", r.fontSize)
|
||||||
|
r.pdf.Ln(r.lineHeight)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PDFRenderer) renderTable(node *nodes.TableNode) error {
|
||||||
|
headers := node.Headers()
|
||||||
|
rows := node.Rows()
|
||||||
|
|
||||||
|
// Calculate column widths
|
||||||
|
colWidth := 170.0 / float64(len(headers))
|
||||||
|
|
||||||
|
// Draw headers
|
||||||
|
r.pdf.SetFont("Arial", "B", r.fontSize)
|
||||||
|
r.pdf.SetFillColor(240, 240, 240)
|
||||||
|
|
||||||
|
for _, header := range headers {
|
||||||
|
r.pdf.CellFormat(colWidth, r.lineHeight, header, "1", 0, "", true, 0, "")
|
||||||
|
}
|
||||||
|
r.pdf.Ln(-1)
|
||||||
|
|
||||||
|
// Draw rows
|
||||||
|
r.pdf.SetFont("Arial", "", r.fontSize)
|
||||||
|
r.pdf.SetFillColor(255, 255, 255)
|
||||||
|
|
||||||
|
for _, row := range rows {
|
||||||
|
for _, cell := range row {
|
||||||
|
r.pdf.CellFormat(colWidth, r.lineHeight, cell, "1", 0, "", false, 0, "")
|
||||||
|
}
|
||||||
|
r.pdf.Ln(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.pdf.Ln(r.lineHeight)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PDFRenderer) renderDirective(node *nodes.DirectiveNode) error {
|
||||||
|
// Handle special directives
|
||||||
|
switch node.Name() {
|
||||||
|
case "image":
|
||||||
|
// Handle image directive
|
||||||
|
if len(node.Arguments()) > 0 {
|
||||||
|
imagePath := node.Arguments()[0]
|
||||||
|
r.pdf.Image(imagePath, r.pdf.GetX(), r.pdf.GetY(), 0, 0, false, "", 0, "")
|
||||||
|
r.pdf.Ln(r.lineHeight)
|
||||||
|
}
|
||||||
|
case "note", "warning", "important":
|
||||||
|
// Handle admonitions
|
||||||
|
r.pdf.SetFillColor(245, 245, 245)
|
||||||
|
startY := r.pdf.GetY()
|
||||||
|
r.pdf.MultiCell(0, r.lineHeight, node.RawContent(), "", "", true)
|
||||||
|
r.pdf.SetY(startY + r.lineHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.renderChildren(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PDFRenderer) renderChildren(node nodes.Node) error {
|
||||||
|
return r.Render(node.Children())
|
||||||
|
}
|
62
pkg/translator/doc.md
Normal file
62
pkg/translator/doc.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# translator
|
||||||
|
--
|
||||||
|
import "i2pgit.org/idk/go-rst/pkg/translator"
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
#### type NoopTranslator
|
||||||
|
|
||||||
|
```go
|
||||||
|
type NoopTranslator struct{}
|
||||||
|
```
|
||||||
|
|
||||||
|
NoopTranslator implements Translator interface but doesn't translate
|
||||||
|
|
||||||
|
#### func NewNoopTranslator
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewNoopTranslator() *NoopTranslator
|
||||||
|
```
|
||||||
|
NewNoopTranslator returns a new NoopTranslator
|
||||||
|
|
||||||
|
#### func (*NoopTranslator) Translate
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (t *NoopTranslator) Translate(text string) string
|
||||||
|
```
|
||||||
|
Translate returns the same text it receives(NoopTranslator)
|
||||||
|
|
||||||
|
#### type POTranslator
|
||||||
|
|
||||||
|
```go
|
||||||
|
type POTranslator struct {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
POTranslator implements Translator interface using a PO file
|
||||||
|
|
||||||
|
#### func NewPOTranslator
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewPOTranslator(poFile string) (*POTranslator, error)
|
||||||
|
```
|
||||||
|
NewPOTranslator returns a new POTranslator
|
||||||
|
|
||||||
|
#### func (*POTranslator) Translate
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (t *POTranslator) Translate(text string) string
|
||||||
|
```
|
||||||
|
Translate returns the translated text if it exists in the PO file, otherwise it
|
||||||
|
returns the original text
|
||||||
|
|
||||||
|
#### type Translator
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Translator interface {
|
||||||
|
Translate(text string) string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Translator is an interface for translating text
|
Reference in New Issue
Block a user