aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/content/doc/advanced/config-cheat-sheet.en-us.md1
-rw-r--r--docs/content/doc/advanced/repo-indexer.en-us.md2
-rw-r--r--modules/analyze/code_langauge.go36
-rw-r--r--modules/git/repo_language_stats.go27
-rw-r--r--modules/indexer/code/bleve.go114
-rw-r--r--modules/indexer/code/bleve_test.go9
-rw-r--r--modules/indexer/code/indexer.go24
-rw-r--r--modules/indexer/code/search.go21
-rw-r--r--modules/indexer/code/wrapped.go6
-rw-r--r--modules/setting/indexer.go3
-rw-r--r--options/locale/locale_en-US.ini1
-rw-r--r--routers/home.go13
-rw-r--r--routers/repo/search.go10
-rw-r--r--templates/explore/code.tmpl22
-rw-r--r--templates/repo/search.tmpl22
-rw-r--r--vendor/github.com/blevesearch/bleve/analysis/analyzer/keyword/keyword.go38
-rw-r--r--vendor/github.com/blevesearch/bleve/analysis/tokenizer/single/single.go49
-rw-r--r--vendor/modules.txt2
-rw-r--r--web_src/less/_base.less4
-rw-r--r--web_src/less/_repository.less5
20 files changed, 346 insertions, 63 deletions
diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
index b21a25faa0..e58a459e4e 100644
--- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md
+++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
@@ -242,6 +242,7 @@ relation to port exhaustion.
- `REPO_INDEXER_PATH`: **indexers/repos.bleve**: Index file used for code search.
- `REPO_INDEXER_INCLUDE`: **empty**: A comma separated list of glob patterns (see https://github.com/gobwas/glob) to **include** in the index. Use `**.txt` to match any files with .txt extension. An empty list means include all files.
- `REPO_INDEXER_EXCLUDE`: **empty**: A comma separated list of glob patterns (see https://github.com/gobwas/glob) to **exclude** from the index. Files that match this list will not be indexed, even if they match in `REPO_INDEXER_INCLUDE`.
+- `REPO_INDEXER_EXCLUDE_VENDORED`: **true**: Exclude vendored files from index.
- `UPDATE_BUFFER_LEN`: **20**: Buffer length of index request.
- `MAX_FILE_SIZE`: **1048576**: Maximum size in bytes of files to be indexed.
- `STARTUP_TIMEOUT`: **30s**: If the indexer takes longer than this timeout to start - fail. (This timeout will be added to the hammer time above for child processes - as bleve will not start until the previous parent is shutdown.) Set to zero to never timeout.
diff --git a/docs/content/doc/advanced/repo-indexer.en-us.md b/docs/content/doc/advanced/repo-indexer.en-us.md
index 66f09df939..b32df7b883 100644
--- a/docs/content/doc/advanced/repo-indexer.en-us.md
+++ b/docs/content/doc/advanced/repo-indexer.en-us.md
@@ -42,6 +42,8 @@ Gitea applies glob pattern matching from the [`gobwas/glob` library](https://git
Limiting the list of files prevents the indexes from becoming polluted with derived or irrelevant files (e.g. lss, sym, map, etc.), so the search results are more relevant. It can also help reduce the index size.
+`REPO_INDEXER_EXCLUDE_VENDORED` (default: true) excludes vendored files from index.
+
`REPO_INDEXER_INCLUDE` (default: empty) is a comma separated list of glob patterns to **include** in the index. An empty list means "_include all files_".
`REPO_INDEXER_EXCLUDE` (default: empty) is a comma separated list of glob patterns to **exclude** from the index. Files that match this list will not be indexed. `REPO_INDEXER_EXCLUDE` takes precedence over `REPO_INDEXER_INCLUDE`.
diff --git a/modules/analyze/code_langauge.go b/modules/analyze/code_langauge.go
new file mode 100644
index 0000000000..f7dd3e7cfc
--- /dev/null
+++ b/modules/analyze/code_langauge.go
@@ -0,0 +1,36 @@
+// Copyright 2020 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 analyze
+
+import (
+ "path/filepath"
+
+ "github.com/src-d/enry/v2"
+)
+
+// GetCodeLanguageWithCallback detects code language based on file name and content using callback
+func GetCodeLanguageWithCallback(filename string, contentFunc func() ([]byte, error)) string {
+ if language, ok := enry.GetLanguageByExtension(filename); ok {
+ return language
+ }
+
+ if language, ok := enry.GetLanguageByFilename(filename); ok {
+ return language
+ }
+
+ content, err := contentFunc()
+ if err != nil {
+ return enry.OtherLanguage
+ }
+
+ return enry.GetLanguage(filepath.Base(filename), content)
+}
+
+// GetCodeLanguage detects code language based on file name and content
+func GetCodeLanguage(filename string, content []byte) string {
+ return GetCodeLanguageWithCallback(filename, func() ([]byte, error) {
+ return content, nil
+ })
+}
diff --git a/modules/git/repo_language_stats.go b/modules/git/repo_language_stats.go
index ffe6dd0848..305fb97795 100644
--- a/modules/git/repo_language_stats.go
+++ b/modules/git/repo_language_stats.go
@@ -9,7 +9,8 @@ import (
"io"
"io/ioutil"
"math"
- "path/filepath"
+
+ "code.gitea.io/gitea/modules/analyze"
"github.com/src-d/enry/v2"
"gopkg.in/src-d/go-git.v4"
@@ -51,25 +52,15 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]float32, e
// TODO: Use .gitattributes file for linguist overrides
- language, ok := enry.GetLanguageByExtension(f.Name)
- if !ok {
- if language, ok = enry.GetLanguageByFilename(f.Name); !ok {
- content, err := readFile(f, fileSizeLimit)
- if err != nil {
- return nil
- }
-
- language = enry.GetLanguage(filepath.Base(f.Name), content)
- if language == enry.OtherLanguage {
- return nil
- }
- }
+ language := analyze.GetCodeLanguageWithCallback(f.Name, func() ([]byte, error) {
+ return readFile(f, fileSizeLimit)
+ })
+ if language == enry.OtherLanguage || language == "" {
+ return nil
}
- if language != "" {
- sizes[language] += f.Size
- total += f.Size
- }
+ sizes[language] += f.Size
+ total += f.Size
return nil
})
diff --git a/modules/indexer/code/bleve.go b/modules/indexer/code/bleve.go
index 6052304f83..39171d17a6 100644
--- a/modules/indexer/code/bleve.go
+++ b/modules/indexer/code/bleve.go
@@ -9,16 +9,20 @@ import (
"os"
"strconv"
"strings"
+ "time"
"code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/analyze"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/charset"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/timeutil"
"github.com/blevesearch/bleve"
- "github.com/blevesearch/bleve/analysis/analyzer/custom"
+ analyzer_custom "github.com/blevesearch/bleve/analysis/analyzer/custom"
+ analyzer_keyword "github.com/blevesearch/bleve/analysis/analyzer/keyword"
"github.com/blevesearch/bleve/analysis/token/lowercase"
"github.com/blevesearch/bleve/analysis/token/unicodenorm"
"github.com/blevesearch/bleve/analysis/tokenizer/unicode"
@@ -26,6 +30,7 @@ import (
"github.com/blevesearch/bleve/mapping"
"github.com/blevesearch/bleve/search/query"
"github.com/ethantkoenig/rupture"
+ "github.com/src-d/enry/v2"
)
const unicodeNormalizeName = "unicodeNormalize"
@@ -86,8 +91,11 @@ func openIndexer(path string, latestVersion int) (bleve.Index, error) {
// RepoIndexerData data stored in the repo indexer
type RepoIndexerData struct {
- RepoID int64
- Content string
+ RepoID int64
+ CommitID string
+ Content string
+ Language string
+ UpdatedAt time.Time
}
// Type returns the document type, for bleve's mapping.Classifier interface.
@@ -95,7 +103,11 @@ func (d *RepoIndexerData) Type() string {
return repoIndexerDocType
}
-func addUpdate(update fileUpdate, repo *models.Repository, batch rupture.FlushingBatch) error {
+func addUpdate(commitSha string, update fileUpdate, repo *models.Repository, batch rupture.FlushingBatch) error {
+ // Ignore vendored files in code search
+ if setting.Indexer.ExcludeVendored && enry.IsVendor(update.Filename) {
+ return nil
+ }
stdout, err := git.NewCommand("cat-file", "-s", update.BlobSha).
RunInDir(repo.RepoPath())
if err != nil {
@@ -118,8 +130,11 @@ func addUpdate(update fileUpdate, repo *models.Repository, batch rupture.Flushin
id := filenameIndexerID(repo.ID, update.Filename)
return batch.Index(id, &RepoIndexerData{
- RepoID: repo.ID,
- Content: string(charset.ToUTF8DropErrors(fileContents)),
+ RepoID: repo.ID,
+ CommitID: commitSha,
+ Content: string(charset.ToUTF8DropErrors(fileContents)),
+ Language: analyze.GetCodeLanguage(update.Filename, fileContents),
+ UpdatedAt: time.Now().UTC(),
})
}
@@ -131,7 +146,7 @@ func addDelete(filename string, repo *models.Repository, batch rupture.FlushingB
const (
repoIndexerAnalyzer = "repoIndexerAnalyzer"
repoIndexerDocType = "repoIndexerDocType"
- repoIndexerLatestVersion = 4
+ repoIndexerLatestVersion = 5
)
// createRepoIndexer create a repo indexer if one does not already exist
@@ -145,11 +160,21 @@ func createRepoIndexer(path string, latestVersion int) (bleve.Index, error) {
textFieldMapping.IncludeInAll = false
docMapping.AddFieldMappingsAt("Content", textFieldMapping)
+ termFieldMapping := bleve.NewTextFieldMapping()
+ termFieldMapping.IncludeInAll = false
+ termFieldMapping.Analyzer = analyzer_keyword.Name
+ docMapping.AddFieldMappingsAt("Language", termFieldMapping)
+ docMapping.AddFieldMappingsAt("CommitID", termFieldMapping)
+
+ timeFieldMapping := bleve.NewDateTimeFieldMapping()
+ timeFieldMapping.IncludeInAll = false
+ docMapping.AddFieldMappingsAt("UpdatedAt", timeFieldMapping)
+
mapping := bleve.NewIndexMapping()
if err := addUnicodeNormalizeTokenFilter(mapping); err != nil {
return nil, err
} else if err := mapping.AddCustomAnalyzer(repoIndexerAnalyzer, map[string]interface{}{
- "type": custom.Name,
+ "type": analyzer_custom.Name,
"char_filters": []string{},
"tokenizer": unicode.Name,
"token_filters": []string{unicodeNormalizeName, lowercase.Name},
@@ -255,7 +280,7 @@ func (b *BleveIndexer) Index(repoID int64) error {
batch := rupture.NewFlushingBatch(b.indexer, maxBatchSize)
for _, update := range changes.Updates {
- if err := addUpdate(update, repo, batch); err != nil {
+ if err := addUpdate(sha, update, repo, batch); err != nil {
return err
}
}
@@ -289,7 +314,7 @@ func (b *BleveIndexer) Delete(repoID int64) error {
// Search searches for files in the specified repo.
// Returns the matching file-paths
-func (b *BleveIndexer) Search(repoIDs []int64, keyword string, page, pageSize int) (int64, []*SearchResult, error) {
+func (b *BleveIndexer) Search(repoIDs []int64, language, keyword string, page, pageSize int) (int64, []*SearchResult, []*SearchResultLanguages, error) {
phraseQuery := bleve.NewMatchPhraseQuery(keyword)
phraseQuery.FieldVal = "Content"
phraseQuery.Analyzer = repoIndexerAnalyzer
@@ -309,16 +334,35 @@ func (b *BleveIndexer) Search(repoIDs []int64, keyword string, page, pageSize in
indexerQuery = phraseQuery
}
+ // Save for reuse without language filter
+ facetQuery := indexerQuery
+ if len(language) > 0 {
+ languageQuery := bleve.NewMatchQuery(language)
+ languageQuery.FieldVal = "Language"
+ languageQuery.Analyzer = analyzer_keyword.Name
+
+ indexerQuery = bleve.NewConjunctionQuery(
+ indexerQuery,
+ languageQuery,
+ )
+ }
+
from := (page - 1) * pageSize
searchRequest := bleve.NewSearchRequestOptions(indexerQuery, pageSize, from, false)
- searchRequest.Fields = []string{"Content", "RepoID"}
+ searchRequest.Fields = []string{"Content", "RepoID", "Language", "CommitID", "UpdatedAt"}
searchRequest.IncludeLocations = true
+ if len(language) == 0 {
+ searchRequest.AddFacet("languages", bleve.NewFacetRequest("Language", 10))
+ }
+
result, err := b.indexer.Search(searchRequest)
if err != nil {
- return 0, nil, err
+ return 0, nil, nil, err
}
+ total := int64(result.Total)
+
searchResults := make([]*SearchResult, len(result.Hits))
for i, hit := range result.Hits {
var startIndex, endIndex int = -1, -1
@@ -333,13 +377,47 @@ func (b *BleveIndexer) Search(repoIDs []int64, keyword string, page, pageSize in
endIndex = locationEnd
}
}
+ language := hit.Fields["Language"].(string)
+ var updatedUnix timeutil.TimeStamp
+ if t, err := time.Parse(time.RFC3339, hit.Fields["UpdatedAt"].(string)); err == nil {
+ updatedUnix = timeutil.TimeStamp(t.Unix())
+ }
searchResults[i] = &SearchResult{
- RepoID: int64(hit.Fields["RepoID"].(float64)),
- StartIndex: startIndex,
- EndIndex: endIndex,
- Filename: filenameOfIndexerID(hit.ID),
- Content: hit.Fields["Content"].(string),
+ RepoID: int64(hit.Fields["RepoID"].(float64)),
+ StartIndex: startIndex,
+ EndIndex: endIndex,
+ Filename: filenameOfIndexerID(hit.ID),
+ Content: hit.Fields["Content"].(string),
+ CommitID: hit.Fields["CommitID"].(string),
+ UpdatedUnix: updatedUnix,
+ Language: language,
+ Color: enry.GetColor(language),
+ }
+ }
+
+ searchResultLanguages := make([]*SearchResultLanguages, 0, 10)
+ if len(language) > 0 {
+ // Use separate query to go get all language counts
+ facetRequest := bleve.NewSearchRequestOptions(facetQuery, 1, 0, false)
+ facetRequest.Fields = []string{"Content", "RepoID", "Language", "CommitID", "UpdatedAt"}
+ facetRequest.IncludeLocations = true
+ facetRequest.AddFacet("languages", bleve.NewFacetRequest("Language", 10))
+
+ if result, err = b.indexer.Search(facetRequest); err != nil {
+ return 0, nil, nil, err
+ }
+
+ }
+ languagesFacet := result.Facets["languages"]
+ for _, term := range languagesFacet.Terms {
+ if len(term.Term) == 0 {
+ continue
}
+ searchResultLanguages = append(searchResultLanguages, &SearchResultLanguages{
+ Language: term.Term,
+ Color: enry.GetColor(term.Term),
+ Count: term.Count,
+ })
}
- return int64(result.Total), searchResults, nil
+ return total, searchResults, searchResultLanguages, nil
}
diff --git a/modules/indexer/code/bleve_test.go b/modules/indexer/code/bleve_test.go
index 695dceb259..89cfceea2d 100644
--- a/modules/indexer/code/bleve_test.go
+++ b/modules/indexer/code/bleve_test.go
@@ -49,27 +49,34 @@ func TestIndexAndSearch(t *testing.T) {
keywords = []struct {
Keyword string
IDs []int64
+ Langs int
}{
{
Keyword: "Description",
IDs: []int64{1},
+ Langs: 1,
},
{
Keyword: "repo1",
IDs: []int64{1},
+ Langs: 1,
},
{
Keyword: "non-exist",
IDs: []int64{},
+ Langs: 0,
},
}
)
for _, kw := range keywords {
- total, res, err := idx.Search(nil, kw.Keyword, 1, 10)
+ total, res, langs, err := idx.Search(nil, "", kw.Keyword, 1, 10)
assert.NoError(t, err)
assert.EqualValues(t, len(kw.IDs), total)
+ assert.NotNil(t, langs)
+ assert.Len(t, langs, kw.Langs)
+
var ids = make([]int64, 0, len(res))
for _, hit := range res {
ids = append(ids, hit.RepoID)
diff --git a/modules/indexer/code/indexer.go b/modules/indexer/code/indexer.go
index 3f9461cd0e..6cbda1491b 100644
--- a/modules/indexer/code/indexer.go
+++ b/modules/indexer/code/indexer.go
@@ -12,22 +12,34 @@ import (
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/timeutil"
)
// SearchResult result of performing a search in a repo
type SearchResult struct {
- RepoID int64
- StartIndex int
- EndIndex int
- Filename string
- Content string
+ RepoID int64
+ StartIndex int
+ EndIndex int
+ Filename string
+ Content string
+ CommitID string
+ UpdatedUnix timeutil.TimeStamp
+ Language string
+ Color string
+}
+
+// SearchResultLanguages result of top languages count in search results
+type SearchResultLanguages struct {
+ Language string
+ Color string
+ Count int
}
// Indexer defines an interface to indexer issues contents
type Indexer interface {
Index(repoID int64) error
Delete(repoID int64) error
- Search(repoIDs []int64, keyword string, page, pageSize int) (int64, []*SearchResult, error)
+ Search(repoIDs []int64, language, keyword string, page, pageSize int) (int64, []*SearchResult, []*SearchResultLanguages, error)
Close()
}
diff --git a/modules/indexer/code/search.go b/modules/indexer/code/search.go
index 18f193a532..ca57b3ff88 100644
--- a/modules/indexer/code/search.go
+++ b/modules/indexer/code/search.go
@@ -11,6 +11,7 @@ import (
"strings"
"code.gitea.io/gitea/modules/highlight"
+ "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
)
@@ -18,6 +19,10 @@ import (
type Result struct {
RepoID int64
Filename string
+ CommitID string
+ UpdatedUnix timeutil.TimeStamp
+ Language string
+ Color string
HighlightClass string
LineNumbers []int
FormattedLines gotemplate.HTML
@@ -100,6 +105,10 @@ func searchResult(result *SearchResult, startIndex, endIndex int) (*Result, erro
return &Result{
RepoID: result.RepoID,
Filename: result.Filename,
+ CommitID: result.CommitID,
+ UpdatedUnix: result.UpdatedUnix,
+ Language: result.Language,
+ Color: result.Color,
HighlightClass: highlight.FileNameToHighlightClass(result.Filename),
LineNumbers: lineNumbers,
FormattedLines: gotemplate.HTML(formattedLinesBuffer.String()),
@@ -107,14 +116,14 @@ func searchResult(result *SearchResult, startIndex, endIndex int) (*Result, erro
}
// PerformSearch perform a search on a repository
-func PerformSearch(repoIDs []int64, keyword string, page, pageSize int) (int, []*Result, error) {
+func PerformSearch(repoIDs []int64, language, keyword string, page, pageSize int) (int, []*Result, []*SearchResultLanguages, error) {
if len(keyword) == 0 {
- return 0, nil, nil
+ return 0, nil, nil, nil
}
- total, results, err := indexer.Search(repoIDs, keyword, page, pageSize)
+ total, results, resultLanguages, err := indexer.Search(repoIDs, language, keyword, page, pageSize)
if err != nil {
- return 0, nil, err
+ return 0, nil, nil, err
}
displayResults := make([]*Result, len(results))
@@ -123,8 +132,8 @@ func PerformSearch(repoIDs []int64, keyword string, page, pageSize int) (int, []
startIndex, endIndex := indices(result.Content, result.StartIndex, result.EndIndex)
displayResults[i], err = searchResult(result, startIndex, endIndex)
if err != nil {
- return 0, nil, err
+ return 0, nil, nil, err
}
}
- return int(total), displayResults, nil
+ return int(total), displayResults, resultLanguages, nil
}
diff --git a/modules/indexer/code/wrapped.go b/modules/indexer/code/wrapped.go
index 6a20883989..926597a382 100644
--- a/modules/indexer/code/wrapped.go
+++ b/modules/indexer/code/wrapped.go
@@ -71,12 +71,12 @@ func (w *wrappedIndexer) Delete(repoID int64) error {
return indexer.Delete(repoID)
}
-func (w *wrappedIndexer) Search(repoIDs []int64, keyword string, page, pageSize int) (int64, []*SearchResult, error) {
+func (w *wrappedIndexer) Search(repoIDs []int64, language, keyword string, page, pageSize int) (int64, []*SearchResult, []*SearchResultLanguages, error) {
indexer, err := w.get()
if err != nil {
- return 0, nil, err
+ return 0, nil, nil, err
}
- return indexer.Search(repoIDs, keyword, page, pageSize)
+ return indexer.Search(repoIDs, language, keyword, page, pageSize)
}
diff --git a/modules/setting/indexer.go b/modules/setting/indexer.go
index 859535281c..4d4df62014 100644
--- a/modules/setting/indexer.go
+++ b/modules/setting/indexer.go
@@ -41,6 +41,7 @@ var (
MaxIndexerFileSize int64
IncludePatterns []glob.Glob
ExcludePatterns []glob.Glob
+ ExcludeVendored bool
}{
IssueType: "bleve",
IssuePath: "indexers/issues.bleve",
@@ -52,6 +53,7 @@ var (
IssueQueueBatchNumber: 20,
MaxIndexerFileSize: 1024 * 1024,
+ ExcludeVendored: true,
}
)
@@ -77,6 +79,7 @@ func newIndexerService() {
}
Indexer.IncludePatterns = IndexerGlobFromString(sec.Key("REPO_INDEXER_INCLUDE").MustString(""))
Indexer.ExcludePatterns = IndexerGlobFromString(sec.Key("REPO_INDEXER_EXCLUDE").MustString(""))
+ Indexer.ExcludeVendored = sec.Key("REPO_INDEXER_EXCLUDE_VENDORED").MustBool(true)
Indexer.UpdateQueueLength = sec.Key("UPDATE_BUFFER_LEN").MustInt(20)
Indexer.MaxIndexerFileSize = sec.Key("MAX_FILE_SIZE").MustInt64(1024 * 1024)
Indexer.StartupTimeout = sec.Key("STARTUP_TIMEOUT").MustDuration(30 * time.Second)
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index dbd1a3680d..821eaccab6 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -215,6 +215,7 @@ user_no_results = No matching users found.
org_no_results = No matching organizations found.
code_no_results = No source code matching your search term found.
code_search_results = Search results for '%s'
+code_last_indexed_at = Last indexed %s
[auth]
create_new_account = Register Account
diff --git a/routers/home.go b/routers/home.go
index 77a7e153e2..1b8c4cd17b 100644
--- a/routers/home.go
+++ b/routers/home.go
@@ -290,6 +290,7 @@ func ExploreCode(ctx *context.Context) {
ctx.Data["PageIsExplore"] = true
ctx.Data["PageIsExploreCode"] = true
+ language := strings.TrimSpace(ctx.Query("l"))
keyword := strings.TrimSpace(ctx.Query("q"))
page := ctx.QueryInt("page")
if page <= 0 {
@@ -317,8 +318,9 @@ func ExploreCode(ctx *context.Context) {
}
var (
- total int
- searchResults []*code_indexer.Result
+ total int
+ searchResults []*code_indexer.Result
+ searchResultLanguages []*code_indexer.SearchResultLanguages
)
// if non-admin login user, we need check UnitTypeCode at first
@@ -340,14 +342,14 @@ func ExploreCode(ctx *context.Context) {
ctx.Data["RepoMaps"] = rightRepoMap
- total, searchResults, err = code_indexer.PerformSearch(repoIDs, keyword, page, setting.UI.RepoSearchPagingNum)
+ total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum)
if err != nil {
ctx.ServerError("SearchResults", err)
return
}
// if non-login user or isAdmin, no need to check UnitTypeCode
} else if (ctx.User == nil && len(repoIDs) > 0) || isAdmin {
- total, searchResults, err = code_indexer.PerformSearch(repoIDs, keyword, page, setting.UI.RepoSearchPagingNum)
+ total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum)
if err != nil {
ctx.ServerError("SearchResults", err)
return
@@ -377,12 +379,15 @@ func ExploreCode(ctx *context.Context) {
}
ctx.Data["Keyword"] = keyword
+ ctx.Data["Language"] = language
ctx.Data["SearchResults"] = searchResults
+ ctx.Data["SearchResultLanguages"] = searchResultLanguages
ctx.Data["RequireHighlightJS"] = true
ctx.Data["PageIsViewCode"] = true
pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
pager.SetDefaultParams(ctx)
+ pager.AddParam(ctx, "l", "Language")
ctx.Data["Page"] = pager
ctx.HTML(200, tplExploreCode)
diff --git a/routers/repo/search.go b/routers/repo/search.go
index 50a92c1e36..e110ae2a72 100644
--- a/routers/repo/search.go
+++ b/routers/repo/search.go
@@ -22,26 +22,30 @@ func Search(ctx *context.Context) {
ctx.Redirect(ctx.Repo.RepoLink, 302)
return
}
+ language := strings.TrimSpace(ctx.Query("l"))
keyword := strings.TrimSpace(ctx.Query("q"))
page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}
- total, searchResults, err := code_indexer.PerformSearch([]int64{ctx.Repo.Repository.ID},
- keyword, page, setting.UI.RepoSearchPagingNum)
+ total, searchResults, searchResultLanguages, err := code_indexer.PerformSearch([]int64{ctx.Repo.Repository.ID},
+ language, keyword, page, setting.UI.RepoSearchPagingNum)
if err != nil {
ctx.ServerError("SearchResults", err)
return
}
ctx.Data["Keyword"] = keyword
+ ctx.Data["Language"] = language
ctx.Data["SourcePath"] = setting.AppSubURL + "/" +
- path.Join(ctx.Repo.Repository.Owner.Name, ctx.Repo.Repository.Name, "src", "branch", ctx.Repo.Repository.DefaultBranch)
+ path.Join(ctx.Repo.Repository.Owner.Name, ctx.Repo.Repository.Name)
ctx.Data["SearchResults"] = searchResults
+ ctx.Data["SearchResultLanguages"] = searchResultLanguages
ctx.Data["RequireHighlightJS"] = true
ctx.Data["PageIsViewCode"] = true
pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
pager.SetDefaultParams(ctx)
+ pager.AddParam(ctx, "l", "Language")
ctx.Data["Page"] = pager
ctx.HTML(200, tplSearch)
diff --git a/templates/explore/code.tmpl b/templates/explore/code.tmpl
index 742ed59442..eb7da976b8 100644
--- a/templates/explore/code.tmpl
+++ b/templates/explore/code.tmpl
@@ -16,13 +16,22 @@
<h3>
{{.i18n.Tr "explore.code_search_results" (.Keyword|Escape) | Str2html }}
</h3>
+ <div>
+ {{range $term := .SearchResultLanguages}}
+ <a class="ui {{if eq $.Language $term.Language}}primary {{end}}basic label" href="{{$.AppSubURL}}/explore/code?q={{$.Keyword}}{{if ne $.Language $term.Language}}&l={{$term.Language}}{{end}}">
+ <i class="color-icon" style="background-color: {{$term.Color}}"></i>
+ {{$term.Language}}
+ <div class="detail">{{$term.Count}}</div>
+ </a>
+ {{end}}
+ </div>
<div class="repository search">
{{range $result := .SearchResults}}
{{$repo := (index $.RepoMaps .RepoID)}}
<div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result">
<h4 class="ui top attached normal header">
<span class="file"><a rel="nofollow" href="{{EscapePound $repo.HTMLURL}}">{{$repo.FullName}}</a> - {{.Filename}}</span>
- <a class="ui basic grey tiny button" rel="nofollow" href="{{EscapePound $repo.HTMLURL}}/src/branch/{{$repo.DefaultBranch}}/{{EscapePound .Filename}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
+ <a class="ui basic grey tiny button" rel="nofollow" href="{{EscapePound $repo.HTMLURL}}/src/commit/{{$result.CommitID}}/{{EscapePound .Filename}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
</h4>
<div class="ui attached table segment">
<div class="file-body file-code code-view">
@@ -31,7 +40,7 @@
<tr>
<td class="lines-num">
{{range .LineNumbers}}
- <a href="{{EscapePound $repo.HTMLURL}}/src/branch/{{$repo.DefaultBranch}}/{{EscapePound $result.Filename}}#L{{.}}"><span>{{.}}</span></a>
+ <a href="{{EscapePound $repo.HTMLURL}}/src/commit/{{$result.CommitID}}/{{EscapePound $result.Filename}}#L{{.}}"><span>{{.}}</span></a>
{{end}}
</td>
<td class="lines-code"><pre><code class="{{.HighlightClass}}"><ol class="linenums">{{.FormattedLines}}</ol></code></pre></td>
@@ -40,6 +49,15 @@
</table>
</div>
</div>
+ <div class="ui bottom attached table segment">
+ {{if $result.Language}}
+ <i class="color-icon" style="background-color: {{$result.Color}}"></i>{{$result.Language}}
+ {{end}}
+ &nbsp;
+ {{if not $result.UpdatedUnix.IsZero}}
+ <span class="ui small grey text pull right">{{$.i18n.Tr "explore.code_last_indexed_at" (TimeSinceUnix $result.UpdatedUnix $.i18n.Lang) | Safe}} &nbsp;</span>
+ {{end}}
+ </div>
</div>
{{end}}
</div>
diff --git a/templates/repo/search.tmpl b/templates/repo/search.tmpl
index c4413e7884..5aa2f8983e 100644
--- a/templates/repo/search.tmpl
+++ b/templates/repo/search.tmpl
@@ -16,12 +16,21 @@
<h3>
{{.i18n.Tr "repo.search.results" (.Keyword|Escape) .RepoLink .RepoName | Str2html }}
</h3>
+ <div>
+ {{range $term := .SearchResultLanguages}}
+ <a class="ui {{if eq $.Language $term.Language}}primary {{end}}basic label" href="{{EscapePound $.SourcePath}}/search?q={{$.Keyword}}{{if ne $.Language $term.Language}}&l={{$term.Language}}{{end}}">
+ <i class="color-icon" style="background-color: {{$term.Color}}"></i>
+ {{$term.Language}}
+ <div class="detail">{{$term.Count}}</div>
+ </a>
+ {{end}}
+ </div>
<div class="repository search">
{{range $result := .SearchResults}}
<div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result">
<h4 class="ui top attached normal header">
<span class="file">{{.Filename}}</span>
- <a class="ui basic grey tiny button" rel="nofollow" href="{{EscapePound $.SourcePath}}/{{EscapePound .Filename}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
+ <a class="ui basic grey tiny button" rel="nofollow" href="{{EscapePound $.SourcePath}}/src/commit/{{$result.CommitID}}/{{EscapePound .Filename}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
</h4>
<div class="ui attached table segment">
<div class="file-body file-code code-view">
@@ -30,7 +39,7 @@
<tr>
<td class="lines-num">
{{range .LineNumbers}}
- <a href="{{EscapePound $.SourcePath}}/{{EscapePound $result.Filename}}#L{{.}}"><span>{{.}}</span></a>
+ <a href="{{EscapePound $.SourcePath}}/src/commit/{{$result.CommitID}}/{{EscapePound $result.Filename}}#L{{.}}"><span>{{.}}</span></a>
{{end}}
</td>
<td class="lines-code"><pre><code class="{{.HighlightClass}}"><ol class="linenums">{{.FormattedLines}}</ol></code></pre></td>
@@ -39,6 +48,15 @@
</table>
</div>
</div>
+ <div class="ui bottom attached table segment">
+ {{if $result.Language}}
+ <i class="color-icon" style="background-color: {{$result.Color}}"></i>{{$result.Language}}
+ {{end}}
+ &nbsp;
+ {{if not $result.UpdatedUnix.IsZero}}
+ <span class="ui small grey text pull right">{{$.i18n.Tr "explore.code_last_indexed_at" (TimeSinceUnix $result.UpdatedUnix $.i18n.Lang) | Safe}} &nbsp;</span>
+ {{end}}
+ </div>
</div>
{{end}}
</div>
diff --git a/vendor/github.com/blevesearch/bleve/analysis/analyzer/keyword/keyword.go b/vendor/github.com/blevesearch/bleve/analysis/analyzer/keyword/keyword.go
new file mode 100644
index 0000000000..2a6c1aff71
--- /dev/null
+++ b/vendor/github.com/blevesearch/bleve/analysis/analyzer/keyword/keyword.go
@@ -0,0 +1,38 @@
+// Copyright (c) 2014 Couchbase, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package keyword
+
+import (
+ "github.com/blevesearch/bleve/analysis"
+ "github.com/blevesearch/bleve/analysis/tokenizer/single"
+ "github.com/blevesearch/bleve/registry"
+)
+
+const Name = "keyword"
+
+func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) {
+ keywordTokenizer, err := cache.TokenizerNamed(single.Name)
+ if err != nil {
+ return nil, err
+ }
+ rv := analysis.Analyzer{
+ Tokenizer: keywordTokenizer,
+ }
+ return &rv, nil
+}
+
+func init() {
+ registry.RegisterAnalyzer(Name, AnalyzerConstructor)
+}
diff --git a/vendor/github.com/blevesearch/bleve/analysis/tokenizer/single/single.go b/vendor/github.com/blevesearch/bleve/analysis/tokenizer/single/single.go
new file mode 100644
index 0000000000..18b2b1af9b
--- /dev/null
+++ b/vendor/github.com/blevesearch/bleve/analysis/tokenizer/single/single.go
@@ -0,0 +1,49 @@
+// Copyright (c) 2014 Couchbase, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package single
+
+import (
+ "github.com/blevesearch/bleve/analysis"
+ "github.com/blevesearch/bleve/registry"
+)
+
+const Name = "single"
+
+type SingleTokenTokenizer struct {
+}
+
+func NewSingleTokenTokenizer() *SingleTokenTokenizer {
+ return &SingleTokenTokenizer{}
+}
+
+func (t *SingleTokenTokenizer) Tokenize(input []byte) analysis.TokenStream {
+ return analysis.TokenStream{
+ &analysis.Token{
+ Term: input,
+ Position: 1,
+ Start: 0,
+ End: len(input),
+ Type: analysis.AlphaNumeric,
+ },
+ }
+}
+
+func SingleTokenTokenizerConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.Tokenizer, error) {
+ return NewSingleTokenTokenizer(), nil
+}
+
+func init() {
+ registry.RegisterTokenizer(Name, SingleTokenTokenizerConstructor)
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index a6fb0ad5e3..8db67e554b 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -54,6 +54,7 @@ github.com/beorn7/perks/quantile
github.com/blevesearch/bleve
github.com/blevesearch/bleve/analysis
github.com/blevesearch/bleve/analysis/analyzer/custom
+github.com/blevesearch/bleve/analysis/analyzer/keyword
github.com/blevesearch/bleve/analysis/analyzer/standard
github.com/blevesearch/bleve/analysis/datetime/flexible
github.com/blevesearch/bleve/analysis/datetime/optional
@@ -62,6 +63,7 @@ github.com/blevesearch/bleve/analysis/token/lowercase
github.com/blevesearch/bleve/analysis/token/porter
github.com/blevesearch/bleve/analysis/token/stop
github.com/blevesearch/bleve/analysis/token/unicodenorm
+github.com/blevesearch/bleve/analysis/tokenizer/single
github.com/blevesearch/bleve/analysis/tokenizer/unicode
github.com/blevesearch/bleve/document
github.com/blevesearch/bleve/geo
diff --git a/web_src/less/_base.less b/web_src/less/_base.less
index f6ea80e103..3e7e16c635 100644
--- a/web_src/less/_base.less
+++ b/web_src/less/_base.less
@@ -1193,6 +1193,10 @@ i.icon.centerlock {
border-radius: 500em;
}
+.ui.label > .color-icon {
+ margin-left: 0;
+}
+
.invisible {
visibility: hidden;
}
diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less
index 93fda6d764..7a22c9fc7d 100644
--- a/web_src/less/_repository.less
+++ b/web_src/less/_repository.less
@@ -1502,6 +1502,11 @@
clear: right;
}
+
+ .ui.bottom.attached.table.segment {
+ padding-top: 5px;
+ padding-bottom: 5px;
+ }
}
.diff-stats {