mirror of
https://github.com/kovetskiy/mark.git
synced 2025-04-24 05:42:40 +08:00
Merge pull request #22 from csoutherland/exactattach
Add ExactAttachment header
This commit is contained in:
commit
f39aeb10d7
29
README.md
29
README.md
@ -29,6 +29,8 @@ File in extended format should follow specification
|
|||||||
<!-- Parent: <parent 1> -->
|
<!-- Parent: <parent 1> -->
|
||||||
<!-- Parent: <parent 2> -->
|
<!-- Parent: <parent 2> -->
|
||||||
<!-- Title: <title> -->
|
<!-- Title: <title> -->
|
||||||
|
<!-- ExactAttachment: <local path> -->
|
||||||
|
<!-- Attachment: <local path> -->
|
||||||
|
|
||||||
<page contents>
|
<page contents>
|
||||||
```
|
```
|
||||||
@ -61,6 +63,33 @@ follows include tag:
|
|||||||
<yaml-data> -->
|
<yaml-data> -->
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Mark also supports attachments. The standard way involves declaring an
|
||||||
|
`Attachment` along with the other items in the header, then have any links
|
||||||
|
start with an `attachment://` pseudo-URL:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
<!-- Attachment: <path> -->
|
||||||
|
|
||||||
|
<beginning of page content>
|
||||||
|
|
||||||
|
An attached link is [here](attachment://<path>)
|
||||||
|
```
|
||||||
|
|
||||||
|
The standard attachment mechanism may not work in some circumstances (e.g.
|
||||||
|
keeping content as close to identical as possible between GitHub and
|
||||||
|
Confluence), so `ExactAttachment` has been introduced:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
<!-- ExactAttachment: <path> -->
|
||||||
|
|
||||||
|
<beginning of page content>
|
||||||
|
|
||||||
|
An attached link is [here](<path>)
|
||||||
|
```
|
||||||
|
|
||||||
|
**NOTE**: Be careful with `ExactAttachment`! If your path string is a subset of
|
||||||
|
another longer string or referenced in text, you may get undesired behavior.
|
||||||
|
|
||||||
Mark also supports macro definitions, which are defined as regexps which will
|
Mark also supports macro definitions, which are defined as regexps which will
|
||||||
be replaced with specified template:
|
be replaced with specified template:
|
||||||
|
|
||||||
|
@ -28,20 +28,22 @@ type Attachment struct {
|
|||||||
Path string
|
Path string
|
||||||
Checksum string
|
Checksum string
|
||||||
Link string
|
Link string
|
||||||
|
Replace string
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResolveAttachments(
|
func ResolveAttachments(
|
||||||
api *confluence.API,
|
api *confluence.API,
|
||||||
page *confluence.PageInfo,
|
page *confluence.PageInfo,
|
||||||
base string,
|
base string,
|
||||||
names []string,
|
replacements map[string]string,
|
||||||
) ([]Attachment, error) {
|
) ([]Attachment, error) {
|
||||||
attaches := []Attachment{}
|
attaches := []Attachment{}
|
||||||
for _, name := range names {
|
for replace, name := range replacements {
|
||||||
attach := Attachment{
|
attach := Attachment{
|
||||||
Name: name,
|
Name: name,
|
||||||
Filename: strings.ReplaceAll(name, "/", "_"),
|
Filename: strings.ReplaceAll(name, "/", "_"),
|
||||||
Path: filepath.Join(base, name),
|
Path: filepath.Join(base, name),
|
||||||
|
Replace: replace,
|
||||||
}
|
}
|
||||||
|
|
||||||
checksum, err := getChecksum(attach.Path)
|
checksum, err := getChecksum(attach.Path)
|
||||||
@ -160,18 +162,18 @@ func ResolveAttachments(
|
|||||||
|
|
||||||
func CompileAttachmentLinks(markdown []byte, attaches []Attachment) []byte {
|
func CompileAttachmentLinks(markdown []byte, attaches []Attachment) []byte {
|
||||||
links := map[string]string{}
|
links := map[string]string{}
|
||||||
names := []string{}
|
replaces := []string{}
|
||||||
|
|
||||||
for _, attach := range attaches {
|
for _, attach := range attaches {
|
||||||
uri, err := url.ParseRequestURI(attach.Link)
|
uri, err := url.ParseRequestURI(attach.Link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
links[attach.Name] = strings.ReplaceAll("&", "&", attach.Link)
|
links[attach.Replace] = strings.ReplaceAll("&", "&", attach.Link)
|
||||||
} else {
|
} else {
|
||||||
links[attach.Name] = uri.Path +
|
links[attach.Replace] = uri.Path +
|
||||||
"?" + url.QueryEscape(uri.Query().Encode())
|
"?" + url.QueryEscape(uri.Query().Encode())
|
||||||
}
|
}
|
||||||
|
|
||||||
names = append(names, attach.Name)
|
replaces = append(replaces, attach.Replace)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort by length so first items will have bigger length
|
// sort by length so first items will have bigger length
|
||||||
@ -179,13 +181,13 @@ func CompileAttachmentLinks(markdown []byte, attaches []Attachment) []byte {
|
|||||||
// attachments/a.jpg
|
// attachments/a.jpg
|
||||||
// attachments/a.jpg.jpg
|
// attachments/a.jpg.jpg
|
||||||
// so we replace longer and then shorter
|
// so we replace longer and then shorter
|
||||||
sort.SliceStable(names, func(i, j int) bool {
|
sort.SliceStable(replaces, func(i, j int) bool {
|
||||||
return len(names[i]) > len(names[j])
|
return len(replaces[i]) > len(replaces[j])
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, name := range names {
|
for _, replace := range replaces {
|
||||||
from := `attachment://` + name
|
from := replace
|
||||||
to := links[name]
|
to := links[replace]
|
||||||
|
|
||||||
log.Debugf(nil, "replacing: %q -> %q", from, to)
|
log.Debugf(nil, "replacing: %q -> %q", from, to)
|
||||||
|
|
||||||
|
@ -11,11 +11,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
HeaderParent = `Parent`
|
HeaderParent = `Parent`
|
||||||
HeaderSpace = `Space`
|
HeaderSpace = `Space`
|
||||||
HeaderTitle = `Title`
|
HeaderTitle = `Title`
|
||||||
HeaderLayout = `Layout`
|
HeaderLayout = `Layout`
|
||||||
HeaderAttachment = `Attachment`
|
HeaderAttachment = `Attachment`
|
||||||
|
HeaderExactAttachment = `ExactAttachment`
|
||||||
)
|
)
|
||||||
|
|
||||||
type Meta struct {
|
type Meta struct {
|
||||||
@ -23,7 +24,7 @@ type Meta struct {
|
|||||||
Space string
|
Space string
|
||||||
Title string
|
Title string
|
||||||
Layout string
|
Layout string
|
||||||
Attachments []string
|
Attachments map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -64,6 +65,7 @@ func ExtractMeta(data []byte) (*Meta, []byte, error) {
|
|||||||
|
|
||||||
if meta == nil {
|
if meta == nil {
|
||||||
meta = &Meta{}
|
meta = &Meta{}
|
||||||
|
meta.Attachments = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
header := strings.Title(matches[1])
|
header := strings.Title(matches[1])
|
||||||
@ -87,7 +89,10 @@ func ExtractMeta(data []byte) (*Meta, []byte, error) {
|
|||||||
meta.Layout = strings.TrimSpace(value)
|
meta.Layout = strings.TrimSpace(value)
|
||||||
|
|
||||||
case HeaderAttachment:
|
case HeaderAttachment:
|
||||||
meta.Attachments = append(meta.Attachments, value)
|
meta.Attachments["attachment://"+value] = value
|
||||||
|
|
||||||
|
case HeaderExactAttachment:
|
||||||
|
meta.Attachments[value] = value
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Errorf(
|
log.Errorf(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user