Commit e023ad98 authored by twanvl's avatar twanvl

more script functions and text editor improvements

parent be2222ca
...@@ -12,7 +12,8 @@ ...@@ -12,7 +12,8 @@
#include <data/card.hpp> #include <data/card.hpp>
#include <data/keyword.hpp> #include <data/keyword.hpp>
#include <data/field.hpp> #include <data/field.hpp>
#include <data/field/text.hpp> // for 0.2.7 fix #include <data/field/text.hpp> // for 0.2.7 fix
#include <util/tagged_string.hpp> // for 0.2.7 fix
#include <script/value.hpp> #include <script/value.hpp>
#include <script/script_manager.hpp> #include <script/script_manager.hpp>
#include <wx/sstream.h> #include <wx/sstream.h>
...@@ -62,9 +63,9 @@ String Set::typeName() const { return _("set"); } ...@@ -62,9 +63,9 @@ String Set::typeName() const { return _("set"); }
void fix_value_207(const ValueP& value) { void fix_value_207(const ValueP& value) {
if (TextValue* v = dynamic_cast<TextValue*>(value.get())) { if (TextValue* v = dynamic_cast<TextValue*>(value.get())) {
// text value -> fix it // text value -> fix it
// v->value.assign( // don't change defaultness v->value.assignDontChangeDefault( // don't change defaultness
// fix_old_tags(v->value); // remove tags fix_old_tags(v->value()) // remove tags
// ); );
} }
} }
......
...@@ -213,6 +213,11 @@ void TextValueEditor::onMenu(wxCommandEvent& ev) { ...@@ -213,6 +213,11 @@ void TextValueEditor::onMenu(wxCommandEvent& ev) {
// ----------------------------------------------------------------------------- : Other overrides // ----------------------------------------------------------------------------- : Other overrides
void TextValueEditor::draw(RotatedDC& dc) {
TextValueViewer::draw(dc);
v.drawSelection(dc, style(), selection_start, selection_end);
}
wxCursor rotated_ibeam; wxCursor rotated_ibeam;
wxCursor TextValueEditor::cursor() const { wxCursor TextValueEditor::cursor() const {
...@@ -237,6 +242,8 @@ void TextValueEditor::onAction(const ValueAction& action, bool undone) { ...@@ -237,6 +242,8 @@ void TextValueEditor::onAction(const ValueAction& action, bool undone) {
TYPE_CASE(action, TextValueAction) { TYPE_CASE(action, TextValueAction) {
selection_start = action.selection_start; selection_start = action.selection_start;
selection_end = action.selection_end; selection_end = action.selection_end;
fixSelection();
if (isCurrent()) showCaret();
} }
} }
...@@ -471,7 +478,7 @@ void TextValueEditor::moveSelection(size_t new_end, bool also_move_start, Moveme ...@@ -471,7 +478,7 @@ void TextValueEditor::moveSelection(size_t new_end, bool also_move_start, Moveme
void TextValueEditor::moveSelectionNoRedraw(size_t new_end, bool also_move_start, Movement dir) { void TextValueEditor::moveSelectionNoRedraw(size_t new_end, bool also_move_start, Movement dir) {
selection_end = new_end; selection_end = new_end;
if (also_move_start) selection_start = selection_end; if (also_move_start) selection_start = selection_end;
fixSelection(dir); fixSelection(dir);
} }
...@@ -479,7 +486,7 @@ void TextValueEditor::fixSelection(Movement dir) { ...@@ -479,7 +486,7 @@ void TextValueEditor::fixSelection(Movement dir) {
const String& val = value().value(); const String& val = value().value();
// value may have become smaller because of undo/redo // value may have become smaller because of undo/redo
// make sure the selection stays inside the text // make sure the selection stays inside the text
size_t size; size_t size = val.size();
selection_end = min(size, selection_end); selection_end = min(size, selection_end);
selection_start = min(size, selection_start); selection_start = min(size, selection_start);
// start and end must be on the same side of separators // start and end must be on the same side of separators
...@@ -513,6 +520,8 @@ void TextValueEditor::fixSelection(Movement dir) { ...@@ -513,6 +520,8 @@ void TextValueEditor::fixSelection(Movement dir) {
atompos = val.find(_("<atom"), atompos + 1); atompos = val.find(_("<atom"), atompos + 1);
} }
// start and end must not be inside or between tags // start and end must not be inside or between tags
selection_start = v.firstVisibleChar(selection_start, dir == MOVE_LEFT ? -1 : +1);
selection_end = v.firstVisibleChar(selection_end, dir == MOVE_LEFT ? -1 : +1);
// TODO // TODO
} }
...@@ -521,7 +530,7 @@ size_t TextValueEditor::prevCharBoundry(size_t pos) const { ...@@ -521,7 +530,7 @@ size_t TextValueEditor::prevCharBoundry(size_t pos) const {
return max(0, (int)pos - 1); return max(0, (int)pos - 1);
} }
size_t TextValueEditor::nextCharBoundry(size_t pos) const { size_t TextValueEditor::nextCharBoundry(size_t pos) const {
return max(value().value().size(), pos + 1); return min(value().value().size(), pos + 1);
} }
size_t TextValueEditor::prevWordBoundry(size_t pos) const { size_t TextValueEditor::prevWordBoundry(size_t pos) const {
const String& val = value().value(); const String& val = value().value();
......
...@@ -79,6 +79,7 @@ class TextValueEditor : public TextValueViewer, public ValueEditor { ...@@ -79,6 +79,7 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
virtual wxCursor cursor() const; virtual wxCursor cursor() const;
virtual void determineSize(); virtual void determineSize();
virtual void onShow(bool); virtual void onShow(bool);
virtual void draw(RotatedDC&);
// --------------------------------------------------- : Data // --------------------------------------------------- : Data
private: private:
......
...@@ -82,7 +82,7 @@ void TextViewer::draw(RotatedDC& dc, const String& text, const TextStyle& style, ...@@ -82,7 +82,7 @@ void TextViewer::draw(RotatedDC& dc, const String& text, const TextStyle& style,
void TextViewer::drawSelection(RotatedDC& dc, const TextStyle& style, size_t sel_start, size_t sel_end) { void TextViewer::drawSelection(RotatedDC& dc, const TextStyle& style, size_t sel_start, size_t sel_end) {
Rotater r(dc, style.getRotation()); Rotater r(dc, style.getRotation());
if (sel_start == sel_end) return; if (sel_start == sel_end) return;
if (sel_end < sel_start) swap(sel_start, sel_end); if (sel_end < sel_start) swap(sel_start, sel_end);
dc.SetBrush(*wxBLACK_BRUSH); dc.SetBrush(*wxBLACK_BRUSH);
dc.SetPen(*wxTRANSPARENT_PEN); dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetLogicalFunction(wxINVERT); dc.SetLogicalFunction(wxINVERT);
...@@ -96,7 +96,7 @@ void TextViewer::Line::drawSelection(RotatedDC& dc, size_t sel_start, size_t sel ...@@ -96,7 +96,7 @@ void TextViewer::Line::drawSelection(RotatedDC& dc, size_t sel_start, size_t sel
if (!visible(dc)) return; if (!visible(dc)) return;
if (sel_start < end() && sel_end > start) { if (sel_start < end() && sel_end > start) {
double x1 = positions[sel_start]; double x1 = positions[sel_start];
double x2 = positions[max(end(), sel_end)]; double x2 = positions[min(end(), sel_end)];
dc.DrawRectangle(RealRect(x1, top, x2 - x1, line_height)); dc.DrawRectangle(RealRect(x1, top, x2 - x1, line_height));
} }
} }
...@@ -116,6 +116,7 @@ const TextViewer::Line& TextViewer::findLine(size_t index) const { ...@@ -116,6 +116,7 @@ const TextViewer::Line& TextViewer::findLine(size_t index) const {
} }
size_t TextViewer::moveLine(size_t index, int delta) const { size_t TextViewer::moveLine(size_t index, int delta) const {
if (lines.empty()) return index;
const Line* line1 = &findLine(index); const Line* line1 = &findLine(index);
const Line* line2 = line1 + delta; const Line* line2 = line1 + delta;
if (line2 >= &lines.front() && line2 <= &lines.back()) { if (line2 >= &lines.front() && line2 <= &lines.back()) {
...@@ -151,6 +152,7 @@ size_t TextViewer::indexAt(const RealPoint& pos) const { ...@@ -151,6 +152,7 @@ size_t TextViewer::indexAt(const RealPoint& pos) const {
} }
RealRect TextViewer::charRect(size_t index) const { RealRect TextViewer::charRect(size_t index) const {
if (lines.empty()) return RealRect(0,0,0,0);
const Line& l = findLine(index); const Line& l = findLine(index);
size_t pos = index - l.start; size_t pos = index - l.start;
if (pos >= l.positions.size()) { if (pos >= l.positions.size()) {
...@@ -160,9 +162,32 @@ RealRect TextViewer::charRect(size_t index) const { ...@@ -160,9 +162,32 @@ RealRect TextViewer::charRect(size_t index) const {
} }
} }
bool TextViewer::isVisible(size_t index) const {
if (lines.empty()) return false;
const Line& l = findLine(index);
size_t pos = index - l.start;
if (pos >= l.positions.size()) {
return false;
} else if (pos + 1 == l.positions.size()) {
return true; // last char of the line
} else {
return l.positions[pos + 1] - l.positions[pos] > 0.0001;
}
}
size_t TextViewer::firstVisibleChar(size_t index, int delta) const {
if (lines.empty()) return index;
const Line& l = findLine(index);
int pos = (int)(index - l.start);
while (pos + delta > 0 && (size_t)pos + delta + 1 < l.positions.size()) {
if (l.positions[pos + 1] - l.positions[pos] > 0.0001) break;
pos += delta;
}
return pos + l.start;
}
double TextViewer::heightOfLastLine() const { double TextViewer::heightOfLastLine() const {
if (lines.empty()) return 0; if (lines.empty()) return 0;
else return lines.back().line_height; return lines.back().line_height;
} }
// ----------------------------------------------------------------------------- : Elements // ----------------------------------------------------------------------------- : Elements
......
...@@ -56,8 +56,6 @@ class TextViewer { ...@@ -56,8 +56,6 @@ class TextViewer {
// --------------------------------------------------- : Positions // --------------------------------------------------- : Positions
/// Find the character index that is before/after the given index, and which has a nonzero width
// size_t moveChar(size_t index, int delta) const;
/// Find the character index that is on a line above/below index /// Find the character index that is on a line above/below index
/** If this would move outisde the text, returns the input index */ /** If this would move outisde the text, returns the input index */
size_t moveLine(size_t index, int delta) const; size_t moveLine(size_t index, int delta) const;
...@@ -78,6 +76,10 @@ class TextViewer { ...@@ -78,6 +76,10 @@ class TextViewer {
/// Return the rectangle around a single character /// Return the rectangle around a single character
RealRect charRect(size_t index) const; RealRect charRect(size_t index) const;
/// Is the character at the given index visible?
bool isVisible(size_t index) const;
/// Find the first character index that is at/before/after the given index, and which has a nonzero width
size_t firstVisibleChar(size_t index, int delta) const;
/// Return the height of the last line /// Return the height of the last line
double heightOfLastLine() const; double heightOfLastLine() const;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <script/value.hpp> #include <script/value.hpp>
#include <script/context.hpp> #include <script/context.hpp>
#include <util/tagged_string.hpp>
#include <wx/regex.h> #include <wx/regex.h>
DECLARE_TYPEOF_COLLECTION(UInt); DECLARE_TYPEOF_COLLECTION(UInt);
...@@ -56,6 +57,7 @@ class ScriptReplaceRule : public ScriptValue { ...@@ -56,6 +57,7 @@ class ScriptReplaceRule : public ScriptValue {
ret += inside; ret += inside;
input = next_input; input = next_input;
} }
ret += input;
SCRIPT_RETURN(ret); SCRIPT_RETURN(ret);
} else { } else {
// dumb replacing // dumb replacing
...@@ -79,7 +81,7 @@ SCRIPT_FUNCTION(replace_rule) { ...@@ -79,7 +81,7 @@ SCRIPT_FUNCTION(replace_rule) {
throw ScriptError(_("Error while compiling regular expression: '")+match+_("'")); throw ScriptError(_("Error while compiling regular expression: '")+match+_("'"));
} }
// replace // replace
ScriptValueP replace = ctx.getVariable(_("replace")); SCRIPT_PARAM(ScriptValueP, replace);
if (replace->type() == SCRIPT_FUNCTION) { if (replace->type() == SCRIPT_FUNCTION) {
ret->replacement_function = replace; ret->replacement_function = replace;
} else { } else {
...@@ -234,25 +236,57 @@ String spec_sort(const String& spec, const String& input) { ...@@ -234,25 +236,57 @@ String spec_sort(const String& spec, const String& input) {
} }
class ScriptSortRule : public ScriptValue { // Utility for defining a script rule with a single parameter
public: #define SCRIPT_RULE_1(funname, type1, name1) \
ScriptSortRule(const String& order) : order(order) {} class ScriptRule_##funname: public ScriptValue { \
public: \
virtual ScriptType type() const { return SCRIPT_FUNCTION; } inline ScriptRule_##funname(const type1& name1) : name1(name1) {} \
virtual String typeName() const { return _("sort_rule"); } virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
virtual ScriptValueP eval(Context& ctx) const { virtual String typeName() const { return _(#funname)_("_rule"); } \
SCRIPT_PARAM(String, input); virtual ScriptValueP eval(Context& ctx) const; \
SCRIPT_RETURN(spec_sort(order, input)); private: \
} type1 name1; \
}; \
private: SCRIPT_FUNCTION(funname##_rule) { \
String order; SCRIPT_PARAM(type1, name1); \
}; return new_intrusive1<ScriptRule_##funname>(name1); \
} \
SCRIPT_FUNCTION(funname) { \
SCRIPT_PARAM(type1, name1); \
return ScriptRule_##funname(name1).eval(ctx); \
} \
ScriptValueP ScriptRule_##funname::eval(Context& ctx) const
// Utility for defining a script rule with two parameters
#define SCRIPT_RULE_2(funname, type1, name1, type2, name2) \
class ScriptRule_##funname: public ScriptValue { \
public: \
inline ScriptRule_##funname(const type1& name1, const type2& name2) \
: name1(name1), name2(name2) {} \
virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
virtual String typeName() const { return _(#funname)_("_rule"); } \
virtual ScriptValueP eval(Context& ctx) const; \
private: \
type1 name1; \
type2 name2; \
}; \
SCRIPT_FUNCTION(funname##_rule) { \
SCRIPT_PARAM(type1, name1); \
SCRIPT_PARAM(type2, name2); \
return new_intrusive2<ScriptRule_##funname>(name1, name2); \
} \
SCRIPT_FUNCTION(funname) { \
SCRIPT_PARAM(type1, name1); \
SCRIPT_PARAM(type2, name2); \
return ScriptRule_##funname(name1, name2).eval(ctx); \
} \
ScriptValueP ScriptRule_##funname::eval(Context& ctx) const
// Create a rule for spec_sorting strings // Create a rule for spec_sorting strings
SCRIPT_FUNCTION(sort_rule) { SCRIPT_RULE_1(sort, String, order) {
SCRIPT_PARAM(String, order); SCRIPT_PARAM(String, input);
return new_intrusive1<ScriptSortRule>(order); SCRIPT_RETURN(spec_sort(order, input));
} }
// ----------------------------------------------------------------------------- : String stuff // ----------------------------------------------------------------------------- : String stuff
...@@ -298,16 +332,55 @@ SCRIPT_FUNCTION(contains) { ...@@ -298,16 +332,55 @@ SCRIPT_FUNCTION(contains) {
SCRIPT_RETURN(input.find(match) != String::npos); SCRIPT_RETURN(input.find(match) != String::npos);
} }
// ----------------------------------------------------------------------------- : Tagged stuff
String replace_tag_contents(String input, const String& tag, const ScriptValueP& contents, Context& ctx) {
String ret;
size_t pos = input.find(tag);
while (pos != String::npos) {
// find end of tag and contents
size_t end = match_close_tag(input, pos);
if (end == String::npos) break; // missing close tag
// prepare for call
String old_contents = input.substr(pos + tag.size(), end - (pos + tag.size()));
ctx.setVariable(_("contents"), toScript(old_contents));
// replace
ret += input.substr(0, pos); // before tag
ret += tag;
ret += *contents->eval(ctx);// new contents (call)
ret += close_tag(tag);
// next
input = input.substr(skip_tag(input,end));
pos = input.find(tag);
}
return ret + input;
}
// Replace the contents of a specific tag
SCRIPT_RULE_2(tag_contents, String, tag, ScriptValueP, contents) {
SCRIPT_PARAM(String, input);
SCRIPT_RETURN(replace_tag_contents(input, tag, contents, ctx));
}
SCRIPT_RULE_1(tag_remove, String, tag) {
SCRIPT_PARAM(String, input);
SCRIPT_RETURN(remove_tag(input, tag));
}
// ----------------------------------------------------------------------------- : Vector stuff // ----------------------------------------------------------------------------- : Vector stuff
/// position of some element in a vector /// position of some element in a vector
/** 1 based index, 0 if not found */ /** 0 based index, -1 if not found */
int position_in_vector(const ScriptValueP& of, const ScriptValueP& in, const ScriptValueP& order_by) { int position_in_vector(const ScriptValueP& of, const ScriptValueP& in, const ScriptValueP& order_by) {
return 0;// TODO ScriptType of_t = of->type(), in_t = in->type();
if (of_t == SCRIPT_STRING || in_t == SCRIPT_STRING) {
return (int)((String)*of).find(*in); // (int)npos == -1
}
return -1; // TODO
} }
// finding positions // finding positions, also of substrings
SCRIPT_FUNCTION(position_of) { SCRIPT_FUNCTION(position_of) {
ScriptValueP of = ctx.getVariable(_("of")); ScriptValueP of = ctx.getVariable(_("of"));
ScriptValueP in = ctx.getVariable(_("in")); ScriptValueP in = ctx.getVariable(_("in"));
...@@ -323,15 +396,20 @@ SCRIPT_FUNCTION(number_of_items) { ...@@ -323,15 +396,20 @@ SCRIPT_FUNCTION(number_of_items) {
// ----------------------------------------------------------------------------- : Initialize functions // ----------------------------------------------------------------------------- : Initialize functions
void init_script_functions(Context& ctx) { void init_script_functions(Context& ctx) {
ctx.setVariable(_("replace rule"), script_replace_rule); ctx.setVariable(_("replace rule"), script_replace_rule);
ctx.setVariable(_("filter rule"), script_filter_rule); ctx.setVariable(_("filter rule"), script_filter_rule);
ctx.setVariable(_("sort rule"), script_sort_rule); ctx.setVariable(_("sort"), script_sort);
ctx.setVariable(_("to upper"), script_to_upper); ctx.setVariable(_("sort rule"), script_sort_rule);
ctx.setVariable(_("to lower"), script_to_lower); ctx.setVariable(_("to upper"), script_to_upper);
ctx.setVariable(_("to title"), script_to_title); ctx.setVariable(_("to lower"), script_to_lower);
ctx.setVariable(_("substring"), script_substring); ctx.setVariable(_("to title"), script_to_title);
ctx.setVariable(_("contains"), script_contains); ctx.setVariable(_("substring"), script_substring);
ctx.setVariable(_("position"), script_position_of); ctx.setVariable(_("contains"), script_contains);
ctx.setVariable(_("number of items"), script_number_of_items); ctx.setVariable(_("tag contents"), script_tag_contents);
ctx.setVariable(_("remove tag"), script_tag_remove);
ctx.setVariable(_("tag contents rule"), script_tag_contents_rule);
ctx.setVariable(_("tag remove rule"), script_tag_remove_rule);
ctx.setVariable(_("position"), script_position_of);
ctx.setVariable(_("number of items"), script_number_of_items);
} }
...@@ -329,7 +329,12 @@ inline ScriptValueP toScript(const shared_ptr<T>& v) { return new_intrusive1<Scr ...@@ -329,7 +329,12 @@ inline ScriptValueP toScript(const shared_ptr<T>& v) { return new_intrusive1<Scr
* Throws an error if the parameter is not found. * Throws an error if the parameter is not found.
*/ */
#define SCRIPT_PARAM(Type, name) \ #define SCRIPT_PARAM(Type, name) \
Type name = *ctx.getVariable(_(#name)) Type name = getParam<Type>(ctx.getVariable(_(#name)))
template <typename T>
inline T getParam (const ScriptValueP& value) { return *value; }
template <>
inline ScriptValueP getParam<ScriptValueP>(const ScriptValueP& value) { return value; }
/// Retrieve an optional parameter /// Retrieve an optional parameter
/** Usage: /** Usage:
......
...@@ -33,6 +33,10 @@ class Defaultable { ...@@ -33,6 +33,10 @@ class Defaultable {
assert(is_default); assert(is_default);
value = new_value; value = new_value;
} }
/// Assigning a value, don't change the defaultness
inline void assignDontChangeDefault(const T& new_value) {
value = new_value;
}
/// Get access to the value /// Get access to the value
inline const T& operator () () const { return value; } inline const T& operator () () const { return value; }
......
...@@ -82,6 +82,14 @@ String fix_old_tags(const String& str) { ...@@ -82,6 +82,14 @@ String fix_old_tags(const String& str) {
// ----------------------------------------------------------------------------- : Finding tags // ----------------------------------------------------------------------------- : Finding tags
size_t tag_start(const String& str, size_t pos) {
size_t start = str.find_last_of(_('<'), pos);
if (start == String::npos) return String::npos;
size_t end = skip_tag(str, start);
if (end <= pos) return String::npos;
return start;
}
size_t skip_tag(const String& str, size_t start) { size_t skip_tag(const String& str, size_t start) {
if (start >= str.size()) return String::npos; if (start >= str.size()) return String::npos;
size_t end = str.find_first_of(_('>'), start); size_t end = str.find_first_of(_('>'), start);
...@@ -152,6 +160,43 @@ String anti_tag(const String& tag) { ...@@ -152,6 +160,43 @@ String anti_tag(const String& tag) {
} }
// ----------------------------------------------------------------------------- : Global operations // ----------------------------------------------------------------------------- : Global operations
String remove_tag(const String& str, const String& tag) {
if (tag.size() < 1) return str;
String ctag = close_tag(tag);
return remove_tag_exact(remove_tag_exact(str, tag), ctag);
}
String remove_tag_exact(const String& str, const String& tag) {
String ret; ret.reserve(str.size());
size_t start = 0, pos = str.find(tag);
while (pos != String::npos) {
ret += str.substr(start, pos - start); // before
// next
start = skip_tag(str, pos);
if (start > str.size()) break;
pos = str.find(tag, start);
}
ret += str.substr(start);
return ret;
}
String remove_tag_contents(const String& str, const String& tag) {
String ret; ret.reserve(str.size());
size_t start = 0, pos = str.find(tag);
while (pos != String::npos) {
size_t end = match_close_tag(str, pos);
if (end == String::npos) return ret; // missing close tag
ret += str.substr(start, pos - start);
// next
start = skip_tag(str, end);
if (start > str.size()) break;
pos = str.find(tag, start);
}
ret += str.substr(start);
return ret;
}
// ----------------------------------------------------------------------------- : Updates // ----------------------------------------------------------------------------- : Updates
/// Return all open or close tags in the given range from a string /// Return all open or close tags in the given range from a string
......
...@@ -42,6 +42,14 @@ String fix_old_tags(const String&); ...@@ -42,6 +42,14 @@ String fix_old_tags(const String&);
// ----------------------------------------------------------------------------- : Finding tags // ----------------------------------------------------------------------------- : Finding tags
/// Returns the position of the tag the given position is in
/** Returns String::npos if pos is not in a tag.
* In a tag is:
* < t a g >
* n y y y y n
*/
size_t tag_start(const String& str, size_t pos);
/// Returns the position just beyond the tag starting at start /// Returns the position just beyond the tag starting at start
size_t skip_tag(const String& str, size_t start); size_t skip_tag(const String& str, size_t start);
...@@ -53,8 +61,10 @@ size_t match_close_tag(const String& str, size_t start); ...@@ -53,8 +61,10 @@ size_t match_close_tag(const String& str, size_t start);
/** If not found returns String::npos */ /** If not found returns String::npos */
size_t last_start_tag_before(const String& str, const String& tag, size_t start); size_t last_start_tag_before(const String& str, const String& tag, size_t start);
/// Is the given range entirely contained in a given tag? /// Is the given range entirely contained in a given tagged block?
/** If so: return the start position of that tag, otherwise returns String::npos */ /** If so: return the start position of that tag, otherwise returns String::npos
* A tagged block is everything between <tag>...</tag>
*/
size_t in_tag(const String& str, const String& tag, size_t start, size_t end); size_t in_tag(const String& str, const String& tag, size_t start, size_t end);
/// Return the tag at the given position (without the <>) /// Return the tag at the given position (without the <>)
...@@ -78,7 +88,7 @@ String anti_tag(const String& tag); ...@@ -78,7 +88,7 @@ String anti_tag(const String& tag);
*/ */
String remove_tag(const String& str, const String& tag); String remove_tag(const String& str, const String& tag);
/// Remove all instances of tags starting with tag /// Remove all instances of tags starting with tag, but not its close tag
String remove_tag_exact(const String& str, const String& tag); String remove_tag_exact(const String& str, const String& tag);
/// Remove all instances of a tag (including contents) from a string /// Remove all instances of a tag (including contents) from a string
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment