Skip to content
This repository was archived by the owner on Dec 11, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions core/src/main/scala/codesearch/core/search/Search.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import cats.syntax.option._
import codesearch.core.config.{Config, SnippetConfig}
import codesearch.core.index.directory.СindexDirectory
import codesearch.core.index.repository.Extensions
import codesearch.core.regex.RegexConstructor
import codesearch.core.search.Search.{CSearchPage, CSearchResult, CodeSnippet, Package, PackageResult, snippetConfig}
import codesearch.core.search.SnippetsGrouper.SnippetInfo
import codesearch.core.syntax.stream._
import codesearch.core.util.Helper.readFileAsync
import fs2.{Pipe, Stream}
import io.chrisdavenport.log4cats.SelfAwareStructuredLogger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import codesearch.core.regex.RegexConstructor
import codesearch.core.syntax.stream._

import scala.sys.process.Process

Expand All @@ -34,16 +34,14 @@ trait Search {
def search(request: SearchRequest): IO[CSearchPage] = {
for {
lines <- csearch(request)

snippetsInfo = Stream
.emits(lines)
.through(SnippetsGrouper.groupLines(snippetConfig))
.through(SnippetsGrouper.groupLines(snippetConfig, request.query))

filteredSnippetsInfo = if (request.withoutTests)
filteredSnippetsInfo: Stream[fs2.Pure, SnippetsGrouper.SnippetInfo] = if (request.withoutTests)
snippetsInfo.filterNot(snippetInfo => isTestInPath(snippetInfo.filePath))
else
snippetsInfo

results <- filteredSnippetsInfo
.drop(snippetConfig.pageSize * (request.page - 1))
.take(snippetConfig.pageSize)
Expand All @@ -52,7 +50,8 @@ trait Search {
.compile
.toList
totalMatches = filteredSnippetsInfo.fold(0)((total, snippet) => total + snippet.totalMatches).compile.toList.last
} yield CSearchPage(results.sortBy(_.pack.name), totalMatches)
snippetCount = filteredSnippetsInfo.fold(0)((total, _) => total + 1).compile.toList.last
} yield CSearchPage(results.sortBy(_.pack.name), totalMatches, snippetCount)
}

/**
Expand Down Expand Up @@ -167,7 +166,8 @@ object Search {
*/
final case class CSearchPage(
data: Seq[PackageResult],
total: Int
total: Int,
snippetCount: Int
)

/**
Expand Down
25 changes: 16 additions & 9 deletions core/src/main/scala/codesearch/core/search/SnippetsGrouper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,46 @@ object SnippetsGrouper {
*/
case class SnippetInfo(filePath: String, lines: NonEmptyVector[Int], totalMatches: Int)

private case class ResultRow(path: String, lineNumber: Int)
private case class ResultRow(path: String, lineNumber: Int, matchedString: Array[String])

/**
* Transforms raw search output in format `filePath:lineNumber:matchedString` to snippets grouping matched lines
* from the same file if they are close to each other
*
* @param config config for creating a snippet
*/
def groupLines[F[_]](config: SnippetConfig): Pipe[F, String, SnippetInfo] = { lines =>
def groupLines[F[_]](config: SnippetConfig, query: String): Pipe[F, String, SnippetInfo] = { lines =>
for {
(_, resultRows) <- lines.map { row =>
val Array(path, lineNumber) = row.split(":").take(2) //filePath:lineNumber:matchedString
ResultRow(path, lineNumber.toInt)
val result = row.split(":") // filePath:lineNumber:matchedString
ResultRow(result(0), result(1).toInt, result.drop(2))
}.groupAdjacentBy(_.path)
snippet <- Stream.emits {
groupRowsToSnippets(config)(resultRows)
groupRowsToSnippets(config, query)(resultRows)
}
} yield snippet
}

private def groupRowsToSnippets(config: SnippetConfig)(rows: Chunk[ResultRow]): Seq[SnippetInfo] = {
private def groupRowsToSnippets(config: SnippetConfig, query: String)(rows: Chunk[ResultRow]): Seq[SnippetInfo] = {
rows.foldLeft(Vector.empty[SnippetInfo]) { (snippets, row) =>
val count = math.max(countSubstring(row.matchedString, query), 1)
snippets.lastOption match {
case Some(snippet) =>
if (row.lineNumber < snippet.lines.last + config.linesAfter) {
snippets.init :+ snippet.copy(lines = snippet.lines :+ row.lineNumber,
totalMatches = snippet.totalMatches + 1)
totalMatches = snippet.totalMatches + count)
} else {
snippets :+ SnippetInfo(row.path, NonEmptyVector.one(row.lineNumber), 1)
snippets :+ SnippetInfo(row.path, NonEmptyVector.one(row.lineNumber), count)
}
case None =>
snippets :+ SnippetInfo(row.path, NonEmptyVector.one(row.lineNumber), 1)
snippets :+ SnippetInfo(row.path, NonEmptyVector.one(row.lineNumber), count)
}
}
}

private def countSubstring(str: Array[String], sub: String): Int = {
str.foldLeft(0) { (count, str) =>
count + str.sliding(sub.length).count(_ == sub)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class SnippetsGrouperSpec extends WordSpec with Matchers {
val snippets: List[SnippetInfo] = fs2.Stream
.emits(matchedLines)
.through(
SnippetsGrouper.groupLines(SnippetConfig(pageSize = 30, linesBefore = 5, linesAfter = 5))
SnippetsGrouper.groupLines(SnippetConfig(pageSize = 30, linesBefore = 5, linesAfter = 5), "import")
)
.compile
.toList
Expand All @@ -44,7 +44,7 @@ class SnippetsGrouperSpec extends WordSpec with Matchers {
val snippets: List[SnippetInfo] = fs2.Stream
.emits(matchedLines)
.through(
SnippetsGrouper.groupLines(SnippetConfig(pageSize = 30, linesBefore = 5, linesAfter = 5))
SnippetsGrouper.groupLines(SnippetConfig(pageSize = 30, linesBefore = 5, linesAfter = 5), "deriving")
)
.compile
.toList
Expand Down Expand Up @@ -73,7 +73,7 @@ class SnippetsGrouperSpec extends WordSpec with Matchers {
val snippets: List[SnippetInfo] = fs2.Stream
.emits(matchedLines)
.through(
SnippetsGrouper.groupLines(SnippetConfig(pageSize = 30, linesBefore = 5, linesAfter = 5))
SnippetsGrouper.groupLines(SnippetConfig(pageSize = 30, linesBefore = 5, linesAfter = 5), "import")
)
.compile
.toList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ trait SearchController[V <: DefaultTable] { self: InjectedController =>
)
db.updated.flatMap { updated =>
searchEngine.search(searchRequest) map {
case CSearchPage(results, total) =>
case CSearchPage(results, total, snippetcount) =>
Ok(
views.html.searchResults(
updated = TimeAgo.using(updated.getTime),
Expand All @@ -81,7 +81,8 @@ trait SearchController[V <: DefaultTable] { self: InjectedController =>
page = searchRequest.page,
totalMatches = total,
callURI = searchRequest.callURI(host).toString,
lang = lang
lang = lang,
snippetCount = snippetcount
)
)
} unsafeToFuture
Expand Down
8 changes: 4 additions & 4 deletions web-server/app/views/pagination.scala.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@import codesearch.core.search.Search.snippetConfig

@(page: Int = 0, totalMatches: Int, callURI: String = "#")
@(page: Int = 0, totalMatches: Int, callURI: String = "#", snippetCount: Int = 0)

@if(page != 0) {

Expand All @@ -14,16 +14,16 @@
</a>
</li>
@for(curPage <- 1 to 10) {
@{if ((curPage - 1) * snippetConfig.pageSize + 1 <= math.min(1000, totalMatches)) {
@{if ((curPage - 1) * snippetConfig.pageSize + 1 <= math.min(1000, snippetCount)) {
<li class={if (page == curPage) "page-item active" else "page-item"}>
<a class="page-link" href={callURI ++ s"&page=$curPage"}>
<span aria-hidden="true">{curPage}</span>
</a>
</li>
} }
}
<li class="@{if (page * snippetConfig.pageSize + 1 <= math.min(1000, totalMatches)) "page-item" else "page-item disabled"}">
<a class="page-link" href=@{if (page * snippetConfig.pageSize + 1 <= math.min(1000, totalMatches)) callURI ++ s"&page=${math.min(page + 1, 10)}" else "#"} aria-label="Next">
<li class="@{if (page * snippetConfig.pageSize + 1 <= math.min(1000, snippetCount)) "page-item" else "page-item disabled"}">
<a class="page-link" href=@{if (page * snippetConfig.pageSize + 1 <= math.min(1000, snippetCount)) callURI ++ s"&page=${math.min(page + 1, 10)}" else "#"} aria-label="Next">
<span aria-hidden="true">&raquo;</span>
<span class="sr-only">Next</span>
</a>
Expand Down
5 changes: 3 additions & 2 deletions web-server/app/views/searchResults.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
page: Int,
totalMatches: Int,
callURI: String,
lang: String
lang: String,
snippetCount: Int
)

@headExtra = {
Expand All @@ -26,5 +27,5 @@
@wrapper(s"Codesearch | $lang", headExtra) {
@searchBox(s"/$lang/search", query, filter, filePath, insensitive, space, precise, sources, withoutTests)
@resultFrame(lang, insensitive, space, precise, query, updated, packages, totalMatches)
@pagination(page, totalMatches, callURI)
@pagination(page, totalMatches, callURI, snippetCount: Int)
}