Better quote handling, parsing state refactor

Should be easier to test in the future
Still needs some work on spacing
This commit is contained in:
Bradlee Speice 2015-04-16 00:37:11 -04:00
parent aec86f9898
commit 3a0a5baa1c
8 changed files with 72 additions and 49 deletions

View File

@ -24,7 +24,7 @@ public class MinimalBible extends Application implements Injector {
} }
public static Context getAppContext() { public static Context getAppContext() {
Logger.w("Statically accessing context, please refactor that."); Logger.v("Statically accessing context, please refactor that.");
return mContext; return mContext;
} }

View File

@ -3,7 +3,6 @@ package org.bspeice.minimalbible.activity.viewer
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.widget.TextView import android.widget.TextView
import com.orhanobut.logger.Logger
import org.bspeice.minimalbible.service.format.osisparser.OsisParser import org.bspeice.minimalbible.service.format.osisparser.OsisParser
import org.crosswire.jsword.book.Book import org.crosswire.jsword.book.Book
import org.crosswire.jsword.book.getVersification import org.crosswire.jsword.book.getVersification
@ -11,18 +10,18 @@ import org.crosswire.jsword.book.getVersification
class PassageView(val v: TextView, val b: Book) class PassageView(val v: TextView, val b: Book)
: RecyclerView.ViewHolder(v) { : RecyclerView.ViewHolder(v) {
val parser = OsisParser()
fun buildOrdinal(verse: Int, info: BookAdapter.ChapterInfo) = fun buildOrdinal(verse: Int, info: BookAdapter.ChapterInfo) =
b.getVersification().decodeOrdinal(verse + info.vOffset) b.getVersification().decodeOrdinal(verse + info.vOffset)
fun getAllVerses(verses: Progression<Int>, info: BookAdapter.ChapterInfo): SpannableStringBuilder { fun getAllVerses(verses: Progression<Int>, info: BookAdapter.ChapterInfo): SpannableStringBuilder {
val builder = SpannableStringBuilder() val builder = SpannableStringBuilder()
val parser = OsisParser()
verses.forEach { parser.appendVerse(b, buildOrdinal(it, info), builder) } verses.forEach { parser.appendVerse(b, buildOrdinal(it, info), builder) }
return builder return builder
} }
fun bind(info: BookAdapter.ChapterInfo) { fun bind(info: BookAdapter.ChapterInfo) {
Logger.d("PassageView", "Binding chapter ${info.chapter}")
v setText getAllVerses(info.vStart..info.vEnd, info) v setText getAllVerses(info.vStart..info.vEnd, info)
} }
} }

View File

@ -25,8 +25,11 @@ class OsisParser() : DefaultHandler() {
// Don't pass a verse as part of the constructor, but still guarantee // Don't pass a verse as part of the constructor, but still guarantee
// that it will exist // that it will exist
var verseContent: VerseContent by Delegates.notNull() var verseContent: VerseContent by Delegates.notNull()
var builder: SpannableStringBuilder by Delegates.notNull() var builder: SpannableStringBuilder by Delegates.notNull()
var state: ParseState = ParseState(listOf())
// TODO: Implement a stack to keep min API 8 // TODO: Implement a stack to keep min API 8
val handlerStack = ArrayDeque<TagHandler>() val handlerStack = ArrayDeque<TagHandler>()
@ -52,23 +55,25 @@ class OsisParser() : DefaultHandler() {
override fun startElement(uri: String, localName: String, override fun startElement(uri: String, localName: String,
qName: String, attributes: Attributes) { qName: String, attributes: Attributes) {
when (localName) { val tag = when (localName) {
OSISUtil.OSIS_ELEMENT_VERSE -> handlerStack push VerseHandler() OSISUtil.OSIS_ELEMENT_VERSE -> VerseHandler()
"divineName" -> handlerStack push DivineHandler() "divineName" -> DivineHandler()
"q" -> handlerStack push QHandler(MinimalBible.getAppContext() "q" -> QHandler(MinimalBible.getAppContext()
.getResources().getColor(R.color.divineSpeech)) .getResources().getColor(R.color.divineSpeech))
else -> handlerStack push UnknownHandler(localName) else -> UnknownHandler(localName)
} }
handlerStack.peek().start(attributes, verseContent, builder) state = tag.start(attributes, verseContent, builder, state)
handlerStack push tag
} }
override fun endElement(uri: String, localName: String, qName: String) { override fun endElement(uri: String, localName: String, qName: String) {
val tagHandler = handlerStack.pop() val tagHandler = handlerStack.pop()
tagHandler.end(verseContent, builder) state = tagHandler.end(verseContent, builder, state) build builder
} }
override fun characters(ch: CharArray, start: Int, length: Int) { override fun characters(ch: CharArray, start: Int, length: Int) {
handlerStack.peek().render(builder, verseContent, String(ch)) val tag = handlerStack.peek()
state = tag.render(builder, verseContent, String(ch), state)
} }
} }

View File

