diff options
author | Dennis van der Schagt <dennisschagt@gmail.com> | 2024-04-04 22:18:39 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-04 22:18:39 +0200 |
commit | e7470294144d464fe1fa1d796a6efb4cf507f85a (patch) | |
tree | 5d7fdc5f63cc15ecf34f0594529197cb24c7121c | |
parent | 24bb2c41b2bd3f8ad019a815c8d9f6f06b06647c (diff) | |
parent | 73c8b3d065581944a7a91aa9982a389b3ba9619a (diff) |
Merge pull request #2084 from dennisschagt/implement-stflstring-issue-806
Add StflString to help styling/quoting for STFL
30 files changed, 536 insertions, 501 deletions
diff --git a/include/dirbrowserformaction.h b/include/dirbrowserformaction.h index 787145e8..35749625 100644 --- a/include/dirbrowserformaction.h +++ b/include/dirbrowserformaction.h @@ -9,6 +9,7 @@ #include "formaction.h" #include "listformatter.h" #include "listwidget.h" +#include "stflrichtext.h" namespace newsboat { @@ -41,7 +42,7 @@ private: void add_directory(std::vector<file_system::FileSystemEntry>& id_at_position, std::string dirname); std::vector<file_system::FileSystemEntry> id_at_position; - std::vector<std::string> lines; + std::vector<StflRichText> lines; std::string get_formatted_dirname(std::string dirname, mode_t mode); diff --git a/include/feedlistformaction.h b/include/feedlistformaction.h index cd3e35e5..bfe99cfb 100644 --- a/include/feedlistformaction.h +++ b/include/feedlistformaction.h @@ -8,6 +8,7 @@ #include "listformaction.h" #include "matcher.h" #include "regexmanager.h" +#include "stflrichtext.h" #include "view.h" namespace newsboat { @@ -83,7 +84,7 @@ private: std::string get_title(std::shared_ptr<RssFeed> feed); - std::string format_line(const std::string& feedlist_format, + StflRichText format_line(const std::string& feedlist_format, std::shared_ptr<RssFeed> feed, unsigned int pos, unsigned int width); diff --git a/include/filebrowserformaction.h b/include/filebrowserformaction.h index 2fb70c60..b8508ecc 100644 --- a/include/filebrowserformaction.h +++ b/include/filebrowserformaction.h @@ -9,6 +9,7 @@ #include "formaction.h" #include "listformatter.h" #include "listwidget.h" +#include "stflrichtext.h" namespace newsboat { @@ -47,7 +48,7 @@ private: std::string filename); std::string get_filename_suggestion(const std::string& s); std::vector<file_system::FileSystemEntry> id_at_position; - std::vector<std::string> lines; + std::vector<StflRichText> lines; std::string get_formatted_filename(std::string filename, mode_t mode); diff --git a/include/itemlistformaction.h b/include/itemlistformaction.h index 8ce86ded..a212b3dd 100644 --- a/include/itemlistformaction.h +++ b/include/itemlistformaction.h @@ -11,6 +11,7 @@ #include "listformaction.h" #include "listformatter.h" #include "regexmanager.h" +#include "stflrichtext.h" #include "view.h" namespace newsboat { @@ -134,7 +135,7 @@ private: void prepare_set_filterpos(); - std::string item2formatted_line(const ItemPtrPosPair& item, + StflRichText item2formatted_line(const ItemPtrPosPair& item, const unsigned int width, const std::string& itemlist_format, const std::string& datetime_format); diff --git a/include/listformatter.h b/include/listformatter.h index 07e303f6..9e71be77 100644 --- a/include/listformatter.h +++ b/include/listformatter.h @@ -7,6 +7,7 @@ #include <vector> #include "regexmanager.h" +#include "stflrichtext.h" namespace newsboat { @@ -14,9 +15,8 @@ class ListFormatter { public: ListFormatter(RegexManager* r = nullptr, const std::string& loc = ""); ~ListFormatter(); - void add_line(const std::string& text); - void set_line(const unsigned int itempos, - const std::string& text); + void add_line(const StflRichText& text); + void set_line(const unsigned int itempos, const StflRichText& text); void clear() { lines.clear(); @@ -28,7 +28,7 @@ public: } private: - std::vector<std::string> lines; + std::vector<StflRichText> lines; RegexManager* rxman; std::string location; }; diff --git a/include/listwidgetbackend.h b/include/listwidgetbackend.h index f148eb97..5136dda1 100644 --- a/include/listwidgetbackend.h +++ b/include/listwidgetbackend.h @@ -9,6 +9,7 @@ #include "listformatter.h" #include "regexmanager.h" #include "stflpp.h" +#include "stflrichtext.h" namespace newsboat { @@ -26,7 +27,7 @@ public: std::uint32_t get_num_lines(); void invalidate_list_content(std::uint32_t num_lines, - std::function<std::string(std::uint32_t, std::uint32_t)> get_line_method); + std::function<StflRichText(std::uint32_t, std::uint32_t)> get_line_method); protected: virtual void on_list_changed() = 0; @@ -40,8 +41,8 @@ private: ListFormatter listfmt; std::uint32_t num_lines; std::uint32_t scroll_offset; - std::map<std::uint32_t, std::string> line_cache; - std::function<std::string(std::uint32_t, std::uint32_t)> get_formatted_line; + std::map<std::uint32_t, StflRichText> line_cache; + std::function<StflRichText(std::uint32_t, std::uint32_t)> get_formatted_line; }; } // namespace newsboat diff --git a/include/pbview.h b/include/pbview.h index 53feb789..b2fbf7f1 100644 --- a/include/pbview.h +++ b/include/pbview.h @@ -6,6 +6,7 @@ #include "listwidget.h" #include "textviewwidget.h" #include "stflpp.h" +#include "stflrichtext.h" namespace newsboat { class KeyMap; @@ -36,7 +37,7 @@ private: std::pair<double, std::string> get_speed_human_readable(double kbps); void handle_resize(); - std::string format_line(const std::string& podlist_format, + StflRichText format_line(const std::string& podlist_format, const Download& dl, unsigned int pos, unsigned int width); diff --git a/include/regexmanager.h b/include/regexmanager.h index 868b338a..ebc911c1 100644 --- a/include/regexmanager.h +++ b/include/regexmanager.h @@ -13,6 +13,7 @@ #include "configactionhandler.h" #include "matcher.h" #include "regexowner.h" +#include "stflrichtext.h" namespace newsboat { @@ -22,15 +23,10 @@ public: void handle_action(const std::string& action, const std::vector<std::string>& params) override; void dump_config(std::vector<std::string>& config_output) const override; - void quote_and_highlight(std::string& str, const std::string& location); + void quote_and_highlight(StflRichText& stflString, const std::string& location); void remove_last_regex(const std::string& location); int article_matches(Matchable* item); int feed_matches(Matchable* feed); - std::map<size_t, std::string> extract_style_tags(std::string& str); - void insert_style_tags(std::string& str, std::map<size_t, std::string>& tags); - void merge_style_tag(std::map<size_t, std::string>& tags, - const std::string& tag, - size_t start, size_t end); std::string get_attrs_stfl_string(const std::string& location, bool hasFocus); private: diff --git a/include/stflrichtext.h b/include/stflrichtext.h new file mode 100644 index 00000000..bf0bd2ed --- /dev/null +++ b/include/stflrichtext.h @@ -0,0 +1,42 @@ +#ifndef NEWSBOAT_STFLSTRING_H_ +#define NEWSBOAT_STFLSTRING_H_ + +#include <map> +#include <string> + +namespace newsboat { + +class StflRichText { +public: + static StflRichText from_plaintext(std::string); + static StflRichText from_quoted(std::string); + + StflRichText(const StflRichText&) = default; + StflRichText(StflRichText&&) = default; + StflRichText& operator=(const StflRichText&) = default; + StflRichText& operator=(StflRichText&&) = default; + ~StflRichText() = default; + + friend StflRichText operator+(StflRichText left, const StflRichText& right); + + void apply_style_tag(const std::string& tag, size_t start, size_t end); + + std::string plaintext() const; + std::string stfl_quoted() const; + +private: + StflRichText(std::string&&, + std::map<size_t, std::string>&&); // Only constructable using the public static functions + static std::map<size_t, std::string> extract_style_tags(std::string&); + static void merge_style_tag(std::map<size_t, std::string>& tags, const std::string& tag, + size_t start, size_t end); + static std::string insert_style_tags(const std::string& str, + const std::map<size_t, std::string>& tags); + + std::string text; // plaintext string (without highlighting) + std::map<size_t, std::string> style_tags; +}; + +} // namespace newsboat + +#endif /* NEWSBOAT_STFLSTRING_H_ */ diff --git a/mk/newsboat.deps b/mk/newsboat.deps index 19b068eb..e4f5b51c 100644 --- a/mk/newsboat.deps +++ b/mk/newsboat.deps @@ -58,6 +58,7 @@ src/rssparser.cpp src/searchresultslistformaction.cpp src/selectformaction.cpp src/statusline.cpp +src/stflrichtext.cpp src/tagsouppullparser.cpp src/textformatter.cpp src/textviewwidget.cpp diff --git a/mk/podboat.deps b/mk/podboat.deps index b42bd3af..9cb9f30f 100644 --- a/mk/podboat.deps +++ b/mk/podboat.deps @@ -10,4 +10,5 @@ src/poddlthread.cpp src/queueloader.cpp src/regexmanager.cpp src/regexowner.cpp +src/stflrichtext.cpp src/textviewwidget.cpp diff --git a/src/dialogsformaction.cpp b/src/dialogsformaction.cpp index 9654a87c..b7eefee9 100644 --- a/src/dialogsformaction.cpp +++ b/src/dialogsformaction.cpp @@ -6,6 +6,7 @@ #include "config.h" #include "fmtstrformatter.h" #include "listformatter.h" +#include "stflrichtext.h" #include "strprintf.h" #include "utils.h" #include "view.h" @@ -31,13 +32,13 @@ void DialogsFormAction::prepare() if (do_redraw) { update_heading(); - auto render_line = [this](std::uint32_t line, std::uint32_t width) -> std::string { + auto render_line = [this](std::uint32_t line, std::uint32_t width) -> StflRichText { (void)width; const auto formaction_names = v.get_formaction_names(); const auto& fa = formaction_names[line]; const bool is_current_formaction = v.get_formaction(fa.first) == get_parent_formaction(); - return utils::quote_for_stfl( + return StflRichText::from_plaintext( strprintf::fmt("%4u %s %s", line + 1, is_current_formaction ? "*" : " ", diff --git a/src/dirbrowserformaction.cpp b/src/dirbrowserformaction.cpp index 0f1527b1..03335014 100644 --- a/src/dirbrowserformaction.cpp +++ b/src/dirbrowserformaction.cpp @@ -247,7 +247,7 @@ void DirBrowserFormAction::prepare() add_directory(id_at_position, directory); } - auto render_line = [this](std::uint32_t line, std::uint32_t width) -> std::string { + auto render_line = [this](std::uint32_t line, std::uint32_t width) -> StflRichText { (void)width; return lines[line]; }; @@ -330,7 +330,7 @@ void DirBrowserFormAction::add_directory( group, sizestr, formatteddirname); - lines.push_back(utils::quote_for_stfl(line)); + lines.push_back(StflRichText::from_plaintext(line)); id_at_position.push_back(file_system::FileSystemEntry{ftype, dirname}); } } diff --git a/src/feedlistformaction.cpp b/src/feedlistformaction.cpp index d65b6aca..b2877ccc 100644 --- a/src/feedlistformaction.cpp +++ b/src/feedlistformaction.cpp @@ -624,10 +624,10 @@ void FeedListFormAction::set_feedlist( update_visible_feeds(feeds); auto render_line = [this, feedlist_format](std::uint32_t line, - std::uint32_t width) -> std::string { + std::uint32_t width) -> StflRichText { if (line >= visible_feeds.size()) { - return "ERROR"; + return StflRichText::from_plaintext("ERROR"); } auto& feed = visible_feeds[line]; return format_line(feedlist_format, feed.first, feed.second, width); @@ -1061,7 +1061,7 @@ std::string FeedListFormAction::get_title(std::shared_ptr<RssFeed> feed) return title; } -std::string FeedListFormAction::format_line(const std::string& feedlist_format, +StflRichText FeedListFormAction::format_line(const std::string& feedlist_format, std::shared_ptr<RssFeed> feed, unsigned int pos, unsigned int width) @@ -1084,19 +1084,20 @@ std::string FeedListFormAction::format_line(const std::string& feedlist_format, fmt.register_fmt('L', utils::censor_url(feed->rssurl())); fmt.register_fmt('d', utils::utf8_to_locale(feed->description())); - auto formattedLine = fmt.do_format(feedlist_format, width); - formattedLine = utils::quote_for_stfl(formattedLine); + const auto formattedLine = fmt.do_format(feedlist_format, width); + auto stflFormattedLine = StflRichText::from_plaintext(formattedLine); - const int id = rxman.feed_matches(feed.get()); - if (id != -1) { - formattedLine = strprintf::fmt("<%d>%s</>", id, formattedLine); + if (unread_count > 0) { + stflFormattedLine.apply_style_tag("<unread>", 0, formattedLine.length()); } - if (unread_count > 0) { - formattedLine = strprintf::fmt("<unread>%s</>", formattedLine); + const int id = rxman.feed_matches(feed.get()); + if (id != -1) { + const auto tag = strprintf::fmt("<%d>", id); + stflFormattedLine.apply_style_tag(tag, 0, formattedLine.length()); } - return formattedLine; + return stflFormattedLine; } std::string FeedListFormAction::title() diff --git a/src/filebrowserformaction.cpp b/src/filebrowserformaction.cpp index 4266492d..fb307b22 100644 --- a/src/filebrowserformaction.cpp +++ b/src/filebrowserformaction.cpp @@ -273,7 +273,7 @@ void FileBrowserFormAction::prepare() } - auto render_line = [this](std::uint32_t line, std::uint32_t width) -> std::string { + auto render_line = [this](std::uint32_t line, std::uint32_t width) -> StflRichText { (void)width; return lines[line]; }; @@ -354,7 +354,7 @@ void FileBrowserFormAction::add_file( group, sizestr, formattedfilename); - lines.push_back(utils::quote_for_stfl(line)); + lines.push_back(StflRichText::from_plaintext(line)); id_at_position.push_back(file_system::FileSystemEntry{ftype, filename}); } } diff --git a/src/helpformaction.cpp b/src/helpformaction.cpp index 7f479c08..2ce2afc2 100644 --- a/src/helpformaction.cpp +++ b/src/helpformaction.cpp @@ -120,14 +120,14 @@ void HelpFormAction::prepare() desc.desc); line = utils::quote_for_stfl(line); line = apply_highlights(line); - listfmt.add_line(line); + listfmt.add_line(StflRichText::from_quoted(line)); } } if (!syskey_descriptions.empty()) { - listfmt.add_line(""); - listfmt.add_line(_("Generic bindings:")); - listfmt.add_line(""); + listfmt.add_line(StflRichText::from_plaintext("")); + listfmt.add_line(StflRichText::from_plaintext(_("Generic bindings:"))); + listfmt.add_line(StflRichText::from_plaintext("")); for (const auto& desc : syskey_descriptions) { if (should_be_visible(desc)) { @@ -137,31 +137,31 @@ void HelpFormAction::prepare() desc.desc); line = utils::quote_for_stfl(line); line = apply_highlights(line); - listfmt.add_line(line); + listfmt.add_line(StflRichText::from_quoted(line)); } } } if (!unbound_descriptions.empty()) { - listfmt.add_line(""); - listfmt.add_line(_("Unbound functions:")); - listfmt.add_line(""); + listfmt.add_line(StflRichText::from_plaintext("")); + listfmt.add_line(StflRichText::from_plaintext(_("Unbound functions:"))); + listfmt.add_line(StflRichText::from_plaintext("")); for (const auto& desc : unbound_descriptions) { if (should_be_visible(desc)) { std::string line = strprintf::fmt("%-39s %s", desc.cmd, desc.desc); line = utils::quote_for_stfl(line); line = apply_highlights(line); - listfmt.add_line(line); + listfmt.add_line(StflRichText::from_quoted(line)); } } } const auto macros = v.get_keymap()->get_macro_descriptions(); if (!macros.empty()) { - listfmt.add_line(""); - listfmt.add_line(_("Macros:")); - listfmt.add_line(""); + listfmt.add_line(StflRichText::from_plaintext("")); + listfmt.add_line(StflRichText::from_plaintext(_("Macros:"))); + listfmt.add_line(StflRichText::from_plaintext("")); for (const auto& macro : macros) { const std::string key = macro.first.to_bindkey_string(); @@ -171,7 +171,7 @@ void HelpFormAction::prepare() std::string line = strprintf::fmt("<macro-prefix>%s %s", key, description); line = utils::quote_for_stfl(line); line = apply_highlights(line); - listfmt.add_line(line); + listfmt.add_line(StflRichText::from_quoted(line)); } } diff --git a/src/itemlistformaction.cpp b/src/itemlistformaction.cpp index f3aa10b1..1d1d851f 100644 --- a/src/itemlistformaction.cpp +++ b/src/itemlistformaction.cpp @@ -1072,10 +1072,10 @@ void ItemListFormAction::draw_items() cfg->get_configvalue("articlelist-format"); auto render_line = [this, itemlist_format, datetime_format](std::uint32_t line, - std::uint32_t width) -> std::string { + std::uint32_t width) -> StflRichText { if (line >= visible_items.size()) { - return "ERROR"; + return StflRichText::from_plaintext("ERROR"); } auto& item = visible_items[line]; return item2formatted_line(item, width, itemlist_format, datetime_format); @@ -1140,7 +1140,7 @@ void ItemListFormAction::prepare() prepare_set_filterpos(); } -std::string ItemListFormAction::item2formatted_line(const ItemPtrPosPair& item, +StflRichText ItemListFormAction::item2formatted_line(const ItemPtrPosPair& item, const unsigned int width, const std::string& itemlist_format, const std::string& datetime_format) @@ -1182,19 +1182,20 @@ std::string ItemListFormAction::item2formatted_line(const ItemPtrPosPair& item, fmt.register_fmt('L', item.first->length()); - auto formattedLine = fmt.do_format(itemlist_format, width); - formattedLine = utils::quote_for_stfl(formattedLine); + const auto formattedLine = fmt.do_format(itemlist_format, width); + auto stflFormattedLine = StflRichText::from_plaintext(formattedLine); const int id = rxman.article_matches(item.first.get()); if (id != -1) { - formattedLine = strprintf::fmt("<%d>%s</>", id, formattedLine); + const auto tag = strprintf::fmt("<%d>", id); + stflFormattedLine.apply_style_tag(tag, 0, formattedLine.length()); } if (item.first->unread()) { - formattedLine = strprintf::fmt("<unread>%s</>", formattedLine); + stflFormattedLine.apply_style_tag("<unread>", 0, formattedLine.length()); } - return formattedLine; + return stflFormattedLine; } void ItemListFormAction::goto_item(const std::string& title) @@ -1279,7 +1280,7 @@ void ItemListFormAction::set_head(const std::string& s, bool ItemListFormAction::jump_to_previous_unread_item(bool start_with_last) { - const int itempos = list.get_position(); + const int itempos = list.get_position(); for (int i = (start_with_last ? itempos : (itempos - 1)); i >= 0; --i) { LOG(Level::DEBUG, "ItemListFormAction::jump_to_previous_unread_item: " diff --git a/src/listformatter.cpp b/src/listformatter.cpp index a33d21da..c2e61c1a 100644 --- a/src/listformatter.cpp +++ b/src/listformatter.cpp @@ -4,6 +4,7 @@ #include <limits.h> #include "stflpp.h" +#include "stflrichtext.h" #include "strprintf.h" #include "utils.h" @@ -16,26 +17,24 @@ ListFormatter::ListFormatter(RegexManager* r, const std::string& loc) ListFormatter::~ListFormatter() {} -void ListFormatter::add_line(const std::string& text) +void ListFormatter::add_line(const StflRichText& text) { + LOG(Level::DEBUG, "ListFormatter::add_line: `%s'", text.stfl_quoted()); set_line(UINT_MAX, text); - LOG(Level::DEBUG, "ListFormatter::add_line: `%s'", text); } void ListFormatter::set_line(const unsigned int itempos, - const std::string& text) + const StflRichText& text) { - std::vector<std::string> formatted_text; - - formatted_text.push_back(utils::wstr2str(utils::clean_nonprintable_characters( - utils::str2wstr(text)))); + const std::wstring wide = utils::str2wstr(text.stfl_quoted()); + const std::wstring cleaned = utils::clean_nonprintable_characters(wide); + const std::string formatted_text = utils::wstr2str(cleaned); + const StflRichText stflRichText = StflRichText::from_quoted(formatted_text); if (itempos == UINT_MAX) { - lines.insert(lines.cend(), - formatted_text.cbegin(), - formatted_text.cend()); + lines.push_back(stflRichText); } else { - lines[itempos] = formatted_text[0]; + lines[itempos] = stflRichText; } } @@ -47,7 +46,7 @@ std::string ListFormatter::format_list() const rxman->quote_and_highlight(str, location); } format_cache.append(strprintf::fmt( - "{listitem text:%s}", Stfl::quote(str))); + "{listitem text:%s}", Stfl::quote(str.stfl_quoted()))); } format_cache.push_back('}'); return format_cache; diff --git a/src/listwidgetbackend.cpp b/src/listwidgetbackend.cpp index 760774d5..5872e2d0 100644 --- a/src/listwidgetbackend.cpp +++ b/src/listwidgetbackend.cpp @@ -55,7 +55,7 @@ std::uint32_t ListWidgetBackend::get_num_lines() } void ListWidgetBackend::invalidate_list_content(std::uint32_t line_count, - std::function<std::string(std::uint32_t, std::uint32_t)> get_line_method) + std::function<StflRichText(std::uint32_t, std::uint32_t)> get_line_method) { line_cache.clear(); get_formatted_line = get_line_method; @@ -85,9 +85,9 @@ void ListWidgetBackend::render() listfmt.clear(); for (std::uint32_t i = 0; i < visible_content_lines; ++i) { const std::uint32_t line = scroll_offset + i; - std::string formatted_line = "NO FORMATTER DEFINED"; + auto formatted_line = StflRichText::from_plaintext("NO FORMATTER DEFINED"); if (line_cache.count(line) >= 1) { - formatted_line = line_cache[line]; + formatted_line = line_cache.at(line); } else if (get_formatted_line) { formatted_line = get_formatted_line(line, viewport_width); line_cache.insert({line, formatted_line}); diff --git a/src/pbview.cpp b/src/pbview.cpp index 8066fdcb..c4113fa8 100644 --- a/src/pbview.cpp +++ b/src/pbview.cpp @@ -90,7 +90,7 @@ void PbView::run(bool auto_download, bool wrap_scroll) dllist_form.run(-3); // compute all widget dimensions auto render_line = [this, line_format](std::uint32_t line, - std::uint32_t width) -> std::string { + std::uint32_t width) -> StflRichText { const auto& downloads = ctrl.downloads(); const auto& dl = downloads.at(line); return format_line(line_format, dl, line, width); @@ -314,7 +314,7 @@ void PbView::run_help() desc.cmd, desc.desc); - listfmt.add_line(descline); + listfmt.add_line(StflRichText::from_plaintext(descline)); } help_textview.stfl_replace_lines(listfmt.get_lines_count(), @@ -395,7 +395,7 @@ void PbView::set_dllist_keymap_hint() dllist_form.set("help", keymap_hint); } -std::string PbView::format_line(const std::string& podlist_format, +StflRichText PbView::format_line(const std::string& podlist_format, const Download& dl, unsigned int pos, unsigned int width) @@ -419,8 +419,7 @@ std::string PbView::format_line(const std::string& podlist_format, fmt.register_fmt('b', strprintf::fmt("%s", dl.basename())); auto formattedLine = fmt.do_format(podlist_format, width); - formattedLine = utils::quote_for_stfl(formattedLine); - return formattedLine; + return StflRichText::from_plaintext(formattedLine); } } // namespace podboat diff --git a/src/regexmanager.cpp b/src/regexmanager.cpp index 2d9de693..b32846ce 100644 --- a/src/regexmanager.cpp +++ b/src/regexmanager.cpp @@ -8,6 +8,7 @@ #include "confighandlerexception.h" #include "configparser.h" #include "logger.h" +#include "stflrichtext.h" #include "strprintf.h" #include "utils.h" @@ -78,104 +79,12 @@ void RegexManager::remove_last_regex(const std::string& location) regexes.pop_back(); } -std::map<size_t, std::string> RegexManager::extract_style_tags(std::string& str) -{ - std::map<size_t, std::string> tags; - - size_t pos = 0; - while (pos < str.size()) { - auto tag_start = str.find_first_of("<>", pos); - if (tag_start == std::string::npos) { - break; - } - if (str[tag_start] == '>') { - // Keep unmatched '>' (stfl way of encoding a literal '>') - pos = tag_start + 1; - continue; - } - auto tag_end = str.find_first_of("<>", tag_start + 1); - if (tag_end == std::string::npos) { - break; - } - if (str[tag_end] == '<') { - // First '<' bracket is unmatched, ignoring it - pos = tag_start + 1; - continue; - } - if (tag_end - tag_start == 1) { - // Convert "<>" into "<" (stfl way of encoding a literal '<') - str.erase(tag_end, 1); - pos = tag_start + 1; - continue; - } - tags[tag_start] = str.substr(tag_start, tag_end - tag_start + 1); - str.erase(tag_start, tag_end - tag_start + 1); - pos = tag_start; - } - return tags; -} - -void RegexManager::insert_style_tags(std::string& str, - std::map<size_t, std::string>& tags) -{ - // Expand "<" into "<>" (reverse of what happened in extract_style_tags() - size_t pos = 0; - while (pos < str.size()) { - auto bracket = str.find_first_of("<", pos); - if (bracket == std::string::npos) { - break; - } - pos = bracket + 1; - // Add to strings in the `tags` map so we don't have to shift all the positions in th |