mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
Added <prefix> and <suffix> tags;
Added prefix and suffix support to combined_editor; 'always symbol' now checks if the symbols are available in the symbol font; Fixed parser bug in spec_sort; A first information field is no longer used as set identification git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@653 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+7
-5
@@ -13,6 +13,7 @@
|
||||
#include <data/keyword.hpp>
|
||||
#include <data/field.hpp>
|
||||
#include <data/field/text.hpp> // for 0.2.7 fix
|
||||
#include <data/field/information.hpp>
|
||||
#include <util/tagged_string.hpp> // for 0.2.7 fix
|
||||
#include <util/order_cache.hpp>
|
||||
#include <script/script_manager.hpp>
|
||||
@@ -106,12 +107,13 @@ String Set::identification() const {
|
||||
return v->toString();
|
||||
}
|
||||
}
|
||||
// otherwise the first field
|
||||
if (!data.empty()) {
|
||||
return data.at(0)->toString();
|
||||
} else {
|
||||
return wxEmptyString;
|
||||
// otherwise the first non-information field
|
||||
FOR_EACH_CONST(v, data) {
|
||||
if (!dynamic_pointer_cast<InfoValue>(v)) {
|
||||
return v->toString();
|
||||
}
|
||||
}
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -215,6 +215,46 @@ next_symbol:;
|
||||
}
|
||||
}
|
||||
|
||||
size_t SymbolFont::recognizePrefix(const String& text, size_t start) const {
|
||||
size_t pos;
|
||||
for (pos = start ; pos < text.size() ; ) {
|
||||
// 1. check merged numbers
|
||||
if (merge_numbers && pos + 1 < text.size()) {
|
||||
size_t num_count = text.find_first_not_of(_("0123456789"), pos) - pos;
|
||||
if (num_count >= 2) {
|
||||
pos += num_count;
|
||||
goto next_symbol;
|
||||
}
|
||||
}
|
||||
// 2. check symbol list
|
||||
FOR_EACH_CONST(sym, symbols) {
|
||||
if (!sym->code.empty() && sym->enabled && is_substr(text, pos, sym->code)) { // symbol matches
|
||||
pos += sym->code.size();
|
||||
goto next_symbol; // continue two levels
|
||||
}
|
||||
}
|
||||
// 3. draw multiple together as text?
|
||||
if (!as_text.empty()) {
|
||||
if (!as_text_r.IsValid()) {
|
||||
as_text_r.Compile(_("^") + as_text, wxRE_ADVANCED);
|
||||
}
|
||||
if (as_text_r.IsValid()) {
|
||||
if (as_text_r.Matches(text.substr(pos))) {
|
||||
size_t start, len;
|
||||
if (as_text_r.GetMatch(&start,&len) && start == 0) {
|
||||
pos += len;
|
||||
goto next_symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 4. failed
|
||||
break;
|
||||
next_symbol:;
|
||||
}
|
||||
return pos - start;
|
||||
}
|
||||
|
||||
SymbolInFont* SymbolFont::defaultSymbol() const {
|
||||
FOR_EACH_CONST(sym, symbols) {
|
||||
if (sym->code.empty() && sym->enabled) return sym.get();
|
||||
|
||||
@@ -47,10 +47,13 @@ class SymbolFont : public Packaged {
|
||||
SymbolInFont* symbol; ///< Symbol to draw, if nullptr, use the default symbol and draw the text
|
||||
};
|
||||
typedef vector<DrawableSymbol> SplitSymbols;
|
||||
|
||||
|
||||
/// Split a string into separate symbols for drawing and for determining their size
|
||||
void split(const String& text, SplitSymbols& out) const;
|
||||
|
||||
/// How many consecutive characters of the text, starting at start can be rendered with this symbol font?
|
||||
size_t recognizePrefix(const String& text, size_t start) const;
|
||||
|
||||
/// Draw a piece of text
|
||||
void draw(RotatedDC& dc, Context& ctx, const RealRect& rect, double font_size, const Alignment& align, const String& text);
|
||||
/// Get information on characters in a string
|
||||
|
||||
@@ -956,6 +956,7 @@ void TextValueEditor::replaceSelection(const String& replacement, const String&
|
||||
void TextValueEditor::tryAutoReplace() {
|
||||
size_t end = selection_start_i;
|
||||
GameSettings& gs = settings.gameSettingsFor(*getSet().game);
|
||||
if (!gs.use_auto_replace) return;
|
||||
FOR_EACH(ar, gs.auto_replaces) {
|
||||
if (ar->enabled && ar->match.size() <= end) {
|
||||
size_t start = end - ar->match.size();
|
||||
|
||||
+74
-47
@@ -75,6 +75,7 @@ struct TextElementsFromString {
|
||||
int soft, kwpph, param, line, soft_line;
|
||||
int code, code_kw, code_string, param_ref, error;
|
||||
int param_id;
|
||||
/// put angle brackets around the text?
|
||||
bool bracket;
|
||||
|
||||
TextElementsFromString()
|
||||
@@ -86,10 +87,15 @@ struct TextElementsFromString {
|
||||
void fromString(TextElements& te, const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx) {
|
||||
te.elements.clear();
|
||||
end = min(end, text.size());
|
||||
size_t text_start = start;
|
||||
// for each character...
|
||||
for (size_t pos = start ; pos < end ; ) {
|
||||
Char c = text.GetChar(pos);
|
||||
if (c == _('<')) {
|
||||
if (text_start < pos) {
|
||||
// text element before this tag?
|
||||
addText(te, text, text_start, pos, style, ctx);
|
||||
}
|
||||
size_t tag_start = pos;
|
||||
pos = skip_tag(text, tag_start);
|
||||
if (is_substr(text, tag_start, _( "<b"))) bold += 1;
|
||||
@@ -132,69 +138,90 @@ struct TextElementsFromString {
|
||||
else if (is_substr(text, tag_start, _("<atom"))) {
|
||||
// 'atomic' indicator
|
||||
size_t end_tag = min(end, match_close_tag(text, tag_start));
|
||||
intrusive_ptr<AtomTextElement> e(new AtomTextElement(text, pos, end_tag));
|
||||
intrusive_ptr<AtomTextElement> e(new AtomTextElement(pos, end_tag));
|
||||
fromString(e->elements, text, pos, end_tag, style, ctx);
|
||||
te.elements.push_back(e);
|
||||
pos = skip_tag(text, end_tag);
|
||||
} else if (is_substr(text, tag_start, _( "<error"))) {
|
||||
// error indicator
|
||||
size_t end_tag = min(end, match_close_tag(text, tag_start));
|
||||
intrusive_ptr<ErrorTextElement> e(new ErrorTextElement(text, pos, end_tag));
|
||||
intrusive_ptr<ErrorTextElement> e(new ErrorTextElement(pos, end_tag));
|
||||
fromString(e->elements, text, pos, end_tag, style, ctx);
|
||||
te.elements.push_back(e);
|
||||
pos = skip_tag(text, end_tag);
|
||||
} else {
|
||||
// ignore other tags
|
||||
}
|
||||
text_start = pos;
|
||||
} else {
|
||||
c = untag_char(c); // unescape
|
||||
// A character of normal text, add to the last text element (if possible)
|
||||
SimpleTextElement* e = nullptr;
|
||||
if (!te.elements.empty()) e = dynamic_cast<SimpleTextElement*>(te.elements.back().get());
|
||||
if (e && e->end == (bracket ? pos + 1 : pos)) {
|
||||
e->end = bracket ? pos + 2 : pos + 1; // just move the end, no need to make a new element
|
||||
e->content += c;
|
||||
if (bracket) {
|
||||
// content is "<somethin>g" should be "<something>"
|
||||
swap(e->content[e->content.size() - 2], e->content[e->content.size() - 1]);
|
||||
}
|
||||
} else {
|
||||
// add a new element for this text
|
||||
if (symbol > 0 && style.symbol_font.valid()) {
|
||||
e = new SymbolTextElement(text, pos, pos + 1, style.symbol_font, &ctx);
|
||||
bracket = false;
|
||||
} else {
|
||||
FontP font = style.font.make(
|
||||
(bold > 0 ? FONT_BOLD : FONT_NORMAL) |
|
||||
(italic > 0 ? FONT_ITALIC : FONT_NORMAL) |
|
||||
(soft > 0 ? FONT_SOFT : FONT_NORMAL) |
|
||||
(kwpph > 0 ? FONT_SOFT : FONT_NORMAL) |
|
||||
(code > 0 ? FONT_CODE : FONT_NORMAL) |
|
||||
(code_kw > 0 ? FONT_CODE_KW : FONT_NORMAL) |
|
||||
(code_string > 0 ? FONT_CODE_STRING : FONT_NORMAL),
|
||||
param > 0 || param_ref > 0
|
||||
? ¶m_colors[(param_id++) % param_colors_count]
|
||||
: nullptr);
|
||||
bracket = kwpph > 0 || param > 0;
|
||||
e = new FontTextElement(
|
||||
text,
|
||||
bracket ? pos - 1 : pos,
|
||||
bracket ? pos + 2 : pos + 1,
|
||||
font,
|
||||
soft > 0 ? DRAW_ACTIVE : DRAW_NORMAL,
|
||||
line > 0 ? BREAK_LINE :
|
||||
soft_line > 0 ? BREAK_SOFT : BREAK_HARD);
|
||||
}
|
||||
if (bracket) {
|
||||
e->content = String(LEFT_ANGLE_BRACKET) + c + RIGHT_ANGLE_BRACKET;
|
||||
} else {
|
||||
e->content = c;
|
||||
}
|
||||
te.elements.push_back(TextElementP(e));
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
}
|
||||
if (text_start < end) {
|
||||
addText(te, text, text_start, end, style, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/// Create a text element for a piece of text
|
||||
void addText(TextElements& te, const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx) {
|
||||
String content = untag(text.substr(start, end - start));
|
||||
assert(content.size() == end-start);
|
||||
// use symbol font?
|
||||
if (symbol > 0 && style.symbol_font.valid()) {
|
||||
te.elements.push_back(new_intrusive5<SymbolTextElement>(content, start, end, style.symbol_font, &ctx));
|
||||
} else {
|
||||
// text, possibly mixed with symbols
|
||||
DrawWhat what = soft > 0 ? DRAW_ACTIVE : DRAW_NORMAL;
|
||||
LineBreak line_break = line > 0 ? BREAK_LINE :
|
||||
soft_line > 0 ? BREAK_SOFT : BREAK_HARD;
|
||||
if (kwpph > 0 || param > 0) {
|
||||
// bracket the text
|
||||
content = String(LEFT_ANGLE_BRACKET) + content + RIGHT_ANGLE_BRACKET;
|
||||
start -= 1;
|
||||
end += 1;
|
||||
}
|
||||
if (style.always_symbol && style.symbol_font.valid()) {
|
||||
// mixed symbols/text, autodetected by symbol font
|
||||
size_t text_pos = 0;
|
||||
size_t pos = 0;
|
||||
FontP font;
|
||||
while (pos < end-start) {
|
||||
if (size_t n = style.symbol_font.font->recognizePrefix(content,pos)) {
|
||||
// at 'pos' there are n symbol font characters
|
||||
if (text_pos < pos) {
|
||||
// text before it?
|
||||
if (!font) font = makeFont(style);
|
||||
te.elements.push_back(new_intrusive6<FontTextElement>(content.substr(text_pos, pos-text_pos), start+text_pos, start+pos, font, what, line_break));
|
||||
}
|
||||
te.elements.push_back(new_intrusive5<SymbolTextElement>(content.substr(pos,n), start+pos, start+pos+n, style.symbol_font, &ctx));
|
||||
text_pos = pos += n;
|
||||
} else {
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
if (text_pos < pos) {
|
||||
if (!font) font = makeFont(style);
|
||||
te.elements.push_back(new_intrusive6<FontTextElement>(content.substr(text_pos), start+text_pos, end, font, what, line_break));
|
||||
}
|
||||
} else {
|
||||
te.elements.push_back(new_intrusive6<FontTextElement>(content, start, end, makeFont(style), what, line_break));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FontP makeFont(const TextStyle& style) {
|
||||
return style.font.make(
|
||||
(bold > 0 ? FONT_BOLD : FONT_NORMAL) |
|
||||
(italic > 0 ? FONT_ITALIC : FONT_NORMAL) |
|
||||
(soft > 0 ? FONT_SOFT : FONT_NORMAL) |
|
||||
(kwpph > 0 ? FONT_SOFT : FONT_NORMAL) |
|
||||
(code > 0 ? FONT_CODE : FONT_NORMAL) |
|
||||
(code_kw > 0 ? FONT_CODE_KW : FONT_NORMAL) |
|
||||
(code_string > 0 ? FONT_CODE_STRING : FONT_NORMAL),
|
||||
param > 0 || param_ref > 0
|
||||
? ¶m_colors[(param_id++) % param_colors_count]
|
||||
: nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+10
-25
@@ -57,12 +57,10 @@ struct CharInfo {
|
||||
/// A section of text that can be rendered using a TextViewer
|
||||
class TextElement : public IntrusivePtrBase<TextElement> {
|
||||
public:
|
||||
/// The text of which a subsection is drawn
|
||||
String text;
|
||||
/// What section of the input string is this element?
|
||||
size_t start, end;
|
||||
|
||||
inline TextElement(const String& text, size_t start ,size_t end) : text(text), start(start), end(end) {}
|
||||
inline TextElement(size_t start ,size_t end) : start(start), end(end) {}
|
||||
virtual ~TextElement() {}
|
||||
|
||||
/// Draw a subsection section of the text in the given rectangle
|
||||
@@ -109,8 +107,8 @@ class TextElements {
|
||||
/// A text element that just shows text
|
||||
class SimpleTextElement : public TextElement {
|
||||
public:
|
||||
SimpleTextElement(const String& text, size_t start, size_t end)
|
||||
: TextElement(text, start, end), content(text.substr(start,end-start))
|
||||
SimpleTextElement(const String& content, size_t start, size_t end)
|
||||
: TextElement(start, end), content(content)
|
||||
{}
|
||||
String content; ///< Text to show
|
||||
};
|
||||
@@ -118,8 +116,8 @@ class SimpleTextElement : public TextElement {
|
||||
/// A text element that uses a normal font
|
||||
class FontTextElement : public SimpleTextElement {
|
||||
public:
|
||||
FontTextElement(const String& text, size_t start, size_t end, const FontP& font, DrawWhat draw_as, LineBreak break_style)
|
||||
: SimpleTextElement(text, start, end)
|
||||
FontTextElement(const String& content, size_t start, size_t end, const FontP& font, DrawWhat draw_as, LineBreak break_style)
|
||||
: SimpleTextElement(content, start, end)
|
||||
, font(font), draw_as(draw_as), break_style(break_style)
|
||||
{}
|
||||
|
||||
@@ -136,8 +134,8 @@ class FontTextElement : public SimpleTextElement {
|
||||
/// A text element that uses a symbol font
|
||||
class SymbolTextElement : public SimpleTextElement {
|
||||
public:
|
||||
SymbolTextElement(const String& text, size_t start, size_t end, const SymbolFontRef& font, Context* ctx)
|
||||
: SimpleTextElement(text, start, end)
|
||||
SymbolTextElement(const String& content, size_t start, size_t end, const SymbolFontRef& font, Context* ctx)
|
||||
: SimpleTextElement(content, start, end)
|
||||
, font(font), ctx(*ctx)
|
||||
{}
|
||||
|
||||
@@ -155,7 +153,7 @@ class SymbolTextElement : public SimpleTextElement {
|
||||
/// A TextElement consisting of sub elements
|
||||
class CompoundTextElement : public TextElement {
|
||||
public:
|
||||
CompoundTextElement(const String& text, size_t start, size_t end) : TextElement(text, start, end) {}
|
||||
CompoundTextElement(size_t start, size_t end) : TextElement(start, end) {}
|
||||
|
||||
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
|
||||
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
|
||||
@@ -168,7 +166,7 @@ class CompoundTextElement : public TextElement {
|
||||
/// A TextElement drawn using a grey background
|
||||
class AtomTextElement : public CompoundTextElement {
|
||||
public:
|
||||
AtomTextElement(const String& text, size_t start, size_t end) : CompoundTextElement(text, start, end) {}
|
||||
AtomTextElement(size_t start, size_t end) : CompoundTextElement(start, end) {}
|
||||
|
||||
virtual void draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
|
||||
};
|
||||
@@ -176,23 +174,10 @@ class AtomTextElement : public CompoundTextElement {
|
||||
/// A TextElement drawn using a red wavy underline
|
||||
class ErrorTextElement : public CompoundTextElement {
|
||||
public:
|
||||
ErrorTextElement(const String& text, size_t start, size_t end) : CompoundTextElement(text, start, end) {}
|
||||
ErrorTextElement(size_t start, size_t end) : CompoundTextElement(start, end) {}
|
||||
|
||||
virtual void draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Other text elements
|
||||
/*
|
||||
/// A text element that displays a horizontal separator line
|
||||
class HorizontalLineTextElement : public TextElement {
|
||||
public:
|
||||
HorizontalLineTextElement(const String& text, size_t start ,size_t end) : TextElement(text, start, end) {}
|
||||
|
||||
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
|
||||
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
|
||||
virtual double minScale() const;
|
||||
};
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
|
||||
@@ -328,12 +328,7 @@ void TextViewer::setExactScrollPosition(double pos) {
|
||||
// ----------------------------------------------------------------------------- : Elements
|
||||
|
||||
void TextViewer::prepareElements(const String& text, const TextStyle& style, Context& ctx) {
|
||||
if (style.always_symbol) {
|
||||
elements.elements.clear();
|
||||
elements.elements.push_back(new_intrusive5<SymbolTextElement>(text, 0, text.size(), style.symbol_font, &ctx));
|
||||
} else {
|
||||
elements.fromString(text, 0, text.size(), style, ctx);
|
||||
}
|
||||
elements.fromString(text, 0, text.size(), style, ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -52,10 +52,21 @@ SCRIPT_FUNCTION_WITH_DEP(combined_editor) {
|
||||
if (separators.size() < values.size() - 1) {
|
||||
throw ScriptError(String::Format(_("Not enough separators for combine_editor, expected %d"), values.size()-1));
|
||||
}
|
||||
// split the value
|
||||
// the value
|
||||
SCRIPT_PARAM(String, value);
|
||||
// remove suffix/prefix
|
||||
SCRIPT_OPTIONAL_PARAM_(String, prefix);
|
||||
SCRIPT_OPTIONAL_PARAM_(String, suffix);
|
||||
if (is_substr(value,0,_("<prefix"))) {
|
||||
value = value.substr(min(value.size(), match_close_tag_end(value, 0)));
|
||||
}
|
||||
size_t pos = value.rfind(_("<suffix"));
|
||||
if (pos != String::npos && match_close_tag_end(value,pos) >= value.size()) {
|
||||
value = value.substr(0, pos);
|
||||
}
|
||||
// split the value
|
||||
vector<pair<String,bool> > value_parts; // (value part, is empty)
|
||||
size_t pos = value.find(_("<sep"));
|
||||
pos = value.find(_("<sep"));
|
||||
while (pos != String::npos) {
|
||||
String part = value.substr(0, pos);
|
||||
value_parts.push_back(make_pair(part, false));
|
||||
@@ -81,18 +92,48 @@ SCRIPT_FUNCTION_WITH_DEP(combined_editor) {
|
||||
// recombine the parts
|
||||
String new_value = value_parts.front().first;
|
||||
bool new_value_empty = value_parts.front().second;
|
||||
size_t size_before_last = 0;
|
||||
for (size_t i = 1 ; i < value_parts.size() ; ++i) {
|
||||
size_before_last = new_value.size();
|
||||
if (value_parts[i].second && new_value_empty && hide_when_empty) {
|
||||
// no separator
|
||||
} else if (value_parts[i].second && soft_before_empty) {
|
||||
// soft separator
|
||||
new_value += _("<sep-soft>") + separators[i - 1] + _("</sep-soft>");
|
||||
new_value_empty = false;
|
||||
} else {
|
||||
// normal separator
|
||||
new_value += _("<sep>") + separators[i - 1] + _("</sep>");
|
||||
new_value_empty = false;
|
||||
}
|
||||
new_value += value_parts[i].first;
|
||||
}
|
||||
if (!new_value_empty || !hide_when_empty) {
|
||||
if (!suffix.empty()) {
|
||||
if (is_substr(new_value, size_before_last, _("<sep-soft>")) && value_parts.size() >= 2) {
|
||||
// If the value ends in a soft separator, we have this situation:
|
||||
// [blah]<sep-soft>ABC</sep-soft><suffix>XYZ</suffix>
|
||||
// This renderes as:
|
||||
// [blah] XYZ
|
||||
// Which looks bad, so instead change the text to
|
||||
// [blah]<sep>XYZ<soft>ABC</soft></sep>
|
||||
// Which might be slightly incorrect, but soft text doesn't matter anyway.
|
||||
size_t after = min(new_value.size(), match_close_tag_end(new_value, size_before_last));
|
||||
new_value = new_value.substr(0, size_before_last)
|
||||
+ _("<sep>")
|
||||
+ suffix
|
||||
+ _("<soft>")
|
||||
+ separators[value_parts.size() - 2]
|
||||
+ _("</soft></sep>")
|
||||
+ new_value.substr(after);
|
||||
} else {
|
||||
new_value += _("<suffix>") + suffix + _("</suffix>");
|
||||
}
|
||||
}
|
||||
if (!prefix.empty()) {
|
||||
new_value = _("<prefix>") + prefix + _("</prefix>") + new_value;
|
||||
}
|
||||
}
|
||||
SCRIPT_RETURN(new_value);
|
||||
}
|
||||
|
||||
|
||||
@@ -239,7 +239,14 @@ void in_place_sort(const String& spec, String& input, String& ret) {
|
||||
String spec_sort(const String& spec, String& input, String& ret) {
|
||||
SpecIterator it(spec);
|
||||
while(it.nextUntil(0)) {
|
||||
if (it.value == _('<')) { // keep only a single copy
|
||||
if (it.escaped) { // single character, escaped
|
||||
FOR_EACH(d, input) {
|
||||
if (d == it.value) {
|
||||
ret += d;
|
||||
d = REMOVED;
|
||||
}
|
||||
}
|
||||
} else if (it.value == _('<')) { // keep only a single copy
|
||||
while (it.nextUntil(_('>'))) {
|
||||
size_t pos = input.find_first_of(it.value);
|
||||
if (pos != String::npos) {
|
||||
|
||||
@@ -249,6 +249,13 @@ size_t index_to_cursor(const String& str, size_t index, Movement dir) {
|
||||
}
|
||||
}
|
||||
i = after;
|
||||
} else if (i == 0 && is_substr(str, i, _("<prefix"))) {
|
||||
// prefix at start of string, skip contents
|
||||
i = match_close_tag_end(str, i);
|
||||
has_width = false;
|
||||
} else if (is_substr(str, i, _("<suffix")) && match_close_tag_end(str,i) >= str.size()) {
|
||||
// suffix at end of string
|
||||
break;
|
||||
} else {
|
||||
i = skip_tag(str, i);
|
||||
has_width = false;
|
||||
@@ -268,7 +275,8 @@ void cursor_to_index_range(const String& str, size_t cursor, size_t& start, size
|
||||
start = end = 0;
|
||||
size_t cur = 0;
|
||||
size_t i = 0;
|
||||
while (cur <= cursor && i < str.size()) {
|
||||
size_t size = str.size(); // can be changed by <suffix> tags
|
||||
while (cur <= cursor && i < size) {
|
||||
Char c = str.GetChar(i);
|
||||
bool has_width = true;
|
||||
if (c == _('<')) {
|
||||
@@ -278,6 +286,14 @@ void cursor_to_index_range(const String& str, size_t cursor, size_t& start, size
|
||||
if (cur >= cursor) { ++i; break; }
|
||||
// skip tag contents, tag counts as a single 'character'
|
||||
i = match_close_tag_end(str, i);
|
||||
} else if (i == 0 && is_substr(str, i, _("<prefix"))) {
|
||||
// prefix at start of string, skip contents, index never before
|
||||
start = i = match_close_tag_end(str,i);
|
||||
has_width = false;
|
||||
} else if (is_substr(str, i, _("<suffix")) && match_close_tag_end(str,i) >= str.size()) {
|
||||
// suffix at start of string, skip contents
|
||||
size = i;
|
||||
has_width = false;
|
||||
} else {
|
||||
i = skip_tag(str, i);
|
||||
has_width = false;
|
||||
@@ -290,8 +306,8 @@ void cursor_to_index_range(const String& str, size_t cursor, size_t& start, size
|
||||
if (cur == cursor) start = i;
|
||||
}
|
||||
}
|
||||
end = min(i, str.size());
|
||||
if (cur < cursor) start = end = str.size();
|
||||
end = min(i, size);
|
||||
if (cur < cursor) start = end = size;
|
||||
if (end <= start) end = start + 1;
|
||||
}
|
||||
|
||||
@@ -336,6 +352,12 @@ String untag_for_cursor(const String& str) {
|
||||
} else if (is_substr(str, i, _("<sep"))) {
|
||||
i = match_close_tag_end(str, i);
|
||||
ret += _('\3'); // use a random character here
|
||||
} else if (i == 0 && is_substr(str, i, _("<prefix"))) {
|
||||
// prefix at start of string, skip contents, index never before
|
||||
i = match_close_tag_end(str,i);
|
||||
} else if (is_substr(str, i, _("<suffix")) && match_close_tag_end(str,i) >= str.size()) {
|
||||
// suffix at start of string, skip contents
|
||||
i = str.size();
|
||||
} else {
|
||||
i = skip_tag(str, i);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user