Extract some more find/replace logic to libaegisub

This commit is contained in:
Thomas Goyne 2015-07-27 08:59:35 -07:00
parent cad8c80aab
commit 74ac2ab1fe
3 changed files with 85 additions and 68 deletions

View File

@ -52,8 +52,24 @@ std::pair<size_t, size_t> find_range(std::string const& haystack, std::string co
return {match_start, match_start + needle.size()};
}
void parse_blocks(std::vector<std::pair<size_t, size_t>>& blocks, std::string const& str) {
blocks.clear();
size_t ovr_start = bad_pos;
size_t i = 0;
for (auto const& c : str) {
if (c == '{' && ovr_start == bad_pos)
ovr_start = i;
else if (c == '}' && ovr_start != bad_pos) {
blocks.emplace_back(ovr_start, i);
ovr_start = bad_pos;
}
++i;
}
}
} // anonymous namespace
namespace agi { namespace util {
std::string strftime(const char *fmt, const tm *tmptr) {
@ -129,12 +145,60 @@ std::pair<size_t, size_t> ifind(std::string const& haystack, std::string const&
return ret;
}
std::string tagless_find_helper::strip_tags(std::string const& str, size_t s) {
parse_blocks(blocks, str);
std::string out;
size_t last = s;
for (auto const& block : blocks) {
if (block.second < s) continue;
if (block.first > last)
out.append(str.begin() + last, str.begin() + block.first);
last = block.second + 1;
}
if (last < str.size())
out.append(str.begin() + last, str.end());
start = s;
return out;
}
void tagless_find_helper::map_range(size_t &s, size_t &e) {
s += start;
e += start;
// Shift the start and end of the match to be relative to the unstripped
// match
for (auto const& block : blocks) {
// Any blocks before start are irrelevant as they're included in `start`
if (block.second < s) continue;
// Skip over blocks at the very beginning of the match
// < should only happen if the cursor was within an override block
// when the user started a search
if (block.first <= s) {
size_t len = block.second - std::max(block.first, s) + 1;
s += len;
e += len;
continue;
}
assert(block.first > s);
// Blocks after the match are irrelevant
if (block.first >= e) break;
// Extend the match to include blocks within the match
// Note that blocks cannot be partially within the match
e += block.second - block.first + 1;
}
}
} // namespace util
#ifndef __APPLE__
namespace osx {
AppNapDisabler::AppNapDisabler(std::string reason) { }
AppNapDisabler::~AppNapDisabler() { }
}
#endif
}
} // namespace agi

View File

@ -15,11 +15,11 @@
#include <algorithm>
#include <boost/range/irange.hpp>
#include <string>
#include <vector>
struct tm;
namespace agi {
namespace util {
namespace agi { namespace util {
/// Clamp `b` to the range [`a`,`c`]
template<typename T>
static inline T mid(T a, T b, T c) {
@ -45,6 +45,20 @@ namespace agi {
/// based on the unfolded length.
std::pair<size_t, size_t> ifind(std::string const& haystack, std::string const& needle);
class tagless_find_helper {
std::vector<std::pair<size_t, size_t>> blocks;
size_t start = 0;
public:
/// Strip ASS override tags at or after `start` in `str`, and initialize
/// state for mapping ranges back to the input string
std::string strip_tags(std::string const& str, size_t start);
/// Convert a range in the string returned by `strip_tags()` to a range
/// int the string last passed to `strip_tags()`
void map_range(size_t& start, size_t& end);
};
/// Set the name of the calling thread in the Visual Studio debugger
/// @param name New name for the thread
void SetThreadName(const char *name);
@ -66,6 +80,4 @@ namespace agi {
auto range(Integer end) -> decltype(boost::irange<Integer>(0, end)) {
return boost::irange<Integer>(0, end);
}
} // namespace util
} // namespace agi
} } // namespace agi::util

View File

@ -73,76 +73,17 @@ public:
class skip_tags_accessor {
boost::flyweight<std::string> AssDialogueBase::*field;
std::vector<std::pair<size_t, size_t>> blocks;
size_t start = 0;
void parse_str(std::string const& str) {
blocks.clear();
size_t ovr_start = bad_pos;
size_t i = 0;
for (auto const& c : str) {
if (c == '{' && ovr_start == bad_pos)
ovr_start = i;
else if (c == '}' && ovr_start != bad_pos) {
blocks.emplace_back(ovr_start, i);
ovr_start = bad_pos;
}
++i;
}
}
agi::util::tagless_find_helper helper;
public:
skip_tags_accessor(SearchReplaceSettings::Field f) : field(get_dialogue_field(f)) { }
std::string get(const AssDialogue *d, size_t s) {
auto const& str = get_normalized(d, field);
parse_str(str);
std::string out;
size_t last = s;
for (auto const& block : blocks) {
if (block.second < s) continue;
if (block.first > last)
out.append(str.begin() + last, str.begin() + block.first);
last = block.second + 1;
}
if (last < str.size())
out.append(str.begin() + last, str.end());
start = s;
return out;
return helper.strip_tags(get_normalized(d, field), s);
}
MatchState make_match_state(size_t s, size_t e, boost::u32regex *r = nullptr) {
s += start;
e += start;
// Shift the start and end of the match to be relative to the unstripped
// match
for (auto const& block : blocks) {
// Any blocks before start are irrelevant as they're included in `start`
if (block.second < s) continue;
// Skip over blocks at the very beginning of the match
// < should only happen if the cursor was within an override block
// when the user started a search
if (block.first <= s) {
size_t len = block.second - std::max(block.first, s) + 1;
s += len;
e += len;
continue;
}
assert(block.first > s);
// Blocks after the match are irrelevant
if (block.first >= e) break;
// Extend the match to include blocks within the match
// Note that blocks cannot be partially within the match
e += block.second - block.first + 1;
}
helper.map_range(s, e);
return {r, s, e};
}
};