Made monospace text clickable.
This commit is contained in:
parent
b81b9371e6
commit
4e4e54dcc5
1 changed files with 67 additions and 16 deletions
|
|
@ -30,6 +30,10 @@ constexpr auto kStringLinkIndexShift = uint16(0x8000);
|
||||||
constexpr auto kMaxDiacAfterSymbol = 2;
|
constexpr auto kMaxDiacAfterSymbol = 2;
|
||||||
constexpr auto kSelectedSpoilerOpacity = 0.5;
|
constexpr auto kSelectedSpoilerOpacity = 0.5;
|
||||||
|
|
||||||
|
inline bool IsMono(int32 flags) {
|
||||||
|
return (flags & TextBlockFPre) || (flags & TextBlockFCode);
|
||||||
|
}
|
||||||
|
|
||||||
Qt::LayoutDirection StringDirection(
|
Qt::LayoutDirection StringDirection(
|
||||||
const QString &str,
|
const QString &str,
|
||||||
int from,
|
int from,
|
||||||
|
|
@ -239,11 +243,13 @@ private:
|
||||||
|
|
||||||
std::vector<EntityLinkData> _links;
|
std::vector<EntityLinkData> _links;
|
||||||
std::vector<EntityLinkData> _spoilers;
|
std::vector<EntityLinkData> _spoilers;
|
||||||
|
std::vector<EntityLinkData> _monos;
|
||||||
base::flat_map<
|
base::flat_map<
|
||||||
const QChar*,
|
const QChar*,
|
||||||
std::vector<StartedEntity>> _startedEntities;
|
std::vector<StartedEntity>> _startedEntities;
|
||||||
|
|
||||||
uint16 _maxLnkIndex = 0;
|
uint16 _maxLnkIndex = 0;
|
||||||
|
uint16 _maxShiftedLnkIndex = 0;
|
||||||
uint16 _maxSpoilerIndex = 0;
|
uint16 _maxSpoilerIndex = 0;
|
||||||
|
|
||||||
// current state
|
// current state
|
||||||
|
|
@ -343,6 +349,11 @@ void Parser::createBlock(int32 skipBack) {
|
||||||
if (_lnkIndex < kStringLinkIndexShift && _lnkIndex > _maxLnkIndex) {
|
if (_lnkIndex < kStringLinkIndexShift && _lnkIndex > _maxLnkIndex) {
|
||||||
_maxLnkIndex = _lnkIndex;
|
_maxLnkIndex = _lnkIndex;
|
||||||
}
|
}
|
||||||
|
if (_lnkIndex > kStringLinkIndexShift) {
|
||||||
|
_maxShiftedLnkIndex = std::max(
|
||||||
|
uint16(_lnkIndex - kStringLinkIndexShift),
|
||||||
|
_maxShiftedLnkIndex);
|
||||||
|
}
|
||||||
if (_spoilerIndex > _maxSpoilerIndex) {
|
if (_spoilerIndex > _maxSpoilerIndex) {
|
||||||
_maxSpoilerIndex = _spoilerIndex;
|
_maxSpoilerIndex = _spoilerIndex;
|
||||||
}
|
}
|
||||||
|
|
@ -459,14 +470,24 @@ bool Parser::checkEntities() {
|
||||||
flags = TextBlockFPlainLink;
|
flags = TextBlockFPlainLink;
|
||||||
} else if (entityType == EntityType::StrikeOut) {
|
} else if (entityType == EntityType::StrikeOut) {
|
||||||
flags = TextBlockFStrikeOut;
|
flags = TextBlockFStrikeOut;
|
||||||
} else if (entityType == EntityType::Code) { // #TODO entities
|
} else if ((entityType == EntityType::Code) // #TODO entities
|
||||||
flags = TextBlockFCode;
|
|| (entityType == EntityType::Pre)) {
|
||||||
} else if (entityType == EntityType::Pre) {
|
if (entityType == EntityType::Code) {
|
||||||
flags = TextBlockFPre;
|
flags = TextBlockFCode;
|
||||||
createBlock();
|
} else {
|
||||||
if (!_t->_blocks.empty() && _t->_blocks.back()->type() != TextBlockTNewline) {
|
flags = TextBlockFPre;
|
||||||
createNewlineBlock();
|
createBlock();
|
||||||
|
if (!_t->_blocks.empty()
|
||||||
|
&& _t->_blocks.back()->type() != TextBlockTNewline) {
|
||||||
|
createNewlineBlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
const auto end = _waitingEntity->offset() + entityLength;
|
||||||
|
_monos.push_back({
|
||||||
|
.text = QString(entityBegin, entityLength),
|
||||||
|
.data = QString(QChar(end)),
|
||||||
|
.type = entityType,
|
||||||
|
});
|
||||||
} else if (entityType == EntityType::Url
|
} else if (entityType == EntityType::Url
|
||||||
|| entityType == EntityType::Email
|
|| entityType == EntityType::Email
|
||||||
|| entityType == EntityType::Mention
|
|| entityType == EntityType::Mention
|
||||||
|
|
@ -706,8 +727,13 @@ void Parser::trimSourceRange() {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
void Parser::finalize(const TextParseOptions &options) {
|
void Parser::finalize(const TextParseOptions &options) {
|
||||||
_t->_links.resize(_maxLnkIndex);
|
_t->_links.resize(_maxLnkIndex + _maxShiftedLnkIndex);
|
||||||
_t->_spoilers.resize(_maxSpoilerIndex);
|
_t->_spoilers.resize(_maxSpoilerIndex);
|
||||||
|
auto monoLnk = uint16(1);
|
||||||
|
struct {
|
||||||
|
uint16 mono = 0;
|
||||||
|
uint16 lnk = 0;
|
||||||
|
} lastHandlerIndex;
|
||||||
for (auto &block : _t->_blocks) {
|
for (auto &block : _t->_blocks) {
|
||||||
const auto spoilerIndex = block->spoilerIndex();
|
const auto spoilerIndex = block->spoilerIndex();
|
||||||
if (spoilerIndex) {
|
if (spoilerIndex) {
|
||||||
|
|
@ -719,22 +745,46 @@ void Parser::finalize(const TextParseOptions &options) {
|
||||||
}
|
}
|
||||||
const auto shiftedIndex = block->lnkIndex();
|
const auto shiftedIndex = block->lnkIndex();
|
||||||
if (shiftedIndex <= kStringLinkIndexShift) {
|
if (shiftedIndex <= kStringLinkIndexShift) {
|
||||||
|
if (IsMono(block->flags())) {
|
||||||
|
const auto entityEnd = int(
|
||||||
|
_monos[monoLnk - 1].data.constData()->unicode());
|
||||||
|
if (block->from() >= entityEnd) {
|
||||||
|
monoLnk++;
|
||||||
|
}
|
||||||
|
const auto monoIndex = _maxLnkIndex
|
||||||
|
+ _maxShiftedLnkIndex
|
||||||
|
+ monoLnk;
|
||||||
|
block->setLnkIndex(monoIndex);
|
||||||
|
|
||||||
|
if (lastHandlerIndex.mono == monoIndex) {
|
||||||
|
continue; // Optimization.
|
||||||
|
}
|
||||||
|
const auto handler = Integration::Instance().createLinkHandler(
|
||||||
|
_monos[monoLnk - 1],
|
||||||
|
_context);
|
||||||
|
_t->_links.resize(monoIndex);
|
||||||
|
if (handler) {
|
||||||
|
_t->setLink(monoIndex, handler);
|
||||||
|
}
|
||||||
|
lastHandlerIndex.mono = monoIndex;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto realIndex = (shiftedIndex - kStringLinkIndexShift);
|
const auto realIndex = (shiftedIndex - kStringLinkIndexShift);
|
||||||
const auto index = _maxLnkIndex + realIndex;
|
const auto index = _maxLnkIndex + realIndex;
|
||||||
block->setLnkIndex(index);
|
block->setLnkIndex(index);
|
||||||
if (_t->_links.size() >= index) {
|
if (lastHandlerIndex.lnk == index) {
|
||||||
continue;
|
continue; // Optimization.
|
||||||
}
|
}
|
||||||
|
|
||||||
_t->_links.resize(index);
|
// _t->_links.resize(index);
|
||||||
const auto handler = Integration::Instance().createLinkHandler(
|
const auto handler = Integration::Instance().createLinkHandler(
|
||||||
_links[realIndex - 1],
|
_links[realIndex - 1],
|
||||||
_context);
|
_context);
|
||||||
if (handler) {
|
if (handler) {
|
||||||
_t->setLink(index, handler);
|
_t->setLink(index, handler);
|
||||||
}
|
}
|
||||||
|
lastHandlerIndex.lnk = index;
|
||||||
}
|
}
|
||||||
_t->_links.squeeze();
|
_t->_links.squeeze();
|
||||||
_t->_spoilers.squeeze();
|
_t->_spoilers.squeeze();
|
||||||
|
|
@ -1953,7 +2003,7 @@ private:
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
auto result = f;
|
auto result = f;
|
||||||
if ((flags & TextBlockFPre) || (flags & TextBlockFCode)) {
|
if (IsMono(flags)) {
|
||||||
result = result->monospace();
|
result = result->monospace();
|
||||||
} else {
|
} else {
|
||||||
if (flags & TextBlockFBold) {
|
if (flags & TextBlockFBold) {
|
||||||
|
|
@ -2592,12 +2642,13 @@ private:
|
||||||
} else {
|
} else {
|
||||||
_background = {};
|
_background = {};
|
||||||
}
|
}
|
||||||
if (block->lnkIndex() || (block->flags() & TextBlockFPlainLink)) {
|
if (IsMono(block->flags())) {
|
||||||
_currentPen = &_textPalette->linkFg->p;
|
|
||||||
_currentPenSelected = &_textPalette->selectLinkFg->p;
|
|
||||||
} else if ((block->flags() & TextBlockFCode) || (block->flags() & TextBlockFPre)) {
|
|
||||||
_currentPen = &_textPalette->monoFg->p;
|
_currentPen = &_textPalette->monoFg->p;
|
||||||
_currentPenSelected = &_textPalette->selectMonoFg->p;
|
_currentPenSelected = &_textPalette->selectMonoFg->p;
|
||||||
|
} else if (block->lnkIndex()
|
||||||
|
|| (block->flags() & TextBlockFPlainLink)) {
|
||||||
|
_currentPen = &_textPalette->linkFg->p;
|
||||||
|
_currentPenSelected = &_textPalette->selectLinkFg->p;
|
||||||
} else {
|
} else {
|
||||||
_currentPen = &_originalPen;
|
_currentPen = &_originalPen;
|
||||||
_currentPenSelected = &_originalPenSelected;
|
_currentPenSelected = &_originalPenSelected;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue