| @@ -5,66 +5,59 @@ from re import sub, UNICODE | |||||
| from markupsafe import escape | from markupsafe import escape | ||||
| def highlight_delta(context, chain, delta): | def highlight_delta(context, chain, delta): | ||||
| degree = chain.degree - 1 | |||||
| highlights = [False] * degree | |||||
| block = [chain.START] * degree | |||||
| for word in chain.text.split() + ([chain.END] * degree): | |||||
| word = _strip_word(chain, word) | |||||
| tblock = tuple(block) | |||||
| if tblock in delta.chain and word in delta.chain[tblock]: | |||||
| highlights[-1 * degree:] = [True] * degree | |||||
| highlights.append(True) | |||||
| else: | |||||
| highlights.append(False) | |||||
| block.pop(0) | |||||
| block.append(word) | |||||
| i = degree | |||||
| numwords = len(chain.text.split()) | |||||
| processed = [] | processed = [] | ||||
| dchain = delta.chain | |||||
| prev_prev = prev = chain.START | |||||
| i = 0 | |||||
| all_words = chain.text.split() | |||||
| paragraphs = chain.text.split("\n") | |||||
| for paragraph in paragraphs: | |||||
| processed_words = [] | |||||
| words = paragraph.split(" ") | |||||
| for i, word in enumerate(words, i): | |||||
| try: | |||||
| next = _strip_word(all_words[i + 1]) | |||||
| try: | |||||
| next_next = _strip_word(all_words[i + 2]) | |||||
| except IndexError: | |||||
| next_next = chain.END | |||||
| except IndexError: | |||||
| next = next_next = chain.END | |||||
| sword = _strip_word(word) | |||||
| middle = (prev, sword) in dchain and next in dchain[(prev, sword)] | |||||
| if middle: | |||||
| before = after = True | |||||
| else: | |||||
| b_block = (prev_prev, prev) | |||||
| a_block = (sword, next) | |||||
| before = b_block in dchain and sword in dchain[b_block] | |||||
| after = a_block in dchain and next_next in dchain[a_block] | |||||
| is_first = i == 0 | |||||
| is_last = i + 1 == len(all_words) | |||||
| res = _highlight_word(word, before, after, is_first, is_last) | |||||
| processed_words.append(res) | |||||
| prev_prev = prev | |||||
| prev = sword | |||||
| processed.append(u" ".join(processed_words)) | |||||
| for paragraph in chain.text.split("\n"): | |||||
| words = [] | |||||
| for i, word in enumerate(paragraph.split(), i): | |||||
| before = highlights[i - 1] | |||||
| after = highlights[i + 1] | |||||
| first = i == degree | |||||
| last = i - degree + 1 == numwords | |||||
| words.append(_highlight_word(word, before, after, first, last)) | |||||
| processed.append(u" ".join(words)) | |||||
| i += 1 | i += 1 | ||||
| return u"<p>" + u"</p>\n<p>".join(processed) + u"</p>" | return u"<p>" + u"</p>\n<p>".join(processed) + u"</p>" | ||||
| def _highlight_word(word, before, after, is_first, is_last): | |||||
| def _highlight_word(word, before, after, first, last): | |||||
| if before and after: | if before and after: | ||||
| # Word is in the middle of a highlighted block, so don't change | # Word is in the middle of a highlighted block, so don't change | ||||
| # anything unless this is the first word (force block to start) or the | # anything unless this is the first word (force block to start) or the | ||||
| # last word (force block to end): | # last word (force block to end): | ||||
| res = unicode(escape(word)) | res = unicode(escape(word)) | ||||
| if is_first: | |||||
| if first: | |||||
| res = u'<span class="cv-hl">' + res | res = u'<span class="cv-hl">' + res | ||||
| if is_last: | |||||
| if last: | |||||
| res += u'</span>' | res += u'</span>' | ||||
| elif before: | elif before: | ||||
| # Word is the last in a highlighted block, so fade it out and then end | # Word is the last in a highlighted block, so fade it out and then end | ||||
| # the block; force open a block before the word if this is the first | # the block; force open a block before the word if this is the first | ||||
| # word: | # word: | ||||
| res = _fade_word(word, u"out") + u"</span>" | res = _fade_word(word, u"out") + u"</span>" | ||||
| if is_first: | |||||
| if first: | |||||
| res = u'<span class="cv-hl">' + res | res = u'<span class="cv-hl">' + res | ||||
| elif after: | elif after: | ||||
| # Word is the first in a highlighted block, so start the block and then | # Word is the first in a highlighted block, so start the block and then | ||||
| # fade it in; force close the block after the word if this is the last | # fade it in; force close the block after the word if this is the last | ||||
| # word: | # word: | ||||
| res = u'<span class="cv-hl">' + _fade_word(word, u"in") | res = u'<span class="cv-hl">' + _fade_word(word, u"in") | ||||
| if is_last: | |||||
| if last: | |||||
| res += u"</span>" | res += u"</span>" | ||||
| else: | else: | ||||
| # Word is completely outside of a highlighted block, so do nothing: | # Word is completely outside of a highlighted block, so do nothing: | ||||
| @@ -84,5 +77,7 @@ def _fade_word(word, dir): | |||||
| base = u'<span class="cv-hl-in">{0}</span>{1}' | base = u'<span class="cv-hl-in">{0}</span>{1}' | ||||
| return base.format(before, after) | return base.format(before, after) | ||||
| def _strip_word(word): | |||||
| def _strip_word(chain, word): | |||||
| if word == chain.START or word == chain.END: | |||||
| return word | |||||
| return sub("[^\w\s-]", "", word.lower(), flags=UNICODE) | return sub("[^\w\s-]", "", word.lower(), flags=UNICODE) | ||||