我正在尝试将Glib::Regex和Gtk::TextView与Gtk::TextBuffer-s一起使用,并且尝试使用Gtk::TextTag-s进行语法高亮显示。

我的语法更新代码(它在行的开头和结尾接收迭代器)

void MainWindow::update_syntax(const Gtk::TextBuffer::iterator& start, const Gtk::TextBuffer::iterator& end)    {
  std::vector<Glib::ustring> keywords;
  keywords.push_back("class");
  keywords.push_back("struct");
  Glib::MatchInfo info;
  auto regex = Glib::Regex::create(R"((\w+))");
  auto ok = regex->match(start.get_visible_text(end), info);
  std::map<Glib::ustring, std::pair<Glib::RefPtr<Gtk::TextMark>, Glib::RefPtr<Gtk::TextMark>>> marks;
  do {
    std::cout << "word: " << info.fetch(1) << std::endl;
    for (auto kw : keywords) {
      if (info.fetch(1) == kw) {
        int start_offset, end_offset;
        info.fetch_pos(1, start_offset, end_offset);
        std::cout << info.fetch(1) << " (at: [" << start_offset << ";" << end_offset << "])" << std::endl;
        marks["keyword"] = std::make_pair(
          this->m_buffer->create_mark(
            this->m_buffer->get_iter_at_offset(start.get_offset() + start_offset)
          ),
          this->m_buffer->create_mark(
            this->m_buffer->get_iter_at_offset(start.get_offset() + end_offset)
          )
        );
      }
    }
  } while(info.next());

  for (auto mark : marks) {
    this->m_buffer->apply_tag_by_name(mark.first,
      mark.second.first->get_iter(), mark.second.second->get_iter());
  }
}

因此流程是,我创建一个简单的正则表达式,该行应与该行中的每个单词匹配,然后创建一个标记映射,此映射稍后将提供设置标记的范围。我在这里使用Gtk::Mark,因为每次对缓冲区的修改都会使迭代器无效。

为了说明这里出了什么问题,我将从该函数中发布一些调试输出,并在其之前添加一个插槽on_insert
void MainWindow::on_insert(const Gtk::TextBuffer::iterator& pos,
  const Glib::ustring& text, int bytes)
{
  std::cout << text << " (added at[" << pos.get_offset() <<
  "]; with [" << bytes << "]bytes)" << std::endl << std::endl;

因此,将class class写入TextView的输出导致第一个突出显示,而第二个未选中,请记录:
c (added at[1]; with [1]bytes)

word: c
l (added at[2]; with [1]bytes)

word: cl
a (added at[3]; with [1]bytes)

word: cla
s (added at[4]; with [1]bytes)

word: clas
s (added at[5]; with [1]bytes)

word: class
class (keyword at: [0;5])
  (added at[6]; with [1]bytes)

word: class
class (keyword at: [0;5])
word: r
c (added at[7]; with [1]bytes)

word: class
class (keyword at: [0;5])
word: rd
l (added at[8]; with [1]bytes)

word: class
class (keyword at: [0;5])
word: rd
a (added at[9]; with [1]bytes)

word: class
class (keyword at: [0;5])
word: rd
word: a
s (added at[10]; with [1]bytes)

word: class
class (keyword at: [0;5])
word: rd
word: as
s (added at[11]; with [1]bytes)

word: class
class (keyword at: [0;5])
word: rd
word: ass

很容易注意到,最后一行显示它已移动了两个偏移量。可能是应用了标签。另外,这里还不清楚的是:word: rd。我使用keyword作为标签的名称。当此代码仍在使用迭代器时,info.fetch(1)返回"keyword",那么正则表达式是否也匹配标签?

希望有Glib和Gtk经验的人知道答案,谢谢。

最佳答案

我尚未使用此特定的API1,但我认为您的对象生存期存在问题。 iter->get_visible_text()返回一个字符串对象,该对象将在调用regex->match()之后销毁。这是一个问题,因为Glib::MatchInfo::next()期望该字符串仍然存在2。这可能就是为什么您在第二场比赛中遇到垃圾的原因。我认为您这样做是安全的:

....
auto visbuf = start.get_visible_text(end);
auto ok = regex->match(visbuf, info);  // existing line
...
  • 所以我可能很烂。
  • 来自Glib::MatchInfo::next()文档:匹配是在传递给match函数的字符串上完成的,因此您不能在调用此函数之前将其释放。
  • 关于c++ - Glib::Regex提取TextTag-s,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12007319/

    10-12 00:21
    查看更多