@@ -19,6 +19,7 @@ import ( | |||||
"golang.org/x/net/html" | "golang.org/x/net/html" | ||||
"code.gitea.io/gitea/modules/base" | "code.gitea.io/gitea/modules/base" | ||||
"code.gitea.io/gitea/modules/markup" | |||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
) | ) | ||||
@@ -40,18 +41,6 @@ func IsMarkdownFile(name string) bool { | |||||
return false | return false | ||||
} | } | ||||
// IsReadmeFile reports whether name looks like a README file | |||||
// based on its name. | |||||
func IsReadmeFile(name string) bool { | |||||
name = strings.ToLower(name) | |||||
if len(name) < 6 { | |||||
return false | |||||
} else if len(name) == 6 { | |||||
return name == "readme" | |||||
} | |||||
return name[:7] == "readme." | |||||
} | |||||
var ( | var ( | ||||
// MentionPattern matches string that mentions someone, e.g. @Unknwon | // MentionPattern matches string that mentions someone, e.g. @Unknwon | ||||
MentionPattern = regexp.MustCompile(`(\s|^|\W)@[0-9a-zA-Z-_\.]+`) | MentionPattern = regexp.MustCompile(`(\s|^|\W)@[0-9a-zA-Z-_\.]+`) | ||||
@@ -707,3 +696,31 @@ func RenderString(raw, urlPrefix string, metas map[string]string) string { | |||||
func RenderWiki(rawBytes []byte, urlPrefix string, metas map[string]string) string { | func RenderWiki(rawBytes []byte, urlPrefix string, metas map[string]string) string { | ||||
return string(render(rawBytes, urlPrefix, metas, true)) | return string(render(rawBytes, urlPrefix, metas, true)) | ||||
} | } | ||||
var ( | |||||
// MarkupName describes markup's name | |||||
MarkupName = "markdown" | |||||
) | |||||
func init() { | |||||
markup.RegisterParser(Parser{}) | |||||
} | |||||
// Parser implements markup.Parser | |||||
type Parser struct { | |||||
} | |||||
// Name implements markup.Parser | |||||
func (Parser) Name() string { | |||||
return MarkupName | |||||
} | |||||
// Extensions implements markup.Parser | |||||
func (Parser) Extensions() []string { | |||||
return setting.Markdown.FileExtensions | |||||
} | |||||
// Render implements markup.Parser | |||||
func (Parser) Render(rawBytes []byte, urlPrefix string, metas map[string]string, isWiki bool) []byte { | |||||
return render(rawBytes, urlPrefix, metas, isWiki) | |||||
} |
@@ -1,3 +1,7 @@ | |||||
// Copyright 2017 The Gitea Authors. All rights reserved. | |||||
// Use of this source code is governed by a MIT-style | |||||
// license that can be found in the LICENSE file. | |||||
package markdown_test | package markdown_test | ||||
import ( | import ( | ||||
@@ -586,31 +590,6 @@ func TestMisc_IsMarkdownFile(t *testing.T) { | |||||
} | } | ||||
} | } | ||||
func TestMisc_IsReadmeFile(t *testing.T) { | |||||
trueTestCases := []string{ | |||||
"readme", | |||||
"README", | |||||
"readME.mdown", | |||||
"README.md", | |||||
} | |||||
falseTestCases := []string{ | |||||
"test.md", | |||||
"wow.MARKDOWN", | |||||
"LOL.mDoWn", | |||||
"test", | |||||
"abcdefg", | |||||
"abcdefghijklmnopqrstuvwxyz", | |||||
"test.md.test", | |||||
} | |||||
for _, testCase := range trueTestCases { | |||||
assert.True(t, IsReadmeFile(testCase)) | |||||
} | |||||
for _, testCase := range falseTestCases { | |||||
assert.False(t, IsReadmeFile(testCase)) | |||||
} | |||||
} | |||||
func TestMisc_IsSameDomain(t *testing.T) { | func TestMisc_IsSameDomain(t *testing.T) { | ||||
setting.AppURL = AppURL | setting.AppURL = AppURL | ||||
setting.AppSubURL = AppSubURL | setting.AppSubURL = AppSubURL | ||||
@@ -0,0 +1,72 @@ | |||||
// Copyright 2017 The Gitea Authors. All rights reserved. | |||||
// Use of this source code is governed by a MIT-style | |||||
// license that can be found in the LICENSE file. | |||||
package markup | |||||
import ( | |||||
"path/filepath" | |||||
"strings" | |||||
) | |||||
// Parser defines an interface for parsering markup file to HTML | |||||
type Parser interface { | |||||
Name() string // markup format name | |||||
Extensions() []string | |||||
Render(rawBytes []byte, urlPrefix string, metas map[string]string, isWiki bool) []byte | |||||
} | |||||
var ( | |||||
parsers = make(map[string]Parser) | |||||
) | |||||
// RegisterParser registers a new markup file parser | |||||
func RegisterParser(parser Parser) { | |||||
for _, ext := range parser.Extensions() { | |||||
parsers[strings.ToLower(ext)] = parser | |||||
} | |||||
} | |||||
// Render renders markup file to HTML with all specific handling stuff. | |||||
func Render(filename string, rawBytes []byte, urlPrefix string, metas map[string]string) []byte { | |||||
return render(filename, rawBytes, urlPrefix, metas, false) | |||||
} | |||||
func render(filename string, rawBytes []byte, urlPrefix string, metas map[string]string, isWiki bool) []byte { | |||||
extension := strings.ToLower(filepath.Ext(filename)) | |||||
if parser, ok := parsers[extension]; ok { | |||||
return parser.Render(rawBytes, urlPrefix, metas, isWiki) | |||||
} | |||||
return nil | |||||
} | |||||
// RenderString renders Markdown to HTML with special links and returns string type. | |||||
func RenderString(filename string, raw, urlPrefix string, metas map[string]string) string { | |||||
return string(render(filename, []byte(raw), urlPrefix, metas, false)) | |||||
} | |||||
// RenderWiki renders markdown wiki page to HTML and return HTML string | |||||
func RenderWiki(filename string, rawBytes []byte, urlPrefix string, metas map[string]string) string { | |||||
return string(render(filename, rawBytes, urlPrefix, metas, true)) | |||||
} | |||||
// Type returns if markup format via the filename | |||||
func Type(filename string) string { | |||||
extension := strings.ToLower(filepath.Ext(filename)) | |||||
if parser, ok := parsers[extension]; ok { | |||||
return parser.Name() | |||||
} | |||||
return "" | |||||
} | |||||
// IsReadmeFile reports whether name looks like a README file | |||||
// based on its name. | |||||
func IsReadmeFile(name string) bool { | |||||
name = strings.ToLower(name) | |||||
if len(name) < 6 { | |||||
return false | |||||
} else if len(name) == 6 { | |||||
return name == "readme" | |||||
} | |||||
return name[:7] == "readme." | |||||
} |
@@ -0,0 +1,36 @@ | |||||
// Copyright 2017 The Gitea Authors. All rights reserved. | |||||
// Use of this source code is governed by a MIT-style | |||||
// license that can be found in the LICENSE file. | |||||
package markup | |||||
import ( | |||||
"testing" | |||||
"github.com/stretchr/testify/assert" | |||||
) | |||||
func TestMisc_IsReadmeFile(t *testing.T) { | |||||
trueTestCases := []string{ | |||||
"readme", | |||||
"README", | |||||
"readME.mdown", | |||||
"README.md", | |||||
} | |||||
falseTestCases := []string{ | |||||
"test.md", | |||||
"wow.MARKDOWN", | |||||
"LOL.mDoWn", | |||||
"test", | |||||
"abcdefg", | |||||
"abcdefghijklmnopqrstuvwxyz", | |||||
"test.md.test", | |||||
} | |||||
for _, testCase := range trueTestCases { | |||||
assert.True(t, IsReadmeFile(testCase)) | |||||
} | |||||
for _, testCase := range falseTestCases { | |||||
assert.False(t, IsReadmeFile(testCase)) | |||||
} | |||||
} |
@@ -21,7 +21,7 @@ import ( | |||||
"code.gitea.io/gitea/modules/highlight" | "code.gitea.io/gitea/modules/highlight" | ||||
"code.gitea.io/gitea/modules/lfs" | "code.gitea.io/gitea/modules/lfs" | ||||
"code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
"code.gitea.io/gitea/modules/markdown" | |||||
"code.gitea.io/gitea/modules/markup" | |||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
"code.gitea.io/gitea/modules/templates" | "code.gitea.io/gitea/modules/templates" | ||||
"github.com/Unknwon/paginater" | "github.com/Unknwon/paginater" | ||||
@@ -56,7 +56,7 @@ func renderDirectory(ctx *context.Context, treeLink string) { | |||||
var readmeFile *git.Blob | var readmeFile *git.Blob | ||||
for _, entry := range entries { | for _, entry := range entries { | ||||
if entry.IsDir() || !markdown.IsReadmeFile(entry.Name()) { | |||||
if entry.IsDir() || !markup.IsReadmeFile(entry.Name()) { | |||||
continue | continue | ||||
} | } | ||||
@@ -87,17 +87,16 @@ func renderDirectory(ctx *context.Context, treeLink string) { | |||||
if isTextFile { | if isTextFile { | ||||
d, _ := ioutil.ReadAll(dataRc) | d, _ := ioutil.ReadAll(dataRc) | ||||
buf = append(buf, d...) | buf = append(buf, d...) | ||||
switch { | |||||
case markdown.IsMarkdownFile(readmeFile.Name()): | |||||
newbuf := markup.Render(readmeFile.Name(), buf, treeLink, ctx.Repo.Repository.ComposeMetas()) | |||||
if newbuf != nil { | |||||
ctx.Data["IsMarkdown"] = true | ctx.Data["IsMarkdown"] = true | ||||
buf = markdown.Render(buf, treeLink, ctx.Repo.Repository.ComposeMetas()) | |||||
default: | |||||
} else { | |||||
// FIXME This is the only way to show non-markdown files | // FIXME This is the only way to show non-markdown files | ||||
// instead of a broken "View Raw" link | // instead of a broken "View Raw" link | ||||
ctx.Data["IsMarkdown"] = true | ctx.Data["IsMarkdown"] = true | ||||
buf = bytes.Replace(buf, []byte("\n"), []byte(`<br>`), -1) | |||||
newbuf = bytes.Replace(buf, []byte("\n"), []byte(`<br>`), -1) | |||||
} | } | ||||
ctx.Data["FileContent"] = string(buf) | |||||
ctx.Data["FileContent"] = string(newbuf) | |||||
} | } | ||||
} | } | ||||
@@ -182,13 +181,15 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st | |||||
d, _ := ioutil.ReadAll(dataRc) | d, _ := ioutil.ReadAll(dataRc) | ||||
buf = append(buf, d...) | buf = append(buf, d...) | ||||
isMarkdown := markdown.IsMarkdownFile(blob.Name()) | |||||
ctx.Data["IsMarkdown"] = isMarkdown | |||||
tp := markup.Type(blob.Name()) | |||||
isSupportedMarkup := tp != "" | |||||
// FIXME: currently set IsMarkdown for compitable | |||||
ctx.Data["IsMarkdown"] = isSupportedMarkup | |||||
readmeExist := isMarkdown || markdown.IsReadmeFile(blob.Name()) | |||||
readmeExist := isSupportedMarkup || markup.IsReadmeFile(blob.Name()) | |||||
ctx.Data["ReadmeExist"] = readmeExist | ctx.Data["ReadmeExist"] = readmeExist | ||||
if readmeExist && isMarkdown { | |||||
ctx.Data["FileContent"] = string(markdown.Render(buf, path.Dir(treeLink), ctx.Repo.Repository.ComposeMetas())) | |||||
if readmeExist && isSupportedMarkup { | |||||
ctx.Data["FileContent"] = string(markup.Render(blob.Name(), buf, path.Dir(treeLink), ctx.Repo.Repository.ComposeMetas())) | |||||
} else { | } else { | ||||
// Building code view blocks with line number on server side. | // Building code view blocks with line number on server side. | ||||
var fileContent string | var fileContent string | ||||
@@ -19,6 +19,7 @@ import ( | |||||
"code.gitea.io/gitea/modules/base" | "code.gitea.io/gitea/modules/base" | ||||
"code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
"code.gitea.io/gitea/modules/markdown" | "code.gitea.io/gitea/modules/markdown" | ||||
"code.gitea.io/gitea/modules/markup" | |||||
) | ) | ||||
const ( | const ( | ||||
@@ -322,7 +323,7 @@ func Wiki(ctx *context.Context) { | |||||
} | } | ||||
ename := entry.Name() | ename := entry.Name() | ||||
if !markdown.IsMarkdownFile(ename) { | |||||
if markup.Type(ename) != markdown.MarkupName { | |||||
ext := strings.ToUpper(filepath.Ext(ename)) | ext := strings.ToUpper(filepath.Ext(ename)) | ||||
ctx.Data["FormatWarning"] = fmt.Sprintf("%s rendering is not supported at the moment. Rendered as Markdown.", ext) | ctx.Data["FormatWarning"] = fmt.Sprintf("%s rendering is not supported at the moment. Rendered as Markdown.", ext) | ||||
} | } | ||||