I have a working TextView/TextBuffer with gtk4 and python 3.12. My ApplicationWindow has two custom TextTags, self.tag_author, and self.tag_title. The author tag turns the background of text yellow. I can select some text, click a button, and I can see the yellow background text.
Bu now, I want to search the buffer, and find the block of text that has been tagged as ‘author’ and find the block of text that has been tagged as ‘title’.
How can I do that?
Hi,
Get the buffer start iter with Gtk.TextBuffer.get_start_iter , then call Gtk.TextIter.forward_to_tag_toggle to search for the next start or end of your tag (use Gtk.TextIter.starts_tag or Gtk.TextIter.ends_tag to detect which one it is)
Thanks! I wrote the following method, and it seems to work. I get the iter for the end of tagged text by calling forward_to_tag_toggle() twice. Is there a better approach to find the end? It looks like I can start searching from a TextMark, but I don’t see the benifit.
def search_buffer_for_tag(self, text_tag: Gtk.TextTag) -> str | None:
# We create two iters, one for the start of the tagged text, and one for the end of the tagged text.
slice_iter_start: Gtk.TextIter = self.textbuffer.get_start_iter()
slice_iter_end: Gtk.TextIter = self.textbuffer.get_start_iter()
# Searching from the beginning of the buffer, we search forward for the "first" toggle. It should be the start.
tag_was_found = slice_iter_start.forward_to_tag_toggle(text_tag)
if not tag_was_found:
print(f"tag {text_tag.props.name} not found")
return None
if not slice_iter_start.starts_tag(text_tag):
raise f"Programming error: Start of tagged text {text_tag.props.name} not found first."
# We start at the beginning, then search again for the end. Is there a better way to do this? Creating a
# TextMark does not seem to offer any advantage.
slice_iter_end.forward_to_tag_toggle(text_tag)
tag_was_found = slice_iter_end.forward_to_tag_toggle(text_tag)
if not tag_was_found:
raise f"Could not find end of tagged text {text_tag.props.name}."
if not slice_iter_end.ends_tag(text_tag):
raise f"Programming error: Fained to seek to end of tagged text {text_tag.props.name}."
# We have the start and the end, so get the slice of text from the TextBuffer.
tagged_text = self.textbuffer.get_slice(slice_iter_start, slice_iter_end, False)
if not tagged_text:
raise f"No text between start and end of tag {text_tag.props.name}"
return tagged_text
Don’t do that, it will raise an exception if the start iter is also a tag start, because forward_to_tag_toggle() will give you a tag end first in that case.
Yes, do a copy() of the start tag and use it as input of forward.
I suggest something like this:
def search_buffer_for_tag(self, text_tag: Gtk.TextTag) -> str | None
current: Gtk.TextIter = self.textbuffer.get_start_iter()
previous: Gtk.TextIter = current.copy()
while current.forward_to_tag_toggle(text_tag):
if current.ends_tag(text_tag):
return self.textbuffer.get_text(previous, current, False)
else:
previous= current.copy()
return None
(replace the return by yield if you need a list of all tagged occurrences, instead of just the 1st one)
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.