diff --git a/modules/indexer/code/search.go b/modules/indexer/code/search.go
index e19e22eea..2ddc2397f 100644
--- a/modules/indexer/code/search.go
+++ b/modules/indexer/code/search.go
@@ -16,14 +16,18 @@ import (
 
 // Result a search result to display
 type Result struct {
-	RepoID         int64
-	Filename       string
-	CommitID       string
-	UpdatedUnix    timeutil.TimeStamp
-	Language       string
-	Color          string
-	LineNumbers    []int
-	FormattedLines template.HTML
+	RepoID      int64
+	Filename    string
+	CommitID    string
+	UpdatedUnix timeutil.TimeStamp
+	Language    string
+	Color       string
+	Lines       []ResultLine
+}
+
+type ResultLine struct {
+	Num              int
+	FormattedContent template.HTML
 }
 
 type SearchResultLanguages = internal.SearchResultLanguages
@@ -70,7 +74,7 @@ func searchResult(result *internal.SearchResult, startIndex, endIndex int) (*Res
 	var formattedLinesBuffer bytes.Buffer
 
 	contentLines := strings.SplitAfter(result.Content[startIndex:endIndex], "\n")
-	lineNumbers := make([]int, len(contentLines))
+	lines := make([]ResultLine, 0, len(contentLines))
 	index := startIndex
 	for i, line := range contentLines {
 		var err error
@@ -93,21 +97,29 @@ func searchResult(result *internal.SearchResult, startIndex, endIndex int) (*Res
 			return nil, err
 		}
 
-		lineNumbers[i] = startLineNum + i
+		lines = append(lines, ResultLine{Num: startLineNum + i})
 		index += len(line)
 	}
 
-	highlighted, _ := highlight.Code(result.Filename, "", formattedLinesBuffer.String())
+	// we should highlight the whole code block first, otherwise it doesn't work well with multiple line highlighting
+	hl, _ := highlight.Code(result.Filename, "", formattedLinesBuffer.String())
+	highlightedLines := strings.Split(string(hl), "\n")
+
+	// The lines outputted by highlight.Code might not match the original lines, because "highlight" removes the last `\n`
+	lines = lines[:min(len(highlightedLines), len(lines))]
+	highlightedLines = highlightedLines[:len(lines)]
+	for i := 0; i < len(lines); i++ {
+		lines[i].FormattedContent = template.HTML(highlightedLines[i])
+	}
 
 	return &Result{
-		RepoID:         result.RepoID,
-		Filename:       result.Filename,
-		CommitID:       result.CommitID,
-		UpdatedUnix:    result.UpdatedUnix,
-		Language:       result.Language,
-		Color:          result.Color,
-		LineNumbers:    lineNumbers,
-		FormattedLines: highlighted,
+		RepoID:      result.RepoID,
+		Filename:    result.Filename,
+		CommitID:    result.CommitID,
+		UpdatedUnix: result.UpdatedUnix,
+		Language:    result.Language,
+		Color:       result.Color,
+		Lines:       lines,
 	}, nil
 }
 
diff --git a/services/repository/files/search.go b/services/repository/files/search.go
index f8317c489..09c3ab5bf 100644
--- a/services/repository/files/search.go
+++ b/services/repository/files/search.go
@@ -16,14 +16,18 @@ import (
 )
 
 type Result struct {
-	RepoID         int64 // ignored
-	Filename       string
-	CommitID       string             // branch
-	UpdatedUnix    timeutil.TimeStamp // ignored
-	Language       string
-	Color          string
-	LineNumbers    []int64
-	FormattedLines template.HTML
+	RepoID      int64 // ignored
+	Filename    string
+	CommitID    string             // branch
+	UpdatedUnix timeutil.TimeStamp // ignored
+	Language    string
+	Color       string
+	Lines       []ResultLine
+}
+
+type ResultLine struct {
+	Num              int64
+	FormattedContent template.HTML
 }
 
 const pHEAD = "HEAD:"
@@ -46,7 +50,8 @@ func NewRepoGrep(ctx context.Context, repo *repo_model.Repository, keyword strin
 		"-n",              // line nums
 		"-i",              // ignore case
 		"--full-name",     // full file path, rel to repo
-		//"--column",        // for adding better highlighting support
+		//"--column",      // for adding better highlighting support
+		"-e", // for queries starting with "-"
 	).
 		AddDynamicArguments(keyword).
 		AddArguments("HEAD").
@@ -57,6 +62,8 @@ func NewRepoGrep(ctx context.Context, repo *repo_model.Repository, keyword strin
 
 	for _, block := range strings.Split(stdout, "\n\n") {
 		res := Result{CommitID: repo.DefaultBranch}
+
+		linenum := []int64{}
 		code := []string{}
 
 		for _, line := range strings.Split(block, "\n") {
@@ -71,18 +78,32 @@ func NewRepoGrep(ctx context.Context, repo *repo_model.Repository, keyword strin
 					continue
 				}
 
-				res.LineNumbers = append(res.LineNumbers, i)
+				linenum = append(linenum, i)
 				code = append(code, after)
 			}
 		}
 
-		if res.Filename == "" || len(code) == 0 || len(res.LineNumbers) == 0 {
+		if res.Filename == "" || len(code) == 0 || len(linenum) == 0 {
 			continue
 		}
 
-		res.FormattedLines, res.Language = highlight.Code(res.Filename, "", strings.Join(code, "\n"))
+		var hl template.HTML
+
+		hl, res.Language = highlight.Code(res.Filename, "", strings.Join(code, "\n"))
 		res.Color = enry.GetColor(res.Language)
 
+		hlCode := strings.Split(string(hl), "\n")
+		n := min(len(hlCode), len(linenum))
+
+		res.Lines = make([]ResultLine, n)
+
+		for i := 0; i < n; i++ {
+			res.Lines[i] = ResultLine{
+				Num:              linenum[i],
+				FormattedContent: template.HTML(hlCode[i]),
+			}
+		}
+
 		data = append(data, &res)
 	}
 
diff --git a/services/repository/files/search_test.go b/services/repository/files/search_test.go
index 959ddaa9f..2f2f87368 100644
--- a/services/repository/files/search_test.go
+++ b/services/repository/files/search_test.go
@@ -25,14 +25,16 @@ func TestNewRepoGrep(t *testing.T) {
 
 		expected := []*Result{
 			{
-				RepoID:         0,
-				Filename:       "README.md",
-				CommitID:       "master",
-				UpdatedUnix:    0,
-				Language:       "Markdown",
-				Color:          "#083fa1",
-				LineNumbers:    []int64{2, 3},
-				FormattedLines: "\nDescription for repo1",
+				RepoID:      0,
+				Filename:    "README.md",
+				CommitID:    "master",
+				UpdatedUnix: 0,
+				Language:    "Markdown",
+				Color:       "#083fa1",
+				Lines: []ResultLine{
+					{Num: 2, FormattedContent: ""},
+					{Num: 3, FormattedContent: "Description for repo1"},
+				},
 			},
 		}
 
diff --git a/templates/code/searchresults.tmpl b/templates/code/searchresults.tmpl
index bb21a5e0d..dca7dea7d 100644
--- a/templates/code/searchresults.tmpl
+++ b/templates/code/searchresults.tmpl
@@ -22,20 +22,7 @@
 				<a role="button" class="ui basic tiny button" rel="nofollow" href="{{$repo.Link}}/src/commit/{{$result.CommitID | PathEscape}}/{{.Filename | PathEscapeSegments}}">{{ctx.Locale.Tr "repo.diff.view_file"}}</a>
 			</h4>
 			<div class="ui attached table segment">
-				<div class="file-body file-code code-view">
-					<table>
-						<tbody>
-							<tr>
-								<td class="lines-num">
-									{{range .LineNumbers}}
-										<a href="{{$repo.Link}}/src/commit/{{$result.CommitID | PathEscape}}/{{$result.Filename | PathEscapeSegments}}#L{{.}}"><span>{{.}}</span></a>
-									{{end}}
-								</td>
-								<td class="lines-code chroma"><code class="code-inner">{{.FormattedLines}}</code></td>
-							</tr>
-						</tbody>
-					</table>
-				</div>
+				{{template "shared/searchfile" dict "RepoLink" $repo.Link "IsIndexer" true "SearchResult" .}}
 			</div>
 			{{template "shared/searchbottom" dict "root" $ "result" .}}
 		</div>
diff --git a/templates/repo/search.tmpl b/templates/repo/search.tmpl
index d0d376f1c..8eaecab68 100644
--- a/templates/repo/search.tmpl
+++ b/templates/repo/search.tmpl
@@ -46,20 +46,7 @@
 								<a role="button" class="ui basic tiny button" rel="nofollow" href="{{$.SourcePath}}/src/{{if $.CodeIndexerEnabled}}commit{{else}}branch{{end}}/{{PathEscape $result.CommitID}}/{{PathEscapeSegments .Filename}}">{{ctx.Locale.Tr "repo.diff.view_file"}}</a>
 							</h4>
 							<div class="ui attached table segment">
-								<div class="file-body file-code code-view">
-									<table>
-										<tbody>
-											<tr>
-												<td class="lines-num">
-													{{range .LineNumbers}}
-														<a href="{{$.SourcePath}}/src/{{if $.CodeIndexerEnabled}}commit{{else}}branch{{end}}/{{PathEscape $result.CommitID}}/{{PathEscapeSegments $result.Filename}}#L{{.}}"><span>{{.}}</span></a>
-													{{end}}
-												</td>
-												<td class="lines-code chroma"><code class="code-inner">{{.FormattedLines}}</code></td>
-											</tr>
-										</tbody>
-									</table>
-								</div>
+								{{template "shared/searchfile" dict "RepoLink" $.SourcePath "IsIndexer" $.CodeIndexerEnabled "SearchResult" .}}
 							</div>
 							{{template "shared/searchbottom" dict "root" $ "result" .}}
 						</div>
diff --git a/templates/shared/searchfile.tmpl b/templates/shared/searchfile.tmpl
new file mode 100644
index 000000000..6ffcd7118
--- /dev/null
+++ b/templates/shared/searchfile.tmpl
@@ -0,0 +1,14 @@
+<div class="file-body file-code code-view">
+	<table>
+		<tbody>
+			{{range .SearchResult.Lines}}
+				<tr>
+					<td class="lines-num">
+						<a href="{{$.RepoLink}}/src/{{if not $.IsIndexer}}branch{{else}}commit{{end}}/{{PathEscape $.SearchResult.CommitID}}/{{PathEscapeSegments $.SearchResult.Filename}}#L{{.Num}}"><span>{{.Num}}</span></a>
+					</td>
+					<td class="lines-code chroma"><code class="code-inner">{{.FormattedContent}}</code></td>
+				</tr>
+			{{end}}
+		</tbody>
+	</table>
+</div>