moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
xml_syntax_highlighter.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2022, Bielefeld University, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of Bielefeld University nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34
35/* Author: Robert Haschke */
36
38#include <assert.h>
39
40namespace moveit_setup
41{
42XmlSyntaxHighlighter::XmlSyntaxHighlighter(QTextDocument* parent) : QSyntaxHighlighter(parent)
43{
44}
45
46void XmlSyntaxHighlighter::addTag(const QString& tag, const QTextCharFormat& format, const QString& parent)
47{
48 const QString start_pattern("<%1.*?/?>");
49 Rule rule;
50 rule.start = QRegularExpression(start_pattern.arg(tag));
51 rule.end = QRegularExpression(QString("</%1>|<%1[^>]*?/>").arg(tag));
52 rule.format = format;
53 if (!parent.isEmpty())
54 {
55 QString parent_start = start_pattern.arg(parent);
56 rule.parent = std::find_if(rules_.begin(), rules_.end(), [&](const std::pair<int, Rule>& rule) {
57 return rule.second.start.pattern() == parent_start;
58 });
59 }
60 else
61 rule.parent = rules_.end();
62
63 rules_.insert(std::make_pair(rules_.size(), rule));
64}
65
66XmlSyntaxHighlighter::Rules::const_iterator
67XmlSyntaxHighlighter::highlight(Rules::const_iterator active, QStringRef text, int start, bool search_end, int& end)
68{
69 int offset = end; // when passed, end indicates the end of the opening expression
70 auto next = active; // return value: active rule at end of text
71
72 if (search_end) // find end of active rule
73 {
74 auto match = active->second.end.match(text);
75 // when returned, end indicates the end of the closing expression
76 end = match.hasMatch() ? match.capturedEnd() : text.size();
77 setFormat(start, end, active->second.format);
78 if (match.hasMatch())
79 {
80 text = text.left(match.capturedStart()); // drop text after (and including) closing expression
81 next = active->second.parent;
82 }
83 }
84 text = text.mid(offset); // skip opening expression
85 start += offset; // adjust start by skipped offset
86 if (text.isEmpty())
87 return next; // early return
88
89 // highlight remaining text using active's children's rules
90 for (auto it = rules_.begin(); it != rules_.end(); ++it)
91 {
92 const auto& rule = it->second;
93 if (rule.parent != active)
94 continue; // skip wrong rules
95
96 offset = 0; // (re)start at beginning of (clipped) text
97 while (true) // process all matches of rule
98 {
99 auto match = rule.start.match(text, offset);
100 if (!match.hasMatch())
101 break;
102
103 offset = match.capturedEnd() - match.capturedStart(); // mark end of opening expression in passed text
104 auto result = highlight(it, text.mid(match.capturedStart()), start + match.capturedStart(), true, offset);
105 // returned offset is w.r.t. beginning of _passed_ text: add passed start offset to yield offset w.r.t. text
106 offset += match.capturedStart();
107 if (result == it) // text is ending with this rule
108 {
109 assert(next == active || next == active->second.parent);
110 assert(offset == text.size()); // end should mark the end of the text
111 next = result; // remember return value: active rule at end of text
112 break;
113 }
114 }
115 }
116
117 return next;
118}
119
121{
122 Rules::const_iterator active = previousBlockState() < 0 ? rules_.end() : rules_.find(previousBlockState());
123 int unused = 0;
124 active = highlight(active, QStringRef(&text, 0, text.size()), 0, active != rules_.cend(), unused);
125 setCurrentBlockState(active != rules_.cend() ? active->first : -1);
126}
127
128} // namespace moveit_setup
void highlightBlock(const QString &text) override
void addTag(const QString &tag, const QTextCharFormat &format, const QString &parent=QString())
XmlSyntaxHighlighter(QTextDocument *parent=nullptr)