You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

markdown.go 2.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package base
  5. import (
  6. "bytes"
  7. "path"
  8. "path/filepath"
  9. "strings"
  10. "github.com/gogits/gfm"
  11. )
  12. func isletter(c byte) bool {
  13. return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
  14. }
  15. func isalnum(c byte) bool {
  16. return (c >= '0' && c <= '9') || isletter(c)
  17. }
  18. var validLinks = [][]byte{[]byte("http://"), []byte("https://"), []byte("ftp://"), []byte("mailto://")}
  19. func isLink(link []byte) bool {
  20. for _, prefix := range validLinks {
  21. if len(link) > len(prefix) && bytes.Equal(bytes.ToLower(link[:len(prefix)]), prefix) && isalnum(link[len(prefix)]) {
  22. return true
  23. }
  24. }
  25. return false
  26. }
  27. func IsMarkdownFile(name string) bool {
  28. name = strings.ToLower(name)
  29. switch filepath.Ext(name) {
  30. case "md", "markdown":
  31. return true
  32. }
  33. return false
  34. }
  35. func IsReadmeFile(name string) bool {
  36. name = strings.ToLower(name)
  37. if len(name) < 6 {
  38. return false
  39. }
  40. if name[:6] == "readme" {
  41. return true
  42. }
  43. return false
  44. }
  45. type CustomRender struct {
  46. gfm.Renderer
  47. urlPrefix string
  48. }
  49. func (options *CustomRender) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
  50. if len(link) > 0 && !isLink(link) {
  51. if link[0] == '#' {
  52. link = append([]byte(options.urlPrefix), link...)
  53. } else {
  54. link = []byte(path.Join(options.urlPrefix, string(link)))
  55. }
  56. }
  57. options.Renderer.Link(out, link, title, content)
  58. }
  59. func RenderMarkdown(rawBytes []byte, urlPrefix string) []byte {
  60. htmlFlags := 0
  61. htmlFlags |= gfm.HTML_USE_XHTML
  62. // htmlFlags |= gfm.HTML_USE_SMARTYPANTS
  63. // htmlFlags |= gfm.HTML_SMARTYPANTS_FRACTIONS
  64. // htmlFlags |= gfm.HTML_SMARTYPANTS_LATEX_DASHES
  65. htmlFlags |= gfm.HTML_SKIP_HTML
  66. htmlFlags |= gfm.HTML_SKIP_STYLE
  67. htmlFlags |= gfm.HTML_SKIP_SCRIPT
  68. htmlFlags |= gfm.HTML_GITHUB_BLOCKCODE
  69. htmlFlags |= gfm.HTML_OMIT_CONTENTS
  70. htmlFlags |= gfm.HTML_COMPLETE_PAGE
  71. renderer := &CustomRender{
  72. Renderer: gfm.HtmlRenderer(htmlFlags, "", ""),
  73. urlPrefix: urlPrefix,
  74. }
  75. // set up the parser
  76. extensions := 0
  77. extensions |= gfm.EXTENSION_NO_INTRA_EMPHASIS
  78. extensions |= gfm.EXTENSION_TABLES
  79. extensions |= gfm.EXTENSION_FENCED_CODE
  80. extensions |= gfm.EXTENSION_AUTOLINK
  81. extensions |= gfm.EXTENSION_STRIKETHROUGH
  82. extensions |= gfm.EXTENSION_HARD_LINE_BREAK
  83. extensions |= gfm.EXTENSION_SPACE_HEADERS
  84. extensions |= gfm.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK
  85. body := gfm.Markdown(rawBytes, renderer, extensions)
  86. return body
  87. }