97 lines
2.9 KiB
Kotlin
97 lines
2.9 KiB
Kotlin
package be.simplenotes.domain.usecases.search
|
|
|
|
import be.simplenotes.search.SearchTerms
|
|
import java.util.*
|
|
|
|
private enum class Quote { SingleQuote, DoubleQuote, }
|
|
|
|
data class ParsedSearchInput(val global: List<String>, val entries: Map<String, String>)
|
|
|
|
object SearchInputParser {
|
|
fun parseInput(input: String): ParsedSearchInput {
|
|
val tokenizer = StringTokenizer(input, ":\"' ", true)
|
|
|
|
val tokens = ArrayList<String>()
|
|
val current = StringBuilder()
|
|
var quoteOpen: Quote? = null
|
|
|
|
fun push() {
|
|
if (current.isNotEmpty()) {
|
|
tokens.add(current.toString())
|
|
}
|
|
current.setLength(0)
|
|
quoteOpen = null
|
|
}
|
|
|
|
while (tokenizer.hasMoreTokens()) {
|
|
when (val token = tokenizer.nextToken()) {
|
|
"\"" -> when {
|
|
Quote.DoubleQuote == quoteOpen -> push()
|
|
quoteOpen == null -> quoteOpen = Quote.DoubleQuote
|
|
else -> current.append(token)
|
|
}
|
|
"'" -> when {
|
|
Quote.SingleQuote == quoteOpen -> push()
|
|
quoteOpen == null -> quoteOpen = Quote.SingleQuote
|
|
else -> current.append(token)
|
|
}
|
|
" " -> {
|
|
if (quoteOpen != null) current.append(" ")
|
|
else push()
|
|
}
|
|
":" -> {
|
|
push()
|
|
tokens.add(token)
|
|
}
|
|
else -> {
|
|
current.append(token)
|
|
}
|
|
}
|
|
}
|
|
|
|
push()
|
|
|
|
val entries = HashMap<String, String>()
|
|
|
|
val colonIndexes = ArrayList<Int>()
|
|
tokens.forEachIndexed { index, token ->
|
|
if (token == ":") colonIndexes += index
|
|
}
|
|
|
|
var changes = 0
|
|
for (colonIndex in colonIndexes) {
|
|
val offset = changes * 3
|
|
|
|
val key = tokens.getOrNull(colonIndex - 1 - offset)
|
|
val value = tokens.getOrNull(colonIndex + 1 - offset)
|
|
|
|
if (key != null && value != null) {
|
|
entries[key] = value
|
|
tokens.removeAt(colonIndex - 1 - offset) // remove key
|
|
tokens.removeAt(colonIndex - 1 - offset) // remove :
|
|
tokens.removeAt(colonIndex - 1 - offset) // remove value
|
|
changes++
|
|
}
|
|
}
|
|
|
|
return ParsedSearchInput(global = tokens, entries = entries)
|
|
}
|
|
}
|
|
|
|
internal fun parseSearchTerms(input: String): SearchTerms {
|
|
val parsedInput = SearchInputParser.parseInput(input)
|
|
|
|
val title: String? = parsedInput.entries["title"]
|
|
val tag: String? = parsedInput.entries["tag"]
|
|
val content: String? = parsedInput.entries["content"]
|
|
|
|
val all = parsedInput.global.takeIf { it.isNotEmpty() }?.joinToString(" ")
|
|
|
|
return SearchTerms(
|
|
title = title,
|
|
tag = tag,
|
|
content = content,
|
|
all = all
|
|
)
|
|
}
|