summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattn/godown
diff options
context:
space:
mode:
authorWim <wim@42.be>2019-12-26 23:12:28 +0100
committerWim <wim@42.be>2020-03-01 22:19:33 +0100
commit795a8705c3fdc5bf55e83d382e7d3ff233896a0b (patch)
tree46ac43e487102de7ea21a823a7a7902ae9493f88 /vendor/github.com/mattn/godown
parent3af0dc3b3a5bfaffe37770c437427f1e99402405 (diff)
downloadmatterbridge-msglm-795a8705c3fdc5bf55e83d382e7d3ff233896a0b.tar.gz
matterbridge-msglm-795a8705c3fdc5bf55e83d382e7d3ff233896a0b.tar.bz2
matterbridge-msglm-795a8705c3fdc5bf55e83d382e7d3ff233896a0b.zip
Add initial Microsoft Teams support
Documentation on https://github.com/42wim/matterbridge/wiki/MS-Teams-setup
Diffstat (limited to 'vendor/github.com/mattn/godown')
-rw-r--r--vendor/github.com/mattn/godown/.gitignore2
-rw-r--r--vendor/github.com/mattn/godown/.travis.yml14
-rw-r--r--vendor/github.com/mattn/godown/LICENSE21
-rw-r--r--vendor/github.com/mattn/godown/README.md42
-rw-r--r--vendor/github.com/mattn/godown/godown.go372
5 files changed, 451 insertions, 0 deletions
diff --git a/vendor/github.com/mattn/godown/.gitignore b/vendor/github.com/mattn/godown/.gitignore
new file mode 100644
index 00000000..2c77a177
--- /dev/null
+++ b/vendor/github.com/mattn/godown/.gitignore
@@ -0,0 +1,2 @@
+*.swp
+godown
diff --git a/vendor/github.com/mattn/godown/.travis.yml b/vendor/github.com/mattn/godown/.travis.yml
new file mode 100644
index 00000000..4a9344d1
--- /dev/null
+++ b/vendor/github.com/mattn/godown/.travis.yml
@@ -0,0 +1,14 @@
+language: go
+
+go:
+ - 1.8
+ - 1.9.3
+
+env:
+ secure: "sssm68fvzltcAnFd0Vc+OJV0eOicaTUO4I/CRX9LsnqzSsiNmaFT5o1O0Mx622ApYxCfiG3G53B8wuPzSMQxdPaSiMqzoXNLjD8gURaZBWTXc+kj9WFUoS4KW5L8KF3zrmS1u6Ja9U/elIpNqbpuwqT7sZUUJJM1JR50uEVmtP9oc/iqTKh3JK1HZCkb/PDVKs7xY5AEOhx1x0QOn9SegMUK2b83WeuSbta3Z6Rp4EW3p3WwI1WHZmm8+IYjvbwu18foQSetfro+pXCyDBpw1zLbBTDR8W02VwkH2vECMm4N7GYPmHWNx2lZFqoFp9zY5zCRUQG9KmxqbappalBCsT1ZyesUt7Wp/qYw5W+1Np7/vQhe8eeyyKMzsS7FBq8Imn4JiBPbj/1KAhVoZZKyv0qU4hgxHPZMC/JtVoTkIH3IXvTE88P92z9pFL30afQ692BXPe+XmCBph4zBdH88vksdiky9DWuXJ+O0rDCcLes45ij/wk6psdTPx3IXuMohfkO81F0pveksBYFkff8dXXxCABUzZbPaawEDnLAQKJ1m+oF3UYhPzVwrelNjFDOUq3mxsTU36uyhB9fb8sJ+BmorTD9AvqNvobcwKlQ6TaVJEhHjDJRxho82OG2gof9UbsJF3+6IM8uuUVy3TP7b1o+t8PQ3iNKTB4RUzGjJCOs="
+
+script:
+ go test -v -race -coverprofile=coverage.txt -covermode=atomic
+
+after_success:
+ - bash <(curl -s https://codecov.io/bash)
diff --git a/vendor/github.com/mattn/godown/LICENSE b/vendor/github.com/mattn/godown/LICENSE
new file mode 100644
index 00000000..e364750d
--- /dev/null
+++ b/vendor/github.com/mattn/godown/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Yasuhiro Matsumoto
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/mattn/godown/README.md b/vendor/github.com/mattn/godown/README.md
new file mode 100644
index 00000000..a94f4157
--- /dev/null
+++ b/vendor/github.com/mattn/godown/README.md
@@ -0,0 +1,42 @@
+# godown
+
+[![Build Status](https://travis-ci.org/mattn/godown.png?branch=master)](https://travis-ci.org/mattn/godown)
+[![Codecov](https://codecov.io/gh/mattn/godown/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/godown)
+[![GoDoc](https://godoc.org/github.com/mattn/godown?status.svg)](http://godoc.org/github.com/mattn/godown)
+[![Go Report Card](https://goreportcard.com/badge/github.com/mattn/godown)](https://goreportcard.com/report/github.com/mattn/godown)
+
+Convert HTML into Markdown
+
+This is work in progress.
+
+## Usage
+
+```
+err := godown.Convert(w, r)
+checkError(err)
+```
+
+
+## Command Line
+
+```
+$ godown < index.html > index.md
+```
+
+## Installation
+
+```
+$ go get github.com/mattn/godown/cmd/godown
+```
+
+## TODO
+
+* escape strings in HTML
+
+## License
+
+MIT
+
+## Author
+
+Yasuhiro Matsumoto (a.k.a. mattn)
diff --git a/vendor/github.com/mattn/godown/godown.go b/vendor/github.com/mattn/godown/godown.go
new file mode 100644
index 00000000..10423be9
--- /dev/null
+++ b/vendor/github.com/mattn/godown/godown.go
@@ -0,0 +1,372 @@
+package godown
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "regexp"
+ "strings"
+
+ "github.com/mattn/go-runewidth"
+
+ "golang.org/x/net/html"
+)
+
+func isChildOf(node *html.Node, name string) bool {
+ node = node.Parent
+ return node != nil && node.Type == html.ElementNode && strings.ToLower(node.Data) == name
+}
+
+func hasClass(node *html.Node, clazz string) bool {
+ for _, attr := range node.Attr {
+ if attr.Key == "class" {
+ for _, c := range strings.Fields(attr.Val) {
+ if c == clazz {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
+func attr(node *html.Node, key string) string {
+ for _, attr := range node.Attr {
+ if attr.Key == key {
+ return attr.Val
+ }
+ }
+ return ""
+}
+
+func br(node *html.Node, w io.Writer, option *Option) {
+ node = node.PrevSibling
+ if node == nil {
+ return
+ }
+ switch node.Type {
+ case html.TextNode:
+ text := strings.Trim(node.Data, " \t")
+ if text != "" && !strings.HasSuffix(text, "\n") {
+ fmt.Fprint(w, "\n")
+ }
+ case html.ElementNode:
+ switch strings.ToLower(node.Data) {
+ case "br", "p", "ul", "ol", "div", "blockquote", "h1", "h2", "h3", "h4", "h5", "h6":
+ fmt.Fprint(w, "\n")
+ }
+ }
+}
+
+func table(node *html.Node, w io.Writer, option *Option) {
+ for tr := node.FirstChild; tr != nil; tr = tr.NextSibling {
+ if tr.Type == html.ElementNode && strings.ToLower(tr.Data) == "tbody" {
+ node = tr
+ break
+ }
+ }
+ var header bool
+ var rows [][]string
+ for tr := node.FirstChild; tr != nil; tr = tr.NextSibling {
+ if tr.Type != html.ElementNode || strings.ToLower(tr.Data) != "tr" {
+ continue
+ }
+ var cols []string
+ if !header {
+ for th := tr.FirstChild; th != nil; th = th.NextSibling {
+ if th.Type != html.ElementNode || strings.ToLower(th.Data) != "th" {
+ continue
+ }
+ var buf bytes.Buffer
+ walk(th, &buf, 0, option)
+ cols = append(cols, buf.String())
+ }
+ if len(cols) > 0 {
+ rows = append(rows, cols)
+ header = true
+ continue
+ }
+ }
+ for td := tr.FirstChild; td != nil; td = td.NextSibling {
+ if td.Type != html.ElementNode || strings.ToLower(td.Data) != "td" {
+ continue
+ }
+ var buf bytes.Buffer
+ walk(td, &buf, 0, option)
+ cols = append(cols, buf.String())
+ }
+ rows = append(rows, cols)
+ }
+ maxcol := 0
+ for _, cols := range rows {
+ if len(cols) > maxcol {
+ maxcol = len(cols)
+ }
+ }
+ widths := make([]int, maxcol)
+ for _, cols := range rows {
+ for i := 0; i < maxcol; i++ {
+ if i < len(cols) {
+ width := runewidth.StringWidth(cols[i])
+ if widths[i] < width {
+ widths[i] = width
+ }
+ }
+ }
+ }
+ for i, cols := range rows {
+ for j := 0; j < maxcol; j++ {
+ fmt.Fprint(w, "|")
+ if j < len(cols) {
+ width := runewidth.StringWidth(cols[j])
+ fmt.Fprint(w, cols[j])
+ fmt.Fprint(w, strings.Repeat(" ", widths[j]-width))
+ } else {
+ fmt.Fprint(w, strings.Repeat(" ", widths[j]))
+ }
+ }
+ fmt.Fprint(w, "|\n")
+ if i == 0 && header {
+ for j := 0; j < maxcol; j++ {
+ fmt.Fprint(w, "|")
+ fmt.Fprint(w, strings.Repeat("-", widths[j]))
+ }
+ fmt.Fprint(w, "|\n")
+ }
+ }
+ fmt.Fprint(w, "\n")
+}
+
+var emptyElements = []string{
+ "area",
+ "base",
+ "br",
+ "col",
+ "embed",
+ "hr",
+ "img",
+ "input",
+ "keygen",
+ "link",
+ "meta",
+ "param",
+ "source",
+ "track",
+ "wbr",
+}
+
+func raw(node *html.Node, w io.Writer, option *Option) {
+ switch node.Type {
+ case html.ElementNode:
+ fmt.Fprintf(w, "<%s", node.Data)
+ for _, attr := range node.Attr {
+ fmt.Fprintf(w, " %s=%q", attr.Key, attr.Val)
+ }
+ found := false
+ tag := strings.ToLower(node.Data)
+ for _, e := range emptyElements {
+ if e == tag {
+ found = true
+ break
+ }
+ }
+ if found {
+ fmt.Fprint(w, "/>")
+ } else {
+ fmt.Fprint(w, ">")
+ for c := node.FirstChild; c != nil; c = c.NextSibling {
+ raw(c, w, option)
+ }
+ fmt.Fprintf(w, "</%s>", node.Data)
+ }
+ case html.TextNode:
+ fmt.Fprint(w, node.Data)
+ }
+}
+
+func bq(node *html.Node, w io.Writer, option *Option) {
+ if node.Type == html.TextNode {
+ fmt.Fprint(w, strings.Replace(node.Data, "\u00a0", " ", -1))
+ } else {
+ for c := node.FirstChild; c != nil; c = c.NextSibling {
+ bq(c, w, option)
+ }
+ }
+}
+
+func pre(node *html.Node, w io.Writer, option *Option) {
+ if node.Type == html.TextNode {
+ fmt.Fprint(w, node.Data)
+ } else {
+ for c := node.FirstChild; c != nil; c = c.NextSibling {
+ pre(c, w, option)
+ }
+ }
+}
+
+func walk(node *html.Node, w io.Writer, nest int, option *Option) {
+ if node.Type == html.TextNode {
+ if strings.TrimSpace(node.Data) != "" {
+ text := regexp.MustCompile(`[[:space:]][[:space:]]*`).ReplaceAllString(strings.Trim(node.Data, "\t\r\n"), " ")
+ fmt.Fprint(w, text)
+ }
+ }
+ n := 0
+ for c := node.FirstChild; c != nil; c = c.NextSibling {
+ switch c.Type {
+ case html.CommentNode:
+ fmt.Fprint(w, "<!--")
+ fmt.Fprint(w, c.Data)
+ fmt.Fprint(w, "-->\n")
+ case html.ElementNode:
+ switch strings.ToLower(c.Data) {
+ case "a":
+ fmt.Fprint(w, "[")
+ walk(c, w, nest, option)
+ fmt.Fprint(w, "]("+attr(c, "href")+")")
+ case "b", "strong":
+ fmt.Fprint(w, "**")
+ walk(c, w, nest, option)
+ fmt.Fprint(w, "**")
+ case "i", "em":
+ fmt.Fprint(w, "_")
+ walk(c, w, nest, option)
+ fmt.Fprint(w, "_")
+ case "del":
+ fmt.Fprint(w, "~~")
+ walk(c, w, nest, option)
+ fmt.Fprint(w, "~~")
+ case "br":
+ br(c, w, option)
+ fmt.Fprint(w, "\n\n")
+ case "p":
+ br(c, w, option)
+ walk(c, w, nest, option)
+ br(c, w, option)
+ fmt.Fprint(w, "\n\n")
+ case "code":
+ if !isChildOf(c, "pre") {
+ fmt.Fprint(w, "`")
+ pre(c, w, option)
+ fmt.Fprint(w, "`")
+ }
+ case "pre":
+ br(c, w, option)
+ var buf bytes.Buffer
+ pre(c, &buf, option)
+ var lang string
+ if option != nil && option.GuessLang != nil {
+ if guess, err := option.GuessLang(buf.String()); err == nil {
+ lang = guess
+ }
+ }
+ fmt.Fprint(w, "```"+lang+"\n")
+ fmt.Fprint(w, buf.String())
+ if !strings.HasSuffix(buf.String(), "\n") {
+ fmt.Fprint(w, "\n")
+ }
+ fmt.Fprint(w, "```\n\n")
+ case "div":
+ br(c, w, option)
+ walk(c, w, nest, option)
+ fmt.Fprint(w, "\n")
+ case "blockquote":
+ br(c, w, option)
+ var buf bytes.Buffer
+ if hasClass(c, "code") {
+ bq(c, &buf, option)
+ var lang string
+ if option != nil && option.GuessLang != nil {
+ if guess, err := option.GuessLang(buf.String()); err == nil {
+ lang = guess
+ }
+ }
+ fmt.Fprint(w, "```"+lang+"\n")
+ fmt.Fprint(w, strings.TrimLeft(buf.String(), "\n"))
+ if !strings.HasSuffix(buf.String(), "\n") {
+ fmt.Fprint(w, "\n")
+ }
+ fmt.Fprint(w, "```\n\n")
+ } else {
+ walk(c, &buf, nest+1, option)
+
+ if lines := strings.Split(strings.TrimSpace(buf.String()), "\n"); len(lines) > 0 {
+ for _, l := range lines {
+ fmt.Fprint(w, "> "+strings.TrimSpace(l)+"\n")
+ }
+ fmt.Fprint(w, "\n")
+ }
+ }
+ case "ul", "ol":
+ br(c, w, option)
+ var buf bytes.Buffer
+ walk(c, &buf, 1, option)
+ if lines := strings.Split(strings.TrimSpace(buf.String()), "\n"); len(lines) > 0 {
+ for i, l := range lines {
+ if i > 0 || nest > 0 {
+ fmt.Fprint(w, "\n")
+ }
+ fmt.Fprint(w, strings.Repeat(" ", nest)+strings.TrimSpace(l))
+ }
+ fmt.Fprint(w, "\n")
+ }
+ case "li":
+ br(c, w, option)
+ if isChildOf(c, "ul") {
+ fmt.Fprint(w, "* ")
+ } else if isChildOf(c, "ol") {
+ n++
+ fmt.Fprint(w, fmt.Sprintf("%d. ", n))
+ }
+ walk(c, w, nest, option)
+ fmt.Fprint(w, "\n")
+ case "h1", "h2", "h3", "h4", "h5", "h6":
+ br(c, w, option)
+ fmt.Fprint(w, strings.Repeat("#", int(rune(c.Data[1])-rune('0')))+" ")
+ walk(c, w, nest, option)
+ fmt.Fprint(w, "\n\n")
+ case "img":
+ fmt.Fprint(w, "!["+attr(c, "alt")+"]("+attr(c, "src")+")")
+ case "hr":
+ br(c, w, option)
+ fmt.Fprint(w, "\n---\n\n")
+ case "table":
+ br(c, w, option)
+ table(c, w, option)
+ case "style":
+ if option != nil && option.Style {
+ br(c, w, option)
+ raw(c, w, option)
+ fmt.Fprint(w, "\n\n")
+ }
+ case "script":
+ if option != nil && option.Script {
+ br(c, w, option)
+ raw(c, w, option)
+ fmt.Fprint(w, "\n\n")
+ }
+ default:
+ walk(c, w, nest, option)
+ }
+ default:
+ walk(c, w, nest, option)
+ }
+ }
+}
+
+type Option struct {
+ GuessLang func(string) (string, error)
+ Script bool
+ Style bool
+}
+
+// Convert convert HTML to Markdown. Read HTML from r and write to w.
+func Convert(w io.Writer, r io.Reader, option *Option) error {
+ doc, err := html.Parse(r)
+ if err != nil {
+ return err
+ }
+ walk(doc, w, 0, option)
+ fmt.Fprint(w, "\n")
+ return nil
+}