1

私は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 classTextViewへの書き込みの出力により、最初の1つが強調表示され、2番目の出力が取得されないという結果になります。ログ:

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

最後の行は、2つのオフセットだけ移動したことを示していることに気付くのは簡単です。タグが適用されている可能性があります。また、ここで明確でないことは、:word: rdです。keywordタグの名前として使用します。そして、このコードがまだイテレータを使用していたときにinfo.fetch(1)返さ"keyword"れたので、正規表現もタグと一致している可能性がありますか?

GlibとGtkの経験がある人が答えを知っていることを願っています、ありがとう。

4

1 に答える 1

2

この特定のAPIはまだ使用していません1が、オブジェクトの有効期間に問題があると思います。 iter->get_visible_text()の呼び出し後に破棄される文字列オブジェクトを返していますregex->match()Glib::MatchInfo::next()その文字列がまだ存在することを期待しているため、これは問題です2。これがおそらく、2回目の試合でゴミを出す理由です。私はあなたがこのようなことをしても安全だと思います:

....
auto visbuf = start.get_visible_text(end); 
auto ok = regex->match(visbuf, info);  // existing line
...
  1. だから私はがらくたでいっぱいになる可能性があります。
  2. Glib :: MatchInfo :: next()のドキュメントから:一致はmatch関数に渡された文字列で行われるため、この関数を呼び出す前に解放することはできません。
于 2012-08-17T23:11:29.617 に答える