diff --git a/modules/git/grep.go b/modules/git/grep.go
index 6ca8456cdb..7cd1a96da6 100644
--- a/modules/git/grep.go
+++ b/modules/git/grep.go
@@ -27,6 +27,7 @@ type GrepResult struct {
type GrepOptions struct {
RefName string
MaxResultLimit int
+ MatchesPerFile int
ContextLineNumber int
IsFuzzy bool
PathSpec []setting.Glob
@@ -54,6 +55,9 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
var results []*GrepResult
cmd := NewCommand(ctx, "grep", "--null", "--break", "--heading", "--fixed-strings", "--line-number", "--ignore-case", "--full-name")
cmd.AddOptionValues("--context", fmt.Sprint(opts.ContextLineNumber))
+ if opts.MatchesPerFile > 0 {
+ cmd.AddOptionValues("--max-count", fmt.Sprint(opts.MatchesPerFile))
+ }
if opts.IsFuzzy {
words := strings.Fields(search)
for _, word := range words {
diff --git a/modules/git/grep_test.go b/modules/git/grep_test.go
index 15dc9e9d50..d2ed7300c1 100644
--- a/modules/git/grep_test.go
+++ b/modules/git/grep_test.go
@@ -44,6 +44,31 @@ func TestGrepSearch(t *testing.T) {
},
}, res)
+ res, err = GrepSearch(context.Background(), repo, "world", GrepOptions{MatchesPerFile: 1})
+ assert.NoError(t, err)
+ assert.Equal(t, []*GrepResult{
+ {
+ Filename: "i-am-a-python.p",
+ LineNumbers: []int{1},
+ LineCodes: []string{"## This is a simple file to do a hello world"},
+ },
+ {
+ Filename: "java-hello/main.java",
+ LineNumbers: []int{1},
+ LineCodes: []string{"public class HelloWorld"},
+ },
+ {
+ Filename: "main.vendor.java",
+ LineNumbers: []int{1},
+ LineCodes: []string{"public class HelloWorld"},
+ },
+ {
+ Filename: "python-hello/hello.py",
+ LineNumbers: []int{1},
+ LineCodes: []string{"## This is a simple file to do a hello world"},
+ },
+ }, res)
+
res, err = GrepSearch(context.Background(), repo, "no-such-content", GrepOptions{})
assert.NoError(t, err)
assert.Len(t, res, 0)
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index f9df8ac46c..294a3765c8 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -2016,6 +2016,8 @@ wiki.pages = Pages
wiki.last_updated = Last updated %s
wiki.page_name_desc = Enter a name for this Wiki page. Some special names are: "Home", "_Sidebar" and "_Footer".
wiki.original_git_entry_tooltip = View original Git file instead of using friendly link.
+wiki.search = Search wiki
+wiki.no_search_results = No results
activity = Activity
activity.navbar.pulse = Pulse
diff --git a/release-notes/8.0.0/feat/3847.md b/release-notes/8.0.0/feat/3847.md
new file mode 100644
index 0000000000..3ff9e872d7
--- /dev/null
+++ b/release-notes/8.0.0/feat/3847.md
@@ -0,0 +1,3 @@
+Basic wiki content search using git-grep
+ - The search results include the first ten matched files
+ - Only the first three matches per file are displayed
diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go
index f0743cc89c..4911fb6452 100644
--- a/routers/web/repo/wiki.go
+++ b/routers/web/repo/wiki.go
@@ -40,6 +40,7 @@ const (
tplWikiRevision base.TplName = "repo/wiki/revision"
tplWikiNew base.TplName = "repo/wiki/new"
tplWikiPages base.TplName = "repo/wiki/pages"
+ tplWikiSearch base.TplName = "repo/wiki/search"
)
// MustEnableWiki check if wiki is enabled, if external then redirect
@@ -795,3 +796,20 @@ func DeleteWikiPagePost(ctx *context.Context) {
ctx.JSONRedirect(ctx.Repo.RepoLink + "/wiki/")
}
+
+func WikiSearchContent(ctx *context.Context) {
+ keyword := ctx.FormTrim("q")
+ if keyword == "" {
+ ctx.HTML(http.StatusOK, tplWikiSearch)
+ return
+ }
+
+ res, err := wiki_service.SearchWikiContents(ctx, ctx.Repo.Repository, keyword)
+ if err != nil {
+ ctx.ServerError("SearchWikiContents", err)
+ return
+ }
+
+ ctx.Data["Results"] = res
+ ctx.HTML(http.StatusOK, tplWikiSearch)
+}
diff --git a/routers/web/web.go b/routers/web/web.go
index 77857d32be..0ab25fd7e3 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1417,6 +1417,7 @@ func registerRoutes(m *web.Route) {
})
m.Group("/wiki", func() {
+ m.Get("/search", repo.WikiSearchContent)
m.Get("/raw/*", repo.WikiRaw)
}, repo.MustEnableWiki)
diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go
index ec5d0fc9e2..24779d41e0 100644
--- a/services/wiki/wiki.go
+++ b/services/wiki/wiki.go
@@ -407,3 +407,19 @@ func DeleteWiki(ctx context.Context, repo *repo_model.Repository) error {
system_model.RemoveAllWithNotice(ctx, "Delete repository wiki", repo.WikiPath())
return nil
}
+
+func SearchWikiContents(ctx context.Context, repo *repo_model.Repository, keyword string) ([]*git.GrepResult, error) {
+ gitRepo, err := git.OpenRepository(ctx, repo.WikiPath())
+ if err != nil {
+ return nil, err
+ }
+ defer gitRepo.Close()
+
+ return git.GrepSearch(ctx, gitRepo, keyword, git.GrepOptions{
+ ContextLineNumber: 0,
+ IsFuzzy: true,
+ RefName: repo.GetWikiBranchName(),
+ MaxResultLimit: 10,
+ MatchesPerFile: 3,
+ })
+}
diff --git a/templates/repo/wiki/search.tmpl b/templates/repo/wiki/search.tmpl
new file mode 100644
index 0000000000..88b12b08b9
--- /dev/null
+++ b/templates/repo/wiki/search.tmpl
@@ -0,0 +1,12 @@
+{{if .Results}}
+ {{range .Results}}
+
+ {{.Filename}}
+ {{range .LineCodes}}
+ {{.}}