fix bug with adding multiple tags at once

This commit is contained in:
GenevensiS
2026-03-18 05:48:30 +01:00
parent 1210dcdf16
commit 87dbb2d7aa
3 changed files with 82 additions and 16 deletions
+13 -7
View File
@@ -119,14 +119,20 @@ unique_ptr<TextValueAction> toggle_format_action(const TextValueP& value, vector
tag == _("li") ? compute_new_bullet_value (new_value, offset, start_i, end_i):
compute_new_simple_value (new_value, tag, start_i, end_i);
// Erase redundant tags
if (start != end) {
// don't simplify if start == end, this way we insert <b></b>, allowing the
// user to press Ctrl+B and start typing bold text
new_value = simplify_tagged(new_value);
if (start != end) {
// Simplify
new_value = simplify_tagged(new_value);
// Adjust selection
start_i = to_tagged_pos(new_value, untagged_start_i, true, true, true);
end_i = to_tagged_pos(new_value, untagged_end_i, false, false, false);
}
else {
// Don't simplify if start == end, this way we insert <b></b>,
// allowing the user to press Ctrl+B and start typing bold text
// Adjust selection
start_i = to_tagged_pos(new_value, untagged_start_i, true, false, true);
end_i = to_tagged_pos(new_value, untagged_end_i, true, false, true);
}
// Adjust selection
start_i = to_tagged_pos(new_value, untagged_start_i, true, false);
end_i = to_tagged_pos(new_value, untagged_end_i, true, false);
}
// Build action
if (value->value() == new_value) {
+65 -6
View File
@@ -129,10 +129,12 @@ String fix_old_tags(const String& str) {
return it;
}
[[nodiscard]] String::const_iterator skip_all_tags(String::const_iterator it, String::const_iterator end, bool skip_open, bool skip_close) {
[[nodiscard]] String::const_iterator skip_all_tags(String::const_iterator it, String::const_iterator end, bool skip_open, bool skip_close, bool skip_nonformat) {
// move after first possible position corresponding
while (it != end && *it == '<') {
if (it + 1 != end && *(it + 1) == '/') {
if (skip_nonformat && !is_formatting_tag(it, end)) {
it = skip_tag(it, end);
} else if (it + 1 != end && *(it + 1) == '/') {
if (skip_close) {
it = skip_tag(it, end);
} else {
@@ -149,7 +151,7 @@ String fix_old_tags(const String& str) {
return it;
}
[[nodiscard]] String::const_iterator advance_untagged(String::const_iterator it, String::const_iterator end, size_t n, bool after_open, bool after_close) {
[[nodiscard]] String::const_iterator advance_untagged(String::const_iterator it, String::const_iterator end, size_t n, bool after_open, bool after_close, bool after_nonformat) {
while (n > 0) {
it = skip_all_tags(it, end);
if (it != end) {
@@ -159,7 +161,7 @@ String fix_old_tags(const String& str) {
return it;
}
}
return skip_all_tags(it, end, after_open, after_close);
return skip_all_tags(it, end, after_open, after_close, after_nonformat);
}
[[nodiscard]] bool is_tag(String::const_iterator it, String::const_iterator end, const char* tag, bool strict) {
@@ -284,6 +286,63 @@ bool is_formatting_tag(const String& str, size_t pos) {
is_substr(str, pos, _("size")) || is_substr(str, pos, _("/size")) ||
is_substr(str, pos, _("color")) || is_substr(str, pos, _("/color"));
}
bool is_formatting_tag(String::const_iterator it, String::const_iterator end) {
// so ugly but so fast!
if (it == end) return false;
if (*it != '<') return false;
++it; if (it == end) return false;
if (*it == '/') {++it; if (it == end) return false;}
if (*it == 'b' || *it == 'i' || *it == 'u') return true;
if (*it == 's') {
++it; if (it == end) return false;
if (*it == 'y') {
++it; if (it == end) return false;
if (*it != 'm') return false;
return true;
}
if (*it == 't') {
++it; if (it == end) return false;
if (*it != 'r') return false;
++it; if (it == end) return false;
if (*it != 'i') return false;
++it; if (it == end) return false;
if (*it != 'k') return false;
++it; if (it == end) return false;
if (*it != 'e') return false;
return true;
}
if (*it == 'i') {
++it; if (it == end) return false;
if (*it != 'z') return false;
++it; if (it == end) return false;
if (*it != 'e') return false;
return true;
}
return false;
}
if (*it == 'f') {
++it; if (it == end) return false;
if (*it != 'o') return false;
++it; if (it == end) return false;
if (*it != 'n') return false;
++it; if (it == end) return false;
if (*it != 't') return false;
return true;
}
if (*it == 'c') {
++it; if (it == end) return false;
if (*it != 'o') return false;
++it; if (it == end) return false;
if (*it != 'l') return false;
++it; if (it == end) return false;
if (*it != 'o') return false;
++it; if (it == end) return false;
if (*it != 'r') return false;
return true;
}
return false;
}
[[nodiscard]] size_t in_tag(const String& str, const String& tag, size_t start, size_t end, bool strict) {
size_t last_start = String::npos;
@@ -343,10 +402,10 @@ size_t to_untagged_pos(const String& str, size_t pos) {
return untag(str.substr(0, pos)).size();
}
size_t to_tagged_pos(const String& str, size_t pos, bool after_open, bool after_close) {
size_t to_tagged_pos(const String& str, size_t pos, bool after_open, bool after_close, bool after_nonformat) {
String::const_iterator it = str.begin();
const String::const_iterator end = str.end();
it = advance_untagged(it, end, pos, after_open, after_close);
it = advance_untagged(it, end, pos, after_open, after_close, after_nonformat);
return std::distance(str.begin(), it);
}
+4 -3
View File
@@ -79,6 +79,7 @@ String fix_old_tags(const String&);
/// Does a string contain a tag at the given location?
/** Matches <b <i <u <strike <font <size <color <sym or their anti tags */
[[nodiscard]] bool is_formatting_tag(const String& str, size_t pos);
[[nodiscard]] bool is_formatting_tag(String::const_iterator it, String::const_iterator end);
/// Is the given range entirely contained in a given tagged block?
/** If so: return the start position of that tag, otherwise returns String::npos
@@ -113,11 +114,11 @@ String anti_tag(const String& tag);
[[nodiscard]] String::const_iterator skip_all_tags(String::const_iterator it, String::const_iterator end);
// Skip past all open/close tags
[[nodiscard]] String::const_iterator skip_all_tags(String::const_iterator it, String::const_iterator end, bool skip_open, bool skip_close);
[[nodiscard]] String::const_iterator skip_all_tags(String::const_iterator it, String::const_iterator end, bool skip_open, bool skip_close, bool skip_nonformat=false);
// Advance an iterator by n positions, not counting tags
// For example: advance_untagged("<b>abc</b>",_,2) = "c</b>"
[[nodiscard]] String::const_iterator advance_untagged(String::const_iterator it, String::const_iterator end, size_t n, bool after_open=false, bool after_close=false);
[[nodiscard]] String::const_iterator advance_untagged(String::const_iterator it, String::const_iterator end, size_t n, bool after_open=false, bool after_close=false, bool after_nonformat=false);
// Find the position of the closing tag matching the tag at it
// If not found, returns end
@@ -142,7 +143,7 @@ size_t to_untagged_pos(const String& str, size_t pos);
/// Take a tagged string and a position inside the untagged version,
/// return the position in the tagged version.
size_t to_tagged_pos(const String& str, size_t pos, bool after_open=false, bool after_close=false);
size_t to_tagged_pos(const String& str, size_t pos, bool after_open=false, bool after_close=false, bool after_nonformat=false);
/// Directions of cursor movement
enum Movement