@ -6,19 +6,18 @@ import org.bspeice.minimalbible.service.format.osisparser.VerseContent
import org.xml.sax.Attributes import org.xml.sax.Attributes
class DivineHandler() : TagHandler { class DivineHandler() : TagHandler {
override fun end(info: VerseContent, builder: SpannableStringBuilder) { override fun end(info: VerseContent, builder: SpannableStringBuilder,
} state: ParseState) = state
override fun start(attrs: Attributes, info: VerseContent, override fun start(attrs: Attributes, info: VerseContent, builder: SpannableStringBuilder,
builder: SpannableStringBuilder) { state: ParseState) = state
}
override fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String) { override fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String,
this buildDivineName chars forEach { it apply builder } state: ParseState) =
} state append(buildDivineName(chars))
fun buildDivineName(chars: String) = fun buildDivineName(chars: String) =
listOf(AppendArgs(chars take 1, null), listOf(AppendArgs(chars take 1),
AppendArgs((chars drop 1).toUpperCase(), RelativeSizeSpan(.8f)) AppendArgs((chars drop 1).toUpperCase(), RelativeSizeSpan(.8f))
) )
} }

View File

@ -7,14 +7,16 @@ import org.xml.sax.Attributes
class QHandler(val color: Int) : TagHandler { class QHandler(val color: Int) : TagHandler {
override fun start(attrs: Attributes, info: VerseContent, builder: SpannableStringBuilder) { fun retrieveMarker(attrs: Attributes) =
} AppendArgs(attrs getValue "marker" ?: "")
override fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String) { override fun start(attrs: Attributes, info: VerseContent, builder: SpannableStringBuilder,
AppendArgs(chars, ForegroundColorSpan(color)) apply builder state: ParseState) = state append retrieveMarker(attrs)
}
override fun end(info: VerseContent, builder: SpannableStringBuilder) { override fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String,
AppendArgs(" ", null) apply builder state: ParseState) =
} state append AppendArgs(chars.trim() + " ", ForegroundColorSpan(color))
override fun end(info: VerseContent, builder: SpannableStringBuilder,
state: ParseState) = state
} }

View File

@ -6,12 +6,29 @@ import org.bspeice.minimalbible.service.format.osisparser.VerseContent
import org.xml.sax.Attributes import org.xml.sax.Attributes
trait TagHandler { trait TagHandler {
fun start(attrs: Attributes, info: VerseContent, builder: SpannableStringBuilder) fun start(attrs: Attributes, info: VerseContent, builder: SpannableStringBuilder,
fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String) state: ParseState): ParseState
fun end(info: VerseContent, builder: SpannableStringBuilder)
fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String,
state: ParseState): ParseState
fun end(info: VerseContent, builder: SpannableStringBuilder,
state: ParseState): ParseState
} }
data class AppendArgs(val text: String, val span: Any?) { class ParseState(val spans: List<AppendArgs>) {
fun build(builder: SpannableStringBuilder): ParseState {
spans.forEach { it apply builder }
return ParseState(listOf())
}
fun append(arg: AppendArgs) = ParseState(spans + arg)
fun append(args: List<AppendArgs>) = ParseState(spans + args)
}
data class AppendArgs(val text: String, val span: Any? = null) {
fun apply(builder: SpannableStringBuilder) { fun apply(builder: SpannableStringBuilder) {
val offset = builder.length() val offset = builder.length()
builder.append(text) builder.append(text)

View File

@ -6,14 +6,15 @@ import org.bspeice.minimalbible.service.format.osisparser.VerseContent
import org.xml.sax.Attributes import org.xml.sax.Attributes
class UnknownHandler(val tagName: String) : TagHandler { class UnknownHandler(val tagName: String) : TagHandler {
override fun end(info: VerseContent, builder: SpannableStringBuilder) { override fun end(info: VerseContent, builder: SpannableStringBuilder,
} state: ParseState): ParseState = state
override fun start(attrs: Attributes, info: VerseContent, override fun start(attrs: Attributes, info: VerseContent, builder: SpannableStringBuilder,
builder: SpannableStringBuilder) { state: ParseState) = state
}
override fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String) { override fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String,
Logger.w("Unknown tag '$tagName' received text: '$chars'") state: ParseState): ParseState {
Logger.v("Unknown tag '$tagName' received text: '$chars'")
return state
} }
} }

View File

@ -10,19 +10,19 @@ import org.xml.sax.Attributes
class VerseHandler() : TagHandler { class VerseHandler() : TagHandler {
override fun end(info: VerseContent, builder: SpannableStringBuilder) { override fun end(info: VerseContent, builder: SpannableStringBuilder,
} state: ParseState) =
state append AppendArgs(" ")
override fun start(attrs: Attributes, info: VerseContent, override fun start(attrs: Attributes, info: VerseContent,
builder: SpannableStringBuilder) { builder: SpannableStringBuilder, state: ParseState) =
when { state append when {
info.verseNum == 1 -> AppendArgs("${info.chapter} ", StyleSpan(Typeface.BOLD)) info.verseNum == 1 -> AppendArgs("${info.chapter} ", StyleSpan(Typeface.BOLD))
else -> AppendArgs("${info.verseNum}", else -> AppendArgs("${info.verseNum}",
listOf(SuperscriptSpan(), RelativeSizeSpan(.75f))) listOf(SuperscriptSpan(), RelativeSizeSpan(.75f)))
} apply builder }
}
override fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String) { override fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String,
builder append chars state: ParseState) =
} state append AppendArgs(chars)
} }