diff --git a/apps/openmw/mwdialogue/hypertextparser.cpp b/apps/openmw/mwdialogue/hypertextparser.cpp
index 776edac94..aa748e772 100644
--- a/apps/openmw/mwdialogue/hypertextparser.cpp
+++ b/apps/openmw/mwdialogue/hypertextparser.cpp
@@ -56,13 +56,17 @@ namespace MWDialogue
keywordList.sort(Misc::StringUtils::ciLess);
KeywordSearch keywordSearch;
- KeywordSearch::Match match;
for (std::list::const_iterator it = keywordList.begin(); it != keywordList.end(); ++it)
keywordSearch.seed(*it, 0 /*unused*/);
- for (std::string::const_iterator it = text.begin(); it != text.end() && keywordSearch.search(it, text.end(), match, text.begin()); it = match.mEnd)
- tokens.push_back(Token(std::string(match.mBeg, match.mEnd), Token::ImplicitKeyword));
+ std::vector::Match> matches;
+ keywordSearch.highlightKeywords(text.begin(), text.end(), matches);
+
+ for (std::vector::Match>::const_iterator it = matches.begin(); it != matches.end(); ++it)
+ {
+ tokens.push_back(Token(std::string(it->mBeg, it->mEnd), Token::ImplicitKeyword));
+ }
}
size_t removePseudoAsterisks(std::string & phrase)
diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp
index 51508890c..5ce492441 100644
--- a/apps/openmw/mwdialogue/keywordsearch.hpp
+++ b/apps/openmw/mwdialogue/keywordsearch.hpp
@@ -66,19 +66,20 @@ public:
return false;
}
- bool search (Point beg, Point end, Match & match, Point start)
+ void highlightKeywords (Point beg, Point end, std::vector& out)
{
for (Point i = beg; i != end; ++i)
{
// check if previous character marked start of new word
- if (i != start)
+ if (i != beg)
{
Point prev = i;
- --prev;
+ --prev;
if(isalpha(*prev))
continue;
}
+
// check first character
typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (std::tolower (*i, mLocale));
@@ -137,16 +138,48 @@ public:
if (t != candidate->second.mKeyword.end ())
continue;
- // we did it, report the good news
+ // found a keyword, but there might still be longer keywords that start somewhere _within_ this keyword
+ // we will resolve these overlapping keywords later, choosing the longest one in case of conflict
+ Match match;
match.mValue = candidate->second.mValue;
match.mBeg = i;
match.mEnd = k;
- return true;
+ out.push_back(match);
+ break;
}
}
- // no match in range, report the bad news
- return false;
+ // resolve overlapping keywords
+ for (typename std::vector::iterator it = out.begin(); it != out.end();)
+ {
+ typename std::vector::iterator next = it;
+ ++next;
+
+ if (next == out.end())
+ break;
+
+ if (it->mEnd <= next->mBeg)
+ {
+ ++it;
+ continue; // no overlap
+ }
+ else
+ {
+ // prefer the longer keyword
+ int size = it->mEnd - it->mBeg;
+ int nextSize = next->mEnd - next->mBeg;
+ if (size >= nextSize) // if both are the same length, then prefer the first keyword
+ {
+ out.erase(next);
+ continue;
+ }
+ else
+ {
+ it = out.erase(it);
+ continue;
+ }
+ }
+ }
}
private:
diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp
index e1e016714..db9fa9f6b 100644
--- a/apps/openmw/mwgui/dialogue.cpp
+++ b/apps/openmw/mwgui/dialogue.cpp
@@ -177,11 +177,13 @@ namespace MWGui
}
else
{
- std::string::const_iterator i = text.begin ();
- KeywordSearchT::Match match;
+ std::vector matches;
+ keywordSearch->highlightKeywords(text.begin(), text.end(), matches);
- while (i != text.end () && keywordSearch->search (i, text.end (), match, text.begin ()))
+ std::string::const_iterator i = text.begin ();
+ for (std::vector::iterator it = matches.begin(); it != matches.end(); ++it)
{
+ KeywordSearchT::Match match = *it;
if (i != match.mBeg)
addTopicLink (typesetter, 0, i - text.begin (), match.mBeg - text.begin ());
@@ -189,7 +191,6 @@ namespace MWGui
i = match.mEnd;
}
-
if (i != text.end ())
addTopicLink (typesetter, 0, i - text.begin (), text.size ());
}
diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp
index 059af463f..add2ac62c 100644
--- a/apps/openmw/mwgui/journalviewmodel.cpp
+++ b/apps/openmw/mwgui/journalviewmodel.cpp
@@ -174,12 +174,14 @@ struct JournalViewModelImpl : JournalViewModel
}
else
{
- std::string::const_iterator i = utf8text.begin ();
-
- KeywordSearchT::Match match;
+ std::vector matches;
+ mModel->mKeywordSearch.highlightKeywords(utf8text.begin(), utf8text.end(), matches);
- while (i != utf8text.end () && mModel->mKeywordSearch.search (i, utf8text.end (), match, utf8text.begin()))
+ std::string::const_iterator i = utf8text.begin ();
+ for (std::vector::const_iterator it = matches.begin(); it != matches.end(); ++it)
{
+ const KeywordSearchT::Match& match = *it;
+
if (i != match.mBeg)
visitor (0, i - utf8text.begin (), match.mBeg - utf8text.begin ());