Highlight word from search query.

This commit is contained in:
John Preston 2024-12-09 14:23:16 +04:00
parent 3957fea5e4
commit 3565215c81
3 changed files with 104 additions and 30 deletions

View file

@ -88,6 +88,7 @@ constexpr auto SwitchAtTopMsgId = MsgId(SpecialMsgIdShift + 2);
constexpr auto ShowAndStartBotMsgId = MsgId(SpecialMsgIdShift + 4);
constexpr auto ShowAndMaybeStartBotMsgId = MsgId(SpecialMsgIdShift + 5);
constexpr auto ShowForChooseMessagesMsgId = MsgId(SpecialMsgIdShift + 6);
constexpr auto kSearchQueryOffsetHint = -1;
static_assert(SpecialMsgIdShift + 0xFF < 0);
static_assert(-(SpecialMsgIdShift + 0xFF) > ServerMaxMsgId);

View file

@ -696,16 +696,19 @@ void Widget::chosenRow(const ChosenRow &row) {
}
return;
} else if (const auto topic = row.key.topic()) {
auto params = Window::SectionShow(
Window::SectionShow::Way::ClearStack);
params.highlightPart.text = _searchState.query;
if (!params.highlightPart.empty()) {
params.highlightPartOffsetHint = kSearchQueryOffsetHint;
}
if (row.newWindow) {
controller()->showInNewWindow(
Window::SeparateId(topic),
row.message.fullId.msg);
} else {
session().data().saveViewAsMessages(topic->forum(), false);
controller()->showThread(
topic,
row.message.fullId.msg,
Window::SectionShow::Way::ClearStack);
controller()->showThread(topic, row.message.fullId.msg, params);
}
} else if (history
&& row.userpicClick
@ -742,13 +745,16 @@ void Widget::chosenRow(const ChosenRow &row) {
const auto showAtMsgId = controller()->uniqueChatsInSearchResults()
? ShowAtUnreadMsgId
: row.message.fullId.msg;
auto params = Window::SectionShow(
Window::SectionShow::Way::ClearStack);
params.highlightPart.text = _searchState.query;
if (!params.highlightPart.empty()) {
params.highlightPartOffsetHint = kSearchQueryOffsetHint;
}
if (row.newWindow) {
controller()->showInNewWindow(peer, showAtMsgId);
} else {
controller()->showThread(
history,
showAtMsgId,
Window::SectionShow::Way::ClearStack);
controller()->showThread(history, showAtMsgId, params);
hideChildList();
}
} else if (const auto folder = row.key.folder()) {

View file

@ -94,6 +94,89 @@ Element *MousedElement/* = nullptr*/;
return session->tryResolveWindow();
}
[[nodiscard]] TextSelection FindSearchQueryHighlight(
const QString &text,
const QString &query) {
const auto lower = query.toLower();
const auto inside = text.toLower();
const auto find = [&](QStringView part) {
auto skip = 0;
if (const auto from = inside.indexOf(part, skip); from >= 0) {
if (!from || !inside[from - 1].isLetterOrNumber()) {
return from;
}
skip = from + 1;
}
return -1;
};
if (const auto from = find(lower); from >= 0) {
const auto till = from + query.size();
if (till >= inside.size() || !inside[till].isLetterOrNumber()) {
return { uint16(from), uint16(till) };
}
}
const auto tillEndOfWord = [&](int from) {
for (auto till = from + 1; till != inside.size(); ++till) {
if (!inside[till].isLetterOrNumber()) {
return TextSelection{ uint16(from), uint16(till) };
}
}
return TextSelection{ uint16(from), uint16(inside.size()) };
};
const auto words = QStringView(lower).split(
QRegularExpression(
u"[\\W]"_q,
QRegularExpression::UseUnicodePropertiesOption),
Qt::SkipEmptyParts);
for (const auto &word : words) {
const auto length = int(word.size());
const auto cut = length / 2;
const auto part = word.mid(0, length - cut);
const auto offset = find(part);
if (offset < 0) {
continue;
}
for (auto i = 0; i != cut; ++i) {
const auto part = word.mid(0, length - i);
if (const auto from = find(part); from >= 0) {
return tillEndOfWord(from);
}
}
return tillEndOfWord(offset);
}
return {};
}
[[nodiscard]] TextSelection ApplyModificationsFrom(
TextSelection result,
const Ui::Text::String &text) {
if (result.empty()) {
return result;
}
for (const auto &modification : text.modifications()) {
if (modification.position >= result.to) {
break;
}
if (modification.added) {
++result.to;
}
const auto shiftTo = std::min(
int(modification.skipped),
result.to - modification.position);
result.to -= shiftTo;
if (modification.position <= result.from) {
if (modification.added) {
++result.from;
}
const auto shiftFrom = std::min(
int(modification.skipped),
result.from - modification.position);
result.from -= shiftFrom;
}
}
return result;
}
} // namespace
std::unique_ptr<Ui::PathShiftGradient> MakePathShiftGradient(
@ -1726,6 +1809,11 @@ TextSelection Element::FindSelectionFromQuote(
return {};
}
const auto &original = quote.item->originalText();
if (quote.offset == kSearchQueryOffsetHint) {
return ApplyModificationsFrom(
FindSearchQueryHighlight(original.text, quote.text.text),
text);
}
const auto length = int(original.text.size());
const auto qlength = int(quote.text.text.size());
const auto checkAt = [&](int offset) {
@ -1789,28 +1877,7 @@ TextSelection Element::FindSelectionFromQuote(
if (result.empty()) {
return {};
}
for (const auto &modification : text.modifications()) {
if (modification.position >= result.to) {
break;
}
if (modification.added) {
++result.to;
}
const auto shiftTo = std::min(
int(modification.skipped),
result.to - modification.position);
result.to -= shiftTo;
if (modification.position <= result.from) {
if (modification.added) {
++result.from;
}
const auto shiftFrom = std::min(
int(modification.skipped),
result.from - modification.position);
result.from -= shiftFrom;
}
}
return result;
return ApplyModificationsFrom(result, text);
}
Reactions::ButtonParameters Element::reactionButtonParameters(