Merge pull request #95 from glacials/html-toplevel-hlevel

Allow customizing header level offset
This commit is contained in:
Niklas Fasching 2023-02-19 18:55:12 +01:00 committed by GitHub
commit fa3e6f91d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 69 additions and 4 deletions

View file

@ -21,6 +21,21 @@ type HTMLWriter struct {
ExtendingWriter Writer
HighlightCodeBlock func(source, lang string, inline bool, params map[string]string) string
PrettyRelativeLinks bool
// TopLevelHLevel determines what HTML heading to use for a
// level-1 Org headline, and by extension further headings.
//
// For example, a value of 1 means a top-level Org headline will be
// rendered as an <h1> element, a level-2 Org headline will be
// rendered as an <h2> element, and so on.
//
// A value of 2 (default) means a top-level Org headline will be
// rendered as an <h2> element, a level-2 Org headline will be
// rendered as an <h3> element, and so on.
//
// This setting and its default behavior match Org's
// :html-toplevel-hlevel export property and the associated
// org-html-toplevel-hlevel variable.
TopLevelHLevel int
strings.Builder
document *Document
@ -72,6 +87,7 @@ func NewHTMLWriter() *HTMLWriter {
}
return fmt.Sprintf("<div class=\"highlight\">\n<pre>\n%s\n</pre>\n</div>", html.EscapeString(source))
},
TopLevelHLevel: 2,
footnotes: &footnotes{
mapping: map[string]int{},
},
@ -272,8 +288,10 @@ func (w *HTMLWriter) WriteHeadline(h Headline) {
return
}
w.WriteString(fmt.Sprintf(`<div id="outline-container-%s" class="outline-%d">`, h.ID(), h.Lvl+1) + "\n")
w.WriteString(fmt.Sprintf(`<h%d id="%s">`, h.Lvl+1, h.ID()) + "\n")
level := (h.Lvl - 1) + w.TopLevelHLevel
w.WriteString(fmt.Sprintf(`<div id="outline-container-%s" class="outline-%d">`, h.ID(), level) + "\n")
w.WriteString(fmt.Sprintf(`<h%d id="%s">`, level, h.ID()) + "\n")
if w.document.GetOption("todo") != "nil" && h.Status != "" {
w.WriteString(fmt.Sprintf(`<span class="todo">%s</span>`, h.Status) + "\n")
}
@ -290,9 +308,9 @@ func (w *HTMLWriter) WriteHeadline(h Headline) {
w.WriteString("&#xa0;&#xa0;&#xa0;")
w.WriteString(fmt.Sprintf(`<span class="tags">%s</span>`, strings.Join(tags, "&#xa0;")))
}
w.WriteString(fmt.Sprintf("\n</h%d>\n", h.Lvl+1))
w.WriteString(fmt.Sprintf("\n</h%d>\n", level))
if content := w.WriteNodesAsString(h.Children...); content != "" {
w.WriteString(fmt.Sprintf(`<div id="outline-text-%s" class="outline-text-%d">`, h.ID(), h.Lvl+1) + "\n" + content + "</div>\n")
w.WriteString(fmt.Sprintf(`<div id="outline-text-%s" class="outline-text-%d">`, h.ID(), level) + "\n" + content + "</div>\n")
}
w.WriteString("</div>\n")
}

View file

@ -56,3 +56,50 @@ func TestPrettyRelativeLinks(t *testing.T) {
})
}
}
var topLevelHLevelTests = map[struct {
TopLevelHLevel int
input string
}]string{
{1, "* Top-level headline"}: "<h1 id=\"headline-1\">\nTop-level headline\n</h1>",
{1, "** Second-level headline"}: "<h2 id=\"headline-1\">\nSecond-level headline\n</h2>",
{1, "*** Third-level headline"}: "<h3 id=\"headline-1\">\nThird-level headline\n</h3>",
{1, "**** Fourth-level headline"}: "<h4 id=\"headline-1\">\nFourth-level headline\n</h4>",
{1, "***** Fifth-level headline"}: "<h5 id=\"headline-1\">\nFifth-level headline\n</h5>",
{1, "****** Sixth-level headline"}: "<h6 id=\"headline-1\">\nSixth-level headline\n</h6>",
{2, "* Top-level headline"}: "<h2 id=\"headline-1\">\nTop-level headline\n</h2>",
{2, "** Second-level headline"}: "<h3 id=\"headline-1\">\nSecond-level headline\n</h3>",
{2, "*** Third-level headline"}: "<h4 id=\"headline-1\">\nThird-level headline\n</h4>",
{2, "**** Fourth-level headline"}: "<h5 id=\"headline-1\">\nFourth-level headline\n</h5>",
{2, "***** Fifth-level headline"}: "<h6 id=\"headline-1\">\nFifth-level headline\n</h6>",
{3, "* Top-level headline"}: "<h3 id=\"headline-1\">\nTop-level headline\n</h3>",
{3, "** Second-level headline"}: "<h4 id=\"headline-1\">\nSecond-level headline\n</h4>",
{3, "*** Third-level headline"}: "<h5 id=\"headline-1\">\nThird-level headline\n</h5>",
{3, "**** Fourth-level headline"}: "<h6 id=\"headline-1\">\nFourth-level headline\n</h6>",
{4, "* Top-level headline"}: "<h4 id=\"headline-1\">\nTop-level headline\n</h4>",
{4, "** Second-level headline"}: "<h5 id=\"headline-1\">\nSecond-level headline\n</h5>",
{4, "*** Third-level headline"}: "<h6 id=\"headline-1\">\nThird-level headline\n</h6>",
{5, "* Top-level headline"}: "<h5 id=\"headline-1\">\nTop-level headline\n</h5>",
{5, "** Second-level headline"}: "<h6 id=\"headline-1\">\nSecond-level headline\n</h6>",
{6, "* Top-level headline"}: "<h6 id=\"headline-1\">\nTop-level headline\n</h6>",
}
func TestTopLevelHLevel(t *testing.T) {
for org, expected := range topLevelHLevelTests {
t.Run(org.input, func(t *testing.T) {
writer := NewHTMLWriter()
writer.TopLevelHLevel = org.TopLevelHLevel
actual, err := New().Silent().Parse(strings.NewReader(org.input), "./topLevelHLevelTests.org").Write(writer)
if err != nil {
t.Errorf("TopLevelHLevel=%d %s\n got error: %s", org.TopLevelHLevel, org.input, err)
} else if actual := strings.TrimSpace(actual); !strings.Contains(actual, expected) {
t.Errorf("TopLevelHLevel=%d %s:\n%s'", org.TopLevelHLevel, org.input, diff(actual, expected))
}
})
}
}