def on_buffer_notify_cursor_position(self, buffer: GtkSource.Buffer,
                                      *args):
     textiter = buffer.get_iter_at_offset(buffer.props.cursor_position)
     if 'string' in buffer.get_context_classes_at_iter(textiter):
         # iter_backward_to_context_class_toggle and iter_forward_to_context_class_toggle
         # seem to be broken (because of course they are), so we do it manually.
         start = self._get_string_start(textiter)
         end = self._get_string_end(textiter)
         if start is None or end is None:
             return True
         string = buffer.get_text(start, end, False)
         self.context.on_selected_string_changed(string)
     return True
    def on_buffer_notify_cursor_position(self, buffer: GtkSource.Buffer,
                                         *args):
        textiter = buffer.get_iter_at_offset(buffer.props.cursor_position)
        tip = self._build_calltip_data(textiter, buffer)
        if not tip:
            if self.position_mark_calltip is not None:
                self.position_mark_calltip.reset(self._active_widget)
            if self._active_widget:
                self._active_widget.destroy()
                self._active_widget = None
                self._active_op = None
                self._active_arg = None
            return True

        op: Pmd2ScriptOpCode
        op, arg_index = tip
        if not self._active_widget:
            self._active_widget = GtkSource.CompletionInfo.new()
            self._active_widget.set_attached_to(self.view)

        self._active_widget.move_to_iter(self.view, textiter)

        op_was_same = self._active_op == op
        if not op_was_same:
            self._active_op = op
            for c in self._active_widget.get_children():
                self._active_widget.remove(c)

            outer_box: Gtk.Box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 4)
            btn_box: Gtk.Box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 4)
            outer_box.pack_start(btn_box, True, False, 0)
            self._active_widget.add(outer_box)

        if not op_was_same or self._active_arg != arg_index:
            self._active_arg = arg_index
            btn_box = self._active_widget.get_children()[0].get_children()[0]
            for c in btn_box.get_children():
                btn_box.remove(c)
            for i, arg in enumerate(op.arguments):
                lbl: Gtk.Label = Gtk.Label.new('')
                if arg_index == i:
                    markup = f'<b>{arg.name}: <i>{arg.type}</i></b>, '
                else:
                    markup = f'<span weight="light">{arg.name}:  <i>{arg.type}</i></span>, '
                if i == len(
                        op.arguments) - 1 and not op.repeating_argument_group:
                    markup = markup.rstrip(', ')
                lbl.set_markup(markup)
                btn_box.pack_start(lbl, True, False, 0)
            if op.repeating_argument_group:
                lbl = Gtk.Label.new('[')
                btn_box.pack_start(lbl, True, False, 0)
                for i, arg in enumerate(op.repeating_argument_group.arguments):
                    lbl = Gtk.Label.new('')
                    # TODO: Support highlighting individual repeating args. (not really used though)
                    if arg_index >= len(op.arguments):
                        markup = f'<b>{arg.name}: <i>{arg.type}</i></b>, '
                    else:
                        markup = f'<span weight="light">{arg.name}:  <i>{arg.type}</i></span>, '
                    if i == len(op.repeating_argument_group.arguments) - 1:
                        markup = markup.rstrip(', ')
                    lbl.set_markup(markup)
                    btn_box.pack_start(lbl, True, False, 0)
                lbl = Gtk.Label.new('... ]')
                btn_box.pack_start(lbl, True, False, 0)

        if self.position_mark_calltip is not None:
            self.position_mark_calltip.add_button_if_pos_mark(
                self._active_widget.get_children()[0], buffer)

        self._active_widget.show_all()

        return True