def _included_files(self, path): ''' Returns all included files in the given file. ''' result = [] with open(path, 'r') as f: data = f.read() reg = QRegExp("=[\s\t]*\".*\"") reg.setMinimal(True) pos = reg.indexIn(data) while pos != -1 and self._isrunning: try: pp = interpret_path(reg.cap(0).strip('"')) f = QFile(pp) ext = os.path.splitext(pp) if f.exists() and ext[1] in nm.settings().SEARCH_IN_EXT: result.append(pp) except Exception as exp: parsed_text = pp try: parsed_text = reg.cap(0).strip('"') except: pass self.warning_signal.emit("Error while parse '%s': %s" % (parsed_text, exp)) pos += reg.matchedLength() pos = reg.indexIn(data, pos) return result
def _included_files(self, path): ''' Returns all included files in the given file. ''' result = [] with open(path, 'r') as f: data = f.read() reg = QRegExp("=[\s\t]*\".*\"") reg.setMinimal(True) pos = reg.indexIn(data) while pos != -1 and self._isrunning: try: pp = interpret_path(reg.cap(0).strip('"')) f = QFile(pp) ext = os.path.splitext(pp) if f.exists() and ext[1] in nm.settings().SEARCH_IN_EXT: result.append(pp) except Exception as exp: parsed_text = pp try: parsed_text = reg.cap(0).strip('"') except: pass self.warning_signal.emit("Error while parse '%s': %s" % (parsed_text, exp)) pos += reg.matchedLength() pos = reg.indexIn(data, pos) return result
def included_files(cls, text_or_path, regexp_retruns=[], regexp_filelist=[QRegExp("\\btextfile\\b"), QRegExp("\\bfile\\b"), QRegExp("\\bdefault\\b"), QRegExp("\\bvalue=.*pkg:\/\/\\b"), QRegExp("\\bvalue=.*package:\/\/\\b"), QRegExp("\\bvalue=.*\$\(find\\b"), QRegExp("\\bargs=.*\$\(find\\b")], recursive=True, unique=True): ''' :param regexp_retruns: the list with patterns which are returned as result. If empy it's the same as 'regexp_filelist' :param regexp_filelist: the list with all patterns to find include files ''' result = [] lines = [] pwd = '.' f = QFile(text_or_path) if f.exists(): pwd = os.path.dirname(text_or_path) with open(text_or_path, 'r') as f: content = f.read() # remove the comments comment_pattern = QRegExp("<!--.*?-->") pos = comment_pattern.indexIn(content) while pos != -1: content = content[:pos] + content[pos + comment_pattern.matchedLength():] pos = comment_pattern.indexIn(content) lines = content.splitlines() else: lines = [text_or_path] line_index = 0 for line in lines: index = cls._index(line, regexp_filelist) if index > -1: startIndex = line.find('"', index) if startIndex > -1: endIndex = line.find('"', startIndex + 1) fileName = line[startIndex + 1:endIndex] if len(fileName) > 0: try: path = cls.interpretPath(fileName, pwd) if os.path.isfile(path): if not regexp_retruns or cls._index(line, regexp_retruns) > -1: if not unique: result.append((line_index, path)) else: result.append(path) ext = os.path.splitext(path) if recursive and ext[1] in nm.settings().SEARCH_IN_EXT: result += cls.included_files(path, regexp_retruns, regexp_filelist) except Exception: import traceback print traceback.format_exc() line_index += 1 if unique: return list(set(result)) return result
def included_files(cls, text_or_path, regexp_list=[QRegExp("\\btextfile\\b"), QRegExp("\\bfile\\b"), QRegExp("\\bdefault\\b"), QRegExp("\\bvalue=.*pkg:\/\/\\b"), QRegExp("\\bvalue=.*package:\/\/\\b"), QRegExp("\\bvalue=.*\$\(find\\b"), QRegExp("\\bargs=.*\$\(find\\b")], recursive=True, unique=True): result = [] lines = [] pwd = '.' f = QFile(text_or_path) if f.exists(): pwd = os.path.dirname(text_or_path) with open(text_or_path, 'r') as f: content = f.read() # remove the comments comment_pattern = QRegExp("<!--.*?-->") pos = comment_pattern.indexIn(content) while pos != -1: content = content[:pos] + content[pos + comment_pattern.matchedLength():] pos = comment_pattern.indexIn(content) lines = content.splitlines() else: lines = [text_or_path] line_index = 0 for line in lines: index = cls._index(line, regexp_list) if index > -1: startIndex = line.find('"', index) if startIndex > -1: endIndex = line.find('"', startIndex + 1) fileName = line[startIndex + 1:endIndex] if len(fileName) > 0: try: path = cls.interpretPath(fileName, pwd) if os.path.isfile(path): if not unique: result.append((line_index, path)) else: result.append(path) ext = os.path.splitext(path) if recursive and ext[1] in nm.settings().SEARCH_IN_EXT: result += cls.included_files(path, regexp_list) except Exception: import traceback print traceback.format_exc() line_index += 1 if unique: return list(set(result)) return result
def getIncludedFiles(cls, inc_file, regexp_list=[QRegExp("\\binclude\\b"), QRegExp("\\btextfile\\b"), QRegExp("\\bfile\\b"), QRegExp("\\bdefault\\b"), QRegExp("\\bvalue=.*pkg:\/\/\\b"), QRegExp("\\bvalue=.*package:\/\/\\b"), QRegExp("\\bvalue=.*\$\(find\\b")]): ''' Reads the configuration file and searches for included files. This files will be returned in a list. @param inc_file: path of the ROS launch file @param regexp_list: pattern of @return: the list with all files needed for the configuration @rtype: C{[str,...]} ''' result = set() with open(inc_file, 'r') as f: content = f.read() # remove the comments comment_pattern = QRegExp("<!--.*?-->") pos = comment_pattern.indexIn(content) while pos != -1: content = content[:pos] + content[pos + comment_pattern.matchedLength():] pos = comment_pattern.indexIn(content) lines = content.splitlines() for line in lines: index = cls._index(line, regexp_list) if index > -1: startIndex = line.find('"', index) if startIndex > -1: endIndex = line.find('"', startIndex + 1) fileName = line[startIndex + 1:endIndex] if len(fileName) > 0: try: path = cls.interpretPath(fileName, os.path.dirname(inc_file)) if os.path.isfile(path): result.add(path) if path.endswith('.launch'): result.update(cls.getIncludedFiles(path, regexp_list)) except: pass return list(result)
class XmlHighlighter(QSyntaxHighlighter): ''' Enabled the syntax highlightning for the ROS launch files. ''' LAUNCH_LAUNCH_CHILDS = [ 'group', 'node', 'test', 'env', 'remap', 'rosparam', 'param', 'machine', 'include', 'arg' ] LAUNCH_LAUNCH_ATTR = {'deprecated=': '"message"'} LAUNCH_GROUP_CHILDS = [ 'node', 'test', 'env', 'remap', 'rosparam', 'param', 'machine', 'include', 'arg' ] LAUNCH_GROUP_ATTR = {'ns=': '"foo"', 'clear_params=': '"true|false"'} LAUNCH_MACHINE_CHILDS = ['env'] LAUNCH_MACHINE_ATTR = { 'name=': '"machine-name"', 'address=': '"blah.willowgarage.com"', 'env-loader=': '"/opt/ros/fuerte/env.sh"', 'default=': '"true|false|never"', 'user='******'"username"', 'password='******'"passwhat"', 'timeout=': '"10.0"' } LAUNCH_NODE_CHILDS = ['env', 'remap', 'rosparam', 'param'] LAUNCH_NODE_ATTR = { 'pkg=': '"mypackage"', 'type=': '"nodetype"', 'name=': '"nodename"', 'args=': '"arg1"', 'machine=': '"machine-name"', 'respawn=': '"true"', 'required=': '"true"', 'ns=': '"foo"', 'clear_params=': '"true|false"', 'output=': '"log|screen"', 'cwd=': '"ROS_HOME|node"', 'launch-prefix=': '"prefix arguments"' } LAUNCH_INCLUDE_CHILDS = ['env', 'arg'] LAUNCH_INCLUDE_ATTR = { 'file=': '"$(find pkg-name)/path/filename.xml"', 'ns=': '"foo"', 'clear_params=': '"true|false"', 'pass_all_args=': '"true|false"' } LAUNCH_REMAP_ATTR = {'from=': '"originalname"', 'to=': '"newname"'} LAUNCH_ENV_ATTR = {'name=': '"name"', 'value=': '"value"'} LAUNCH_PARAM_ATTR = { 'name=': '"namespace/name"', 'value=': '"value"', 'type=': '"str|int|double|bool"', 'textfile=': '"$(find pkg-name)/path/file.txt"', 'binfile=': '"$(find pkg-name)/path/file"', 'command=': '"$(find pkg-name)/exe \'$(find pkg-name)/arg.txt\'"' } LAUNCH_ROSPARAM_ATTR = { 'command=': '"load|dump|delete"', 'file=': '"$(find pkg-name)/path/foo.yaml"', 'param=': '"name"', 'ns=': '"foo"', 'subst_value=': '"true|false"' } LAUNCH_ARG_ATTR = { 'name=': '"name"', 'value=': '"bar"', 'default=': '"defbar"' } LAUNCH_TEST_CHILDS = ['env', 'remap', 'rosparam', 'param'] LAUNCH_TEST_ATTR = { 'pkg=': '"mypackage"', 'type=': '"nodetype"', 'name=': '"nodename"', 'test-name=': '"test_name"', 'args=': '"arg1"', 'ns=': '"foo"', 'clear_params=': '"true|false"', 'retry=': '"0"', 'cwd=': '"ROS_HOME|node"', 'launch-prefix=': '"prefix arguments"', 'time-limit=': '"60.0"' } LAUNCH_CHILDS = { 'launch': LAUNCH_LAUNCH_CHILDS, 'group': LAUNCH_GROUP_CHILDS, 'machine': LAUNCH_MACHINE_CHILDS, 'node': LAUNCH_NODE_CHILDS, 'include': LAUNCH_INCLUDE_CHILDS, 'remap': [], 'env': [], 'param': [], 'rosparam': [], 'arg': [], 'test': LAUNCH_TEST_CHILDS } LAUNCH_ATT_GLOBAL = {'if=': '""', 'unless=': '""'} LAUNCH_LAUNCH_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_GROUP_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_MACHINE_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_NODE_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_INCLUDE_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_REMAP_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_ENV_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_PARAM_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_ROSPARAM_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_ARG_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_TEST_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_ATTR = { 'launch': LAUNCH_LAUNCH_ATTR, 'group': LAUNCH_GROUP_ATTR, 'machine': LAUNCH_MACHINE_ATTR, 'node': LAUNCH_NODE_ATTR, 'include': LAUNCH_INCLUDE_ATTR, 'remap': LAUNCH_REMAP_ATTR, 'env': LAUNCH_ENV_ATTR, 'param': LAUNCH_PARAM_ATTR, 'rosparam': LAUNCH_ROSPARAM_ATTR, 'arg': LAUNCH_ARG_ATTR, 'test': LAUNCH_TEST_ATTR, } DEPRECATED_PARAMETER = { 'associations': 'nm/associations', 'kill_on_stop': 'nm/kill_on_stop', } STATE_COMMENT = 2 STATE_STRING = 4 def __init__(self, parent=None, is_launch=True): QSyntaxHighlighter.__init__(self, parent) self._is_launch = is_launch self.rules = [] self.comment_start = QRegExp("<!--") self.comment_end = QRegExp("-->") self.comment_format = self._create_format(Qt.darkGray, 'italic') # self.mark_background = QBrush(QColor(251, 247, 222)) # create patterns for braces self.rules.append((self._create_regexp("</?|/?>"), self._create_format(QColor(24, 24, 24)))) # create patterns for TAG if self._is_launch: tag_list = '|'.join( ["\\b%s\\b" % t for t in self.LAUNCH_CHILDS.keys()]) self.rules.append((self._create_regexp(tag_list), self._create_format(Qt.darkRed))) else: self.rules.append( (self._create_regexp(">|/>|<[/.\w:]*[\s\t>]|<[/.\w:]*$"), self._create_format(Qt.darkRed))) # create patterns for ATTRIBUTES if self._is_launch: attr_list = '|'.join( set([ "\\b%s" % attr for v in self.LAUNCH_ATTR.values() for attr in v.keys() ])) self.rules.append((self._create_regexp(attr_list), self._create_format(QColor(0, 100, 0)))) # darkGreen else: self.rules.append((self._create_regexp("[_.\w]*="), self._create_format(QColor(0, 100, 0)))) # darkGreen # create patterns for substitutions self.rule_arg = (self._create_regexp("\\$\\(.*\\)"), self._create_format(QColor(77, 0, 38))) # create patterns for DOCTYPE self.rules.append((self._create_regexp("<!DOCTYPE.*>"), self._create_format(Qt.lightGray))) self.rules.append((self._create_regexp("<\\?xml.*\\?>"), self._create_format(Qt.lightGray))) # create patterns for yaml parameter inside self.rules.append((self._create_regexp("[_.\w]*\s*:"), self._create_format(Qt.darkBlue))) # create patterns for yaml oneline strings inside self.rules.append( (self._create_regexp("'.*'"), self._create_format(Qt.blue))) # create pattern for list signes self.rules.append((self._create_regexp("^\s*-"), self._create_format(Qt.darkRed, 'bold'))) # create pattern for digits self.rules.append((self._create_regexp("\\d+"), self._create_format(QColor(127, 64, 127)))) self.yaml_comment_rule = (self._create_regexp("#[.]*"), self._create_format(Qt.darkGray)) # create deprecated self.dep_pattern = [] if self.DEPRECATED_PARAMETER: attr_list = '|'.join( set([ r'name="%s"' % attr for attr in self.DEPRECATED_PARAMETER.keys() ])) # print(attr_list) self.dep_pattern.append( (self._create_regexp(attr_list), self._create_format(QColor(250, 0, 0), 'bold'))) # red # create patterns for strings self.string_pattern = QRegExp("\"") self.string_format = self._create_format(Qt.blue) # part to select an XML block self._tag_hl_range = [] # list with puples (start, length) self._tag_hl_last = [] # set with blocks of last highlighted tags self._color_hl_tag = QColor(255, 128, 0) def _create_regexp(self, pattern=''): _regexp = QRegExp() _regexp.setMinimal(True) _regexp.setPattern(pattern) return _regexp def _create_format(self, color, style=''): _format = QTextCharFormat() _format.setForeground(color) if 'bold' in style: _format.setFontWeight(QFont.Bold) else: _format.setFontWeight(QFont.Normal) if 'italic' in style: _format.setFontItalic(True) return _format def highlightBlock(self, text): for pattern, form in self.rules: index = pattern.indexIn(text) while index >= 0: length = pattern.matchedLength() frmt = form if self._in_hl_range(index, self._tag_hl_range): frmt = QTextCharFormat(form) if not self._end_tag_found: frmt.setForeground(Qt.red) else: frmt.setForeground(self._color_hl_tag) frmt.setFontWeight(QFont.Bold) self.setFormat(index, length, frmt) index = pattern.indexIn(text, index + length) # search for YAML comments index = self.yaml_comment_rule[0].indexIn(text) if index >= 0: self.setFormat(index, len(text) - index, self.yaml_comment_rule[1]) self._tag_hl_range = [] self.setCurrentBlockState(0) # detection for XML comments self._comments_idx = [] idx_start_cmt = 0 comment_length = 0 if self.previousBlockState( ) == -1 or not self.previousBlockState() & self.STATE_COMMENT: idx_start_cmt = self.comment_start.indexIn(text) while idx_start_cmt >= 0: idx_end = self.comment_end.indexIn(text, idx_start_cmt) comment_length = 0 if idx_end == -1: self.setCurrentBlockState(self.STATE_COMMENT) comment_length = len(text) - idx_start_cmt else: comment_length = idx_end - idx_start_cmt + self.comment_end.matchedLength( ) self._comments_idx.append((idx_start_cmt, comment_length)) self.setFormat(idx_start_cmt, comment_length, self.comment_format) idx_start_cmt = self.comment_start.indexIn( text, idx_start_cmt + comment_length) # format string and detection for multiline string idx_start = self.string_pattern.indexIn(text) if self.previousBlockState( ) != -1 and self.previousBlockState() & self.STATE_STRING: strlen = idx_start + self.string_pattern.matchedLength() if idx_start == -1: strlen = len(text) self.setCurrentBlockState(self.currentBlockState() + self.STATE_STRING) self.setFormat(0, strlen, self.string_format) idx_start = self.string_pattern.indexIn(text, strlen) idx_search = idx_start + 1 while idx_start >= 0: # skip the strings which are in the comments if not self._in_hl_range(idx_search, self._comments_idx): idx_end = self.string_pattern.indexIn(text, idx_search) strlen = 0 if not self._in_hl_range(idx_end, self._comments_idx): if idx_end == -1: self.setCurrentBlockState(self.currentBlockState() + self.STATE_STRING) strlen = len(text) - idx_start else: strlen = idx_end - idx_start + self.string_pattern.matchedLength( ) idx_search = idx_start + strlen self.setFormat(idx_start, strlen, self.string_format) idx_start = self.string_pattern.indexIn(text, idx_search) idx_search = idx_start + 1 else: idx_search = idx_end + 1 else: idx_start = self.string_pattern.indexIn(text, idx_search) idx_search = idx_start + 1 # mark arguments index = self.rule_arg[0].indexIn(text) while index >= 0: if not self._in_hl_range(index, self._comments_idx): length = self.rule_arg[0].matchedLength() self.setFormat(index, length, self.rule_arg[1]) index = self.rule_arg[0].indexIn(text, index + length) # mark deprecated parameter for pattern, form in self.dep_pattern: index = pattern.indexIn(text) while index >= 0: length = pattern.matchedLength() frmt = form if self._in_hl_range(index, self._tag_hl_range): frmt = QTextCharFormat(form) if not self._end_tag_found: frmt.setForeground(Qt.red) else: frmt.setForeground(self._color_hl_tag) frmt.setFontWeight(QFont.Bold) self.setFormat(index, length, frmt) index = pattern.indexIn(text, index + length) def mark_block(self, block, position): text = block.text() word, idx_word = self._get_current_word(text, position) for hlblock in self._tag_hl_last: self.rehighlightBlock(hlblock) del self._tag_hl_last[:] self._tag_hl_range = [(idx_word, len(word))] next_block = block open_braces = 0 closed_braces = 0 idx_search = idx_word rindex = -1 loop = 0 tag_len = 0 if self._isclosetag(word): # we are at the close tag: search for the open tag opentag = '<%s' % self._get_tag(word) tag_len = len(opentag) while rindex == -1 and next_block.isValid(): rindex = text.rfind(opentag, 0, idx_search) obr, cbr = self._get_braces_count( text[rindex if rindex != -1 else 0:idx_search]) open_braces += obr closed_braces += cbr loop += 1 if loop > 50000: rindex = -1 break if rindex == -1: next_block = next_block.previous() text = next_block.text() idx_search = len(text) elif open_braces <= closed_braces: idx_search = rindex rindex = -1 elif self._isopentag(word): # we are at the open tag: search for the close tag closetag = QRegExp("</%s>|/>" % self._get_tag(word)) closetag.setMinimal(True) while rindex == -1 and next_block.isValid(): rindex = closetag.indexIn(text, idx_search) max_search_idx = rindex + closetag.matchedLength( ) if rindex != -1 else len(text) obr, cbr = self._get_braces_count( text[idx_search:max_search_idx]) open_braces += obr closed_braces += cbr loop += 1 if loop > 50000: rindex = -1 break if rindex == -1: next_block = next_block.next() text = next_block.text() idx_search = 0 elif open_braces > closed_braces: idx_search = rindex + closetag.matchedLength() rindex = -1 tag_len = closetag.matchedLength() else: self._tag_hl_range = [] self._end_tag_found = rindex != -1 if self._tag_hl_range and block != next_block: self.rehighlightBlock(block) self._tag_hl_last.append(block) if rindex != -1: self._tag_hl_range.append((rindex, tag_len)) self.rehighlightBlock(next_block) self._tag_hl_last.append(next_block) def _get_braces_count(self, text): closed_short = text.count('/>') closed_long = text.count('</') cmnt_long = text.count('<!') openbr = text.count('<') - closed_long - cmnt_long return openbr, closed_short + closed_long def _isopentag(self, word): return word.startswith('<') and '/' not in word def _isclosetag(self, word): return '/>' == word or word.startswith('</') def _get_tag(self, word): return word.strip('</>') def _get_current_word(self, text, position): word = '' idx_start = position for i in reversed(range(0, position)): if text[i] in [' ', '\n', '=', '"']: break else: word = "%s%s" % (text[i], word) idx_start = i for i in range(position, len(text)): if text[i] in [' ', '\n', '=', '"']: break else: word += text[i] return word, idx_start def _in_hl_range(self, value, ranges): for (start, length) in ranges: if value >= start and value <= start + length: return True return False def get_tag_of_current_block(self, block, position): text = block.text() next_block = block idx_search = position rindex = -1 loop = 0 # we are at the close tag: search for the open tag opentag = '<' while rindex == -1 and next_block.isValid(): rindex = text.rfind(opentag, 0, idx_search) loop += 1 if loop > 100: rindex = -1 break if rindex == -1: next_block = next_block.previous() text = next_block.text() idx_search = len(text) tag = '' if rindex != -1: for i in range(rindex + 1, len(text)): if text[i] in [' ', '\n', '=', '"', '>']: break else: tag += text[i] return tag
def mark_block(self, block, position): text = block.text() word, idx_word = self._get_current_word(text, position) for hlblock in self._tag_hl_last: self.rehighlightBlock(hlblock) del self._tag_hl_last[:] self._tag_hl_range = [(idx_word, len(word))] next_block = block open_braces = 0 closed_braces = 0 idx_search = idx_word rindex = -1 loop = 0 tag_len = 0 if self._isclosetag(word): # we are at the close tag: search for the open tag opentag = '<%s' % self._get_tag(word) tag_len = len(opentag) while rindex == -1 and next_block.isValid(): rindex = text.rfind(opentag, 0, idx_search) obr, cbr = self._get_braces_count( text[rindex if rindex != -1 else 0:idx_search]) open_braces += obr closed_braces += cbr loop += 1 if loop > 50000: rindex = -1 break if rindex == -1: next_block = next_block.previous() text = next_block.text() idx_search = len(text) elif open_braces <= closed_braces: idx_search = rindex rindex = -1 elif self._isopentag(word): # we are at the open tag: search for the close tag closetag = QRegExp("</%s>|/>" % self._get_tag(word)) closetag.setMinimal(True) while rindex == -1 and next_block.isValid(): rindex = closetag.indexIn(text, idx_search) max_search_idx = rindex + closetag.matchedLength( ) if rindex != -1 else len(text) obr, cbr = self._get_braces_count( text[idx_search:max_search_idx]) open_braces += obr closed_braces += cbr loop += 1 if loop > 50000: rindex = -1 break if rindex == -1: next_block = next_block.next() text = next_block.text() idx_search = 0 elif open_braces > closed_braces: idx_search = rindex + closetag.matchedLength() rindex = -1 tag_len = closetag.matchedLength() else: self._tag_hl_range = [] self._end_tag_found = rindex != -1 if self._tag_hl_range and block != next_block: self.rehighlightBlock(block) self._tag_hl_last.append(block) if rindex != -1: self._tag_hl_range.append((rindex, tag_len)) self.rehighlightBlock(next_block) self._tag_hl_last.append(next_block)
class XmlHighlighter(QSyntaxHighlighter): ''' Enabled the syntax highlightning for the ROS launch files. ''' LAUNCH_LAUNCH_CHILDS = ['group', 'node', 'test', 'env', 'remap', 'rosparam', 'param', 'machine', 'include', 'arg'] LAUNCH_LAUNCH_ATTR = {'deprecated=': '"message"'} LAUNCH_GROUP_CHILDS = ['node', 'test', 'env', 'remap', 'rosparam', 'param', 'machine', 'include', 'arg'] LAUNCH_GROUP_ATTR = {'ns=': '"foo"', 'clear_params=': '"true|false"' } LAUNCH_MACHINE_CHILDS = ['env'] LAUNCH_MACHINE_ATTR = {'name=': '"machine-name"', 'address=': '"blah.willowgarage.com"', 'env-loader=': '"/opt/ros/fuerte/env.sh"', 'default=': '"true|false|never"', 'user='******'"username"', 'password='******'"passwhat"', 'timeout=': '"10.0"' } LAUNCH_NODE_CHILDS = ['env', 'remap', 'rosparam', 'param'] LAUNCH_NODE_ATTR = {'pkg=': '"mypackage"', 'type=': '"nodetype"', 'name=': '"nodename"', 'args=': '"arg1"', 'machine=': '"machine-name"', 'respawn=': '"true"', 'required=': '"true"', 'ns=': '"foo"', 'clear_params=': '"true|false"', 'output=': '"log|screen"', 'cwd=': '"ROS_HOME|node"', 'launch-prefix=': '"prefix arguments"' } LAUNCH_INCLUDE_CHILDS = ['env', 'arg'] LAUNCH_INCLUDE_ATTR = {'file=': '"$(find pkg-name)/path/filename.xml"', 'ns=': '"foo"', 'clear_params=': '"true|false"' } LAUNCH_REMAP_ATTR = {'from=': '"originalname"', 'to=': '"newname"' } LAUNCH_ENV_ATTR = {'name=': '"name"', 'value=': '"value"' } LAUNCH_PARAM_ATTR = {'name=': '"namespace/name"', 'value=': '"value"', 'type=': '"str|int|double|bool"', 'textfile=': '"$(find pkg-name)/path/file.txt"', 'binfile=': '"$(find pkg-name)/path/file"', 'command=': '"$(find pkg-name)/exe \'$(find pkg-name)/arg.txt\'"' } LAUNCH_ROSPARAM_ATTR = {'command=': '"load|dump|delete"', 'file=': '"$(find pkg-name)/path/foo.yaml"', 'param=': '"name"', 'ns=': '"foo"', 'subst_value=': '"true|false"' } LAUNCH_ARG_ATTR = {'name=': '"name"', 'value=': '"bar"', 'default=': '"defbar"' } LAUNCH_TEST_CHILDS = ['env', 'remap', 'rosparam', 'param'] LAUNCH_TEST_ATTR = {'pkg=': '"mypackage"', 'type=': '"nodetype"', 'name=': '"nodename"', 'test-name=': '"test_name"', 'args=': '"arg1"', 'ns=': '"foo"', 'clear_params=': '"true|false"', 'retry=': '"0"', 'cwd=': '"ROS_HOME|node"', 'launch-prefix=': '"prefix arguments"', 'time-limit=': '"60.0"' } LAUNCH_CHILDS = {'launch': LAUNCH_LAUNCH_CHILDS, 'group': LAUNCH_GROUP_CHILDS, 'machine': LAUNCH_MACHINE_CHILDS, 'node': LAUNCH_NODE_CHILDS, 'include': LAUNCH_INCLUDE_CHILDS, 'remap': [], 'env': [], 'param': [], 'rosparam': [], 'arg': [], 'test': LAUNCH_TEST_CHILDS } LAUNCH_ATT_GLOBAL = {'if=': '""', 'unless=': '""'} LAUNCH_LAUNCH_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_GROUP_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_MACHINE_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_NODE_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_INCLUDE_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_REMAP_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_ENV_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_PARAM_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_ROSPARAM_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_ARG_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_TEST_ATTR.update(LAUNCH_ATT_GLOBAL) LAUNCH_ATTR = {'launch': LAUNCH_LAUNCH_ATTR, 'group': LAUNCH_GROUP_ATTR, 'machine': LAUNCH_MACHINE_ATTR, 'node': LAUNCH_NODE_ATTR, 'include': LAUNCH_INCLUDE_ATTR, 'remap': LAUNCH_REMAP_ATTR, 'env': LAUNCH_ENV_ATTR, 'param': LAUNCH_PARAM_ATTR, 'rosparam': LAUNCH_ROSPARAM_ATTR, 'arg': LAUNCH_ARG_ATTR, 'test': LAUNCH_TEST_ATTR, } STATE_COMMENT = 2 STATE_STRING = 4 def __init__(self, parent=None): QSyntaxHighlighter.__init__(self, parent) self.rules = [] self.comment_start = QRegExp("<!--") self.comment_end = QRegExp("-->") self.comment_format = self._create_format(Qt.darkGray, 'italic') # self.mark_background = QBrush(QColor(251, 247, 222)) # create patterns for braces self.rules.append((self._create_regexp("</?|/?>"), self._create_format(QColor(24, 24, 24)))) # create patterns for TAG tag_list = '|'.join(["\\b%s\\b" % t for t in self.LAUNCH_CHILDS.keys()]) self.rules.append((self._create_regexp(tag_list), self._create_format(Qt.darkRed))) # create patterns for ATTRIBUTES attr_list = '|'.join(set(["\\b%s" % attr for v in self.LAUNCH_ATTR.values() for attr in v.keys()])) self.rules.append((self._create_regexp(attr_list), self._create_format(QColor(0, 100, 0)))) # darkGreen # create patterns for substitutions self.rule_arg = (self._create_regexp("\\$\\(.*\\)"), self._create_format(QColor(77, 0, 38))) # create patterns for DOCTYPE self.rules.append((self._create_regexp("<!DOCTYPE.*>"), self._create_format(Qt.lightGray))) self.rules.append((self._create_regexp("<\\?xml.*\\?>"), self._create_format(Qt.lightGray))) # create patterns for yaml parameter inside self.rules.append((self._create_regexp("^\s*[_.\w]*\s*:"), self._create_format(Qt.darkBlue))) # create patterns for yaml oneline strings inside self.rules.append((self._create_regexp("'.*'"), self._create_format(Qt.blue))) # create pattern for list signes self.rules.append((self._create_regexp("^\s*-"), self._create_format(Qt.darkRed, 'bold'))) # create pattern for digits self.rules.append((self._create_regexp("\\d+"), self._create_format(QColor(127, 64, 127)))) # create patterns for strings self.string_pattern = QRegExp("\"") self.string_format = self._create_format(Qt.blue) # part to select an XML block self._tag_hl_range = [] # list with puples (start, length) self._tag_hl_last = set() # set with blocks of last highlighted tags def _create_regexp(self, pattern=''): _regexp = QRegExp() _regexp.setMinimal(True) _regexp.setPattern(pattern) return _regexp def _create_format(self, color, style=''): _format = QTextCharFormat() _format.setForeground(color) if 'bold' in style: _format.setFontWeight(QFont.Bold) else: _format.setFontWeight(QFont.Normal) if 'italic' in style: _format.setFontItalic(True) return _format def highlightBlock(self, text): for pattern, form in self.rules: index = pattern.indexIn(text) while index >= 0: length = pattern.matchedLength() frmt = form if self._in_hl_range(index, self._tag_hl_range): frmt = QTextCharFormat(form) if not self._end_tag_found: frmt.setForeground(Qt.red) frmt.setFontWeight(QFont.Bold) self.setFormat(index, length, frmt) index = pattern.indexIn(text, index + length) self._tag_hl_range = [] self.setCurrentBlockState(0) # detection for comments self._comments_idx = [] idx_start_cmt = 0 comment_length = 0 if self.previousBlockState() == -1 or not self.previousBlockState() & self.STATE_COMMENT: idx_start_cmt = self.comment_start.indexIn(text) while idx_start_cmt >= 0: idx_end = self.comment_end.indexIn(text, idx_start_cmt) comment_length = 0 if idx_end == -1: self.setCurrentBlockState(self.STATE_COMMENT) comment_length = len(text) - idx_start_cmt else: comment_length = idx_end - idx_start_cmt + self.comment_end.matchedLength() self._comments_idx.append((idx_start_cmt, comment_length)) self.setFormat(idx_start_cmt, comment_length, self.comment_format) idx_start_cmt = self.comment_start.indexIn(text, idx_start_cmt + comment_length) # format string and detection for multiline string idx_start = self.string_pattern.indexIn(text) if self.previousBlockState() != -1 and self.previousBlockState() & self.STATE_STRING: strlen = idx_start + self.string_pattern.matchedLength() if idx_start == -1: strlen = len(text) self.setCurrentBlockState(self.currentBlockState() + self.STATE_STRING) self.setFormat(0, strlen, self.string_format) idx_start = self.string_pattern.indexIn(text, strlen) idx_search = idx_start + 1 while idx_start >= 0: # skip the strings which are in the comments if not self._in_hl_range(idx_search, self._comments_idx): idx_end = self.string_pattern.indexIn(text, idx_search) strlen = 0 if not self._in_hl_range(idx_end, self._comments_idx): if idx_end == -1: self.setCurrentBlockState(self.currentBlockState() + self.STATE_STRING) strlen = len(text) - idx_start else: strlen = idx_end - idx_start + self.string_pattern.matchedLength() idx_search = idx_start + strlen self.setFormat(idx_start, strlen, self.string_format) idx_start = self.string_pattern.indexIn(text, idx_search) idx_search = idx_start + 1 else: idx_search = idx_end + 1 else: idx_start = self.string_pattern.indexIn(text, idx_search) idx_search = idx_start + 1 # mark arguments index = self.rule_arg[0].indexIn(text) while index >= 0: if not self._in_hl_range(index, self._comments_idx): length = self.rule_arg[0].matchedLength() self.setFormat(index, length, self.rule_arg[1]) index = self.rule_arg[0].indexIn(text, index + length) def mark_block(self, block, position): text = block.text() word, idx_word = self._get_current_word(text, position) for hlblock in self._tag_hl_last: self.rehighlightBlock(hlblock) self._tag_hl_last.clear() self._tag_hl_range = [(idx_word, len(word))] next_block = block open_braces = 0 closed_braces = 0 idx_search = idx_word rindex = -1 loop = 0 tag_len = 0 if self._isclosetag(word): # we are at the close tag: search for the open tag opentag = '<%s' % self._get_tag(word) tag_len = len(opentag) while rindex == -1 and next_block.isValid(): rindex = text.rfind(opentag, 0, idx_search) obr, cbr = self._get_braces_count(text[rindex if rindex != -1 else 0:idx_search]) open_braces += obr closed_braces += cbr loop += 1 if loop > 50000: rindex = -1 break if rindex == -1: next_block = next_block.previous() text = next_block.text() idx_search = len(text) elif open_braces <= closed_braces: idx_search = rindex rindex = -1 elif self._isopentag(word): # we are at the open tag: search for the close tag closetag = QRegExp("</%s>|/>" % self._get_tag(word)) closetag.setMinimal(True) while rindex == -1 and next_block.isValid(): rindex = closetag.indexIn(text, idx_search) max_search_idx = rindex + closetag.matchedLength() if rindex != -1 else len(text) obr, cbr = self._get_braces_count(text[idx_search:max_search_idx]) open_braces += obr closed_braces += cbr loop += 1 if loop > 50000: rindex = -1 break if rindex == -1: next_block = next_block.next() text = next_block.text() idx_search = 0 elif open_braces > closed_braces: idx_search = rindex + closetag.matchedLength() rindex = -1 tag_len = closetag.matchedLength() else: self._tag_hl_range = [] self._end_tag_found = rindex != -1 if self._tag_hl_range and block != next_block: self.rehighlightBlock(block) self._tag_hl_last.add(block) if rindex != -1: self._tag_hl_range.append((rindex, tag_len)) self.rehighlightBlock(next_block) self._tag_hl_last.add(next_block) def _get_braces_count(self, text): closed_short = text.count('/>') closed_long = text.count('</') cmnt_long = text.count('<!') openbr = text.count('<') - closed_long - cmnt_long return openbr, closed_short + closed_long def _isopentag(self, word): return word.startswith('<') and '/' not in word def _isclosetag(self, word): return '/>' == word or word.startswith('</') def _get_tag(self, word): return word.strip('</>') def _get_current_word(self, text, position): word = '' idx_start = position for i in reversed(range(0, position)): if text[i] in [' ', '\n', '=', '"']: break else: word = "%s%s" % (text[i], word) idx_start = i for i in range(position, len(text)): if text[i] in [' ', '\n', '=', '"']: break else: word += text[i] return word, idx_start def _in_hl_range(self, value, ranges): for (start, length) in ranges: if value >= start and value <= start + length: return True return False def get_tag_of_current_block(self, block, position): text = block.text() next_block = block idx_search = position rindex = -1 loop = 0 # we are at the close tag: search for the open tag opentag = '<' while rindex == -1 and next_block.isValid(): rindex = text.rfind(opentag, 0, idx_search) loop += 1 if loop > 100: rindex = -1 break if rindex == -1: next_block = next_block.previous() text = next_block.text() idx_search = len(text) tag = '' if rindex != -1: for i in range(rindex + 1, len(text)): if text[i] in [' ', '\n', '=', '"', '>']: break else: tag += text[i] return tag
def mark_block(self, block, position): text = block.text() word, idx_word = self._get_current_word(text, position) for hlblock in self._tag_hl_last: self.rehighlightBlock(hlblock) self._tag_hl_last.clear() self._tag_hl_range = [(idx_word, len(word))] next_block = block open_braces = 0 closed_braces = 0 idx_search = idx_word rindex = -1 loop = 0 tag_len = 0 if self._isclosetag(word): # we are at the close tag: search for the open tag opentag = '<%s' % self._get_tag(word) tag_len = len(opentag) while rindex == -1 and next_block.isValid(): rindex = text.rfind(opentag, 0, idx_search) obr, cbr = self._get_braces_count(text[rindex if rindex != -1 else 0:idx_search]) open_braces += obr closed_braces += cbr loop += 1 if loop > 50000: rindex = -1 break if rindex == -1: next_block = next_block.previous() text = next_block.text() idx_search = len(text) elif open_braces <= closed_braces: idx_search = rindex rindex = -1 elif self._isopentag(word): # we are at the open tag: search for the close tag closetag = QRegExp("</%s>|/>" % self._get_tag(word)) closetag.setMinimal(True) while rindex == -1 and next_block.isValid(): rindex = closetag.indexIn(text, idx_search) max_search_idx = rindex + closetag.matchedLength() if rindex != -1 else len(text) obr, cbr = self._get_braces_count(text[idx_search:max_search_idx]) open_braces += obr closed_braces += cbr loop += 1 if loop > 50000: rindex = -1 break if rindex == -1: next_block = next_block.next() text = next_block.text() idx_search = 0 elif open_braces > closed_braces: idx_search = rindex + closetag.matchedLength() rindex = -1 tag_len = closetag.matchedLength() else: self._tag_hl_range = [] self._end_tag_found = rindex != -1 if self._tag_hl_range and block != next_block: self.rehighlightBlock(block) self._tag_hl_last.add(block) if rindex != -1: self._tag_hl_range.append((rindex, tag_len)) self.rehighlightBlock(next_block) self._tag_hl_last.add(next_block)