Add support for timestamps
This commit is contained in:
parent
bd33e8885e
commit
63fef04fb3
9 changed files with 121 additions and 1 deletions
|
@ -118,3 +118,8 @@ dl > dd { margin: -1em 0 1em 1em; }
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
color: lightgrey;
|
color: lightgrey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timestamp {
|
||||||
|
background-color: #eee;
|
||||||
|
padding: 0.05em 0.2em;
|
||||||
|
border: 1px solid #ccc; }
|
||||||
|
|
|
@ -81,7 +81,7 @@ func New() *Configuration {
|
||||||
DefaultSettings: map[string]string{
|
DefaultSettings: map[string]string{
|
||||||
"TODO": "TODO | DONE",
|
"TODO": "TODO | DONE",
|
||||||
"EXCLUDE_TAGS": "noexport",
|
"EXCLUDE_TAGS": "noexport",
|
||||||
"OPTIONS": "toc:t e:t f:t pri:t todo:t tags:t",
|
"OPTIONS": "toc:t <:t e:t f:t pri:t todo:t tags:t",
|
||||||
},
|
},
|
||||||
Log: log.New(os.Stderr, "go-org: ", 0),
|
Log: log.New(os.Stderr, "go-org: ", 0),
|
||||||
}
|
}
|
||||||
|
@ -166,6 +166,7 @@ func (d *Document) Get(key string) string {
|
||||||
|
|
||||||
// GetOption returns the value associated to the export option key
|
// GetOption returns the value associated to the export option key
|
||||||
// Currently supported options:
|
// Currently supported options:
|
||||||
|
// - < (export timestamps)
|
||||||
// - e (export org entities)
|
// - e (export org entities)
|
||||||
// - f (export footnotes)
|
// - f (export footnotes)
|
||||||
// - toc (export table of content)
|
// - toc (export table of content)
|
||||||
|
|
|
@ -246,6 +246,22 @@ func (w *HTMLWriter) WriteFootnoteLink(l FootnoteLink) {
|
||||||
w.WriteString(fmt.Sprintf(`<sup class="footnote-reference"><a id="footnote-reference-%s" href="#footnote-%s">%s</a></sup>`, n, n, n))
|
w.WriteString(fmt.Sprintf(`<sup class="footnote-reference"><a id="footnote-reference-%s" href="#footnote-%s">%s</a></sup>`, n, n, n))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *HTMLWriter) WriteTimestamp(t Timestamp) {
|
||||||
|
if !w.document.GetOption("<") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.WriteString(`<span class="timestamp"><`)
|
||||||
|
if t.IsDate {
|
||||||
|
w.WriteString(t.Time.Format(datestampFormat))
|
||||||
|
} else {
|
||||||
|
w.WriteString(t.Time.Format(timestampFormat))
|
||||||
|
}
|
||||||
|
if t.Interval != "" {
|
||||||
|
w.WriteString(" " + t.Interval)
|
||||||
|
}
|
||||||
|
w.WriteString(`></span>`)
|
||||||
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) WriteRegularLink(l RegularLink) {
|
func (w *HTMLWriter) WriteRegularLink(l RegularLink) {
|
||||||
url := html.EscapeString(l.URL)
|
url := html.EscapeString(l.URL)
|
||||||
if l.Protocol == "file" {
|
if l.Protocol == "file" {
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package org
|
package org
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,6 +19,12 @@ type ExplicitLineBreak struct{}
|
||||||
|
|
||||||
type StatisticToken struct{ Content string }
|
type StatisticToken struct{ Content string }
|
||||||
|
|
||||||
|
type Timestamp struct {
|
||||||
|
Time time.Time
|
||||||
|
IsDate bool
|
||||||
|
Interval string
|
||||||
|
}
|
||||||
|
|
||||||
type Emphasis struct {
|
type Emphasis struct {
|
||||||
Kind string
|
Kind string
|
||||||
Content []Node
|
Content []Node
|
||||||
|
@ -40,9 +48,13 @@ var imageExtensionRegexp = regexp.MustCompile(`^[.](png|gif|jpe?g|svg|tiff?)$`)
|
||||||
var videoExtensionRegexp = regexp.MustCompile(`^[.](webm|mp4)$`)
|
var videoExtensionRegexp = regexp.MustCompile(`^[.](webm|mp4)$`)
|
||||||
|
|
||||||
var subScriptSuperScriptRegexp = regexp.MustCompile(`^([_^]){([^{}]+?)}`)
|
var subScriptSuperScriptRegexp = regexp.MustCompile(`^([_^]){([^{}]+?)}`)
|
||||||
|
var timestampRegexp = regexp.MustCompile(`^<(\d{4}-\d{2}-\d{2})( [A-Za-z]+)?( \d{2}:\d{2})?( \+\d+[dwmy])?>`)
|
||||||
var footnoteRegexp = regexp.MustCompile(`^\[fn:([\w-]+?)(:(.*?))?\]`)
|
var footnoteRegexp = regexp.MustCompile(`^\[fn:([\w-]+?)(:(.*?))?\]`)
|
||||||
var statisticsTokenRegexp = regexp.MustCompile(`^\[(\d+/\d+|\d+%)\]`)
|
var statisticsTokenRegexp = regexp.MustCompile(`^\[(\d+/\d+|\d+%)\]`)
|
||||||
|
|
||||||
|
var timestampFormat = "2006-01-02 Mon 15:04"
|
||||||
|
var datestampFormat = "2006-01-02 Mon"
|
||||||
|
|
||||||
func (d *Document) parseInline(input string) (nodes []Node) {
|
func (d *Document) parseInline(input string) (nodes []Node) {
|
||||||
previous, current := 0, 0
|
previous, current := 0, 0
|
||||||
for current < len(input) {
|
for current < len(input) {
|
||||||
|
@ -58,6 +70,8 @@ func (d *Document) parseInline(input string) (nodes []Node) {
|
||||||
consumed, node = d.parseEmphasis(input, current, true)
|
consumed, node = d.parseEmphasis(input, current, true)
|
||||||
case '[':
|
case '[':
|
||||||
consumed, node = d.parseOpeningBracket(input, current)
|
consumed, node = d.parseOpeningBracket(input, current)
|
||||||
|
case '<':
|
||||||
|
consumed, node = d.parseTimestamp(input, current)
|
||||||
case '\\':
|
case '\\':
|
||||||
consumed, node = d.parseExplicitLineBreak(input, current)
|
consumed, node = d.parseExplicitLineBreak(input, current)
|
||||||
case '\n':
|
case '\n':
|
||||||
|
@ -222,6 +236,22 @@ func (d *Document) parseRegularLink(input string, start int) (int, Node) {
|
||||||
return consumed, RegularLink{protocol, description, link, false}
|
return consumed, RegularLink{protocol, description, link, false}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Document) parseTimestamp(input string, start int) (int, Node) {
|
||||||
|
if m := timestampRegexp.FindStringSubmatch(input[start:]); m != nil {
|
||||||
|
ddmmyy, hhmm, interval, isDate := m[1], m[3], strings.TrimSpace(m[4]), false
|
||||||
|
if hhmm == "" {
|
||||||
|
hhmm, isDate = "00:00", true
|
||||||
|
}
|
||||||
|
t, err := time.Parse(timestampFormat, fmt.Sprintf("%s Mon %s", ddmmyy, hhmm))
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
timestamp := Timestamp{t, isDate, interval}
|
||||||
|
return len(m[0]), timestamp
|
||||||
|
}
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Document) parseEmphasis(input string, start int, isRaw bool) (int, Node) {
|
func (d *Document) parseEmphasis(input string, start int, isRaw bool) (int, Node) {
|
||||||
marker, i := input[start], start
|
marker, i := input[start], start
|
||||||
if !hasValidPreAndBorderChars(input, i) {
|
if !hasValidPreAndBorderChars(input, i) {
|
||||||
|
@ -282,3 +312,4 @@ func (n StatisticToken) String() string { return orgWriter.nodesAsString(n) }
|
||||||
func (n Emphasis) String() string { return orgWriter.nodesAsString(n) }
|
func (n Emphasis) String() string { return orgWriter.nodesAsString(n) }
|
||||||
func (n FootnoteLink) String() string { return orgWriter.nodesAsString(n) }
|
func (n FootnoteLink) String() string { return orgWriter.nodesAsString(n) }
|
||||||
func (n RegularLink) String() string { return orgWriter.nodesAsString(n) }
|
func (n RegularLink) String() string { return orgWriter.nodesAsString(n) }
|
||||||
|
func (n Timestamp) String() string { return orgWriter.nodesAsString(n) }
|
||||||
|
|
|
@ -278,6 +278,19 @@ func (w *OrgWriter) WriteExplicitLineBreak(l ExplicitLineBreak) {
|
||||||
w.WriteString(`\\` + "\n" + w.indent)
|
w.WriteString(`\\` + "\n" + w.indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *OrgWriter) WriteTimestamp(t Timestamp) {
|
||||||
|
w.WriteString("<")
|
||||||
|
if t.IsDate {
|
||||||
|
w.WriteString(t.Time.Format(datestampFormat))
|
||||||
|
} else {
|
||||||
|
w.WriteString(t.Time.Format(timestampFormat))
|
||||||
|
}
|
||||||
|
if t.Interval != "" {
|
||||||
|
w.WriteString(" " + t.Interval)
|
||||||
|
}
|
||||||
|
w.WriteString(">")
|
||||||
|
}
|
||||||
|
|
||||||
func (w *OrgWriter) WriteFootnoteLink(l FootnoteLink) {
|
func (w *OrgWriter) WriteFootnoteLink(l FootnoteLink) {
|
||||||
w.WriteString("[fn:" + l.Name)
|
w.WriteString("[fn:" + l.Name)
|
||||||
if l.Definition != nil {
|
if l.Definition != nil {
|
||||||
|
|
37
org/testdata/inline.html
vendored
37
org/testdata/inline.html
vendored
|
@ -111,4 +111,41 @@ auto link, i.e. not inside <code class="verbatim">\[[square brackets]\]</code> <
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
timestamps
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
<span class="timestamp"><2019-01-06 Sun></span>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
<span class="timestamp"><2019-01-06 Sun></span>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
<span class="timestamp"><2019-01-06 Sun 18:00></span>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
<span class="timestamp"><2019-01-06 Sun 18:00 +1w></span>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
<span class="timestamp"><2019-01-06 Sun 18:00></span>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p>
|
||||||
|
<span class="timestamp"><2019-01-06 Sun 18:00 +1w></span>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
7
org/testdata/inline.org
vendored
7
org/testdata/inline.org
vendored
|
@ -27,3 +27,10 @@
|
||||||
6. regular link to https (image) [[https://placekitten.com/200/200#.png]]
|
6. regular link to https (image) [[https://placekitten.com/200/200#.png]]
|
||||||
7. regular link enclosed in [] [[[https://www.example.com]]] [[[https://www.example.com][example.com]]]
|
7. regular link enclosed in [] [[[https://www.example.com]]] [[[https://www.example.com][example.com]]]
|
||||||
8. auto link, i.e. not inside =\[[square brackets]\]= https://www.example.com
|
8. auto link, i.e. not inside =\[[square brackets]\]= https://www.example.com
|
||||||
|
- timestamps
|
||||||
|
- <2019-01-06>
|
||||||
|
- <2019-01-06 Sun>
|
||||||
|
- <2019-01-06 Sun 18:00>
|
||||||
|
- <2019-01-06 Sun 18:00 +1w>
|
||||||
|
- <2019-01-06 18:00>
|
||||||
|
- <2019-01-06 18:00 +1w>
|
||||||
|
|
7
org/testdata/inline.pretty_org
vendored
7
org/testdata/inline.pretty_org
vendored
|
@ -27,3 +27,10 @@
|
||||||
6. regular link to https (image) [[https://placekitten.com/200/200#.png]]
|
6. regular link to https (image) [[https://placekitten.com/200/200#.png]]
|
||||||
7. regular link enclosed in [] [[[https://www.example.com]]] [[[https://www.example.com][example.com]]]
|
7. regular link enclosed in [] [[[https://www.example.com]]] [[[https://www.example.com][example.com]]]
|
||||||
8. auto link, i.e. not inside =\[[square brackets]\]= https://www.example.com
|
8. auto link, i.e. not inside =\[[square brackets]\]= https://www.example.com
|
||||||
|
- timestamps
|
||||||
|
- <2019-01-06 Sun>
|
||||||
|
- <2019-01-06 Sun>
|
||||||
|
- <2019-01-06 Sun 18:00>
|
||||||
|
- <2019-01-06 Sun 18:00 +1w>
|
||||||
|
- <2019-01-06 Sun 18:00>
|
||||||
|
- <2019-01-06 Sun 18:00 +1w>
|
||||||
|
|
|
@ -29,6 +29,7 @@ type Writer interface {
|
||||||
WriteExplicitLineBreak(ExplicitLineBreak)
|
WriteExplicitLineBreak(ExplicitLineBreak)
|
||||||
WriteLineBreak(LineBreak)
|
WriteLineBreak(LineBreak)
|
||||||
WriteRegularLink(RegularLink)
|
WriteRegularLink(RegularLink)
|
||||||
|
WriteTimestamp(Timestamp)
|
||||||
WriteFootnoteLink(FootnoteLink)
|
WriteFootnoteLink(FootnoteLink)
|
||||||
WriteFootnoteDefinition(FootnoteDefinition)
|
WriteFootnoteDefinition(FootnoteDefinition)
|
||||||
}
|
}
|
||||||
|
@ -78,6 +79,8 @@ func WriteNodes(w Writer, nodes ...Node) {
|
||||||
w.WriteLineBreak(n)
|
w.WriteLineBreak(n)
|
||||||
case RegularLink:
|
case RegularLink:
|
||||||
w.WriteRegularLink(n)
|
w.WriteRegularLink(n)
|
||||||
|
case Timestamp:
|
||||||
|
w.WriteTimestamp(n)
|
||||||
case FootnoteLink:
|
case FootnoteLink:
|
||||||
w.WriteFootnoteLink(n)
|
w.WriteFootnoteLink(n)
|
||||||
case FootnoteDefinition:
|
case FootnoteDefinition:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue