def _get_opcode_mark(cls, b: GtkSource.Buffer, ssb_filename: str,
                      opcode_addr: int,
                      is_for_macro_call: bool) -> Optional[Gtk.TextMark]:
     if is_for_macro_call:
         return b.get_mark(
             f'opcode_<<<{ssb_filename}>>>_{opcode_addr}_call')
     else:
         return b.get_mark(f'opcode_<<<{ssb_filename}>>>_{opcode_addr}')
 def switch_to_new_op_marks(cls, b: GtkSource.Buffer, ssb_filename: str):
     textiter: Gtk.TextIter = b.get_start_iter().copy()
     # TODO: This is probably pretty slow
     while textiter.forward_char():
         old_marks_at_pos = [
             m for m in textiter.get_marks() if m.get_name()
             and m.get_name().startswith(f'opcode_<<<{ssb_filename}>>>_')
         ]
         new_marks_at_pos = [
             m for m in textiter.get_marks() if m.get_name() and
             m.get_name().startswith(f'TMP_opcode_<<<{ssb_filename}>>>_')
         ]
         for m in old_marks_at_pos:
             b.delete_mark(m)
         for m in new_marks_at_pos:
             name = m.get_name()
             # Maybe by chance an old mark with this name still exists elsewhere, remove it.
             om = b.get_mark(name[4:])
             if om is not None:
                 b.delete_mark(om)
             # Move by deleting and re-creating.
             match = MARK_PATTERN_TMP.match(m.get_name())
             if match.group(3):
                 b.create_mark(
                     f'opcode_<<<{str(match.group(1))}>>>_{int(match.group(2))}_{match.group(3)}',
                     textiter)
             else:
                 b.create_mark(
                     f'opcode_<<<{str(match.group(1))}>>>_{int(match.group(2))}',
                     textiter)
             b.delete_mark(m)
 def remove_breakpoint_line_mark(cls, b: GtkSource.Buffer,
                                 ssb_filename: str, opcode_offset: int,
                                 category: str):
     # XXX: This is a bit ugly, but due to the fact, that there can be one call to a macro
     # in the same file, there can be exactly 0-2 line markers:
     for i in [0, 1]:
         m: Gtk.TextMark = b.get_mark(
             f'for:opcode_<<<{ssb_filename}>>>_{opcode_offset}_{i}')
         if m is None:
             return
         b.remove_source_marks(b.get_iter_at_mark(m), b.get_iter_at_mark(m),
                               category)
 def add_breakpoint_line_mark(cls, b: GtkSource.Buffer, ssb_filename: str,
                              opcode_offset: int, category: str):
     ms = []
     m: Gtk.TextMark = cls._get_opcode_mark(b, ssb_filename, opcode_offset,
                                            True)
     if m is not None:
         ms.append(m)
     m = cls._get_opcode_mark(b, ssb_filename, opcode_offset, False)
     if m is not None:
         ms.append(m)
     for i, m in enumerate(ms):
         line_iter = b.get_iter_at_line(b.get_iter_at_mark(m).get_line())
         lm: Gtk.TextMark = b.get_mark(
             f'for:opcode_<<<{ssb_filename}>>>_{opcode_offset}_{i}')
         if lm is not None:
             return
         b.create_source_mark(
             f'for:opcode_<<<{ssb_filename}>>>_{opcode_offset}_{i}',
             category, line_iter)