示例#1
0
void
gimp_text_tool_editor_button_press (GimpTextTool        *text_tool,
                                    gdouble              x,
                                    gdouble              y,
                                    GimpButtonPressType  press_type)
{
  GtkTextBuffer *buffer = GTK_TEXT_BUFFER (text_tool->buffer);
  GtkTextIter    cursor;
  GtkTextIter    selection;

  gimp_text_tool_xy_to_iter (text_tool, x, y, &cursor);

  selection = cursor;

  text_tool->select_start_iter = cursor;
  text_tool->select_words      = FALSE;
  text_tool->select_lines      = FALSE;

  switch (press_type)
    {
    case GIMP_BUTTON_PRESS_NORMAL:
      gtk_text_buffer_place_cursor (buffer, &cursor);
      break;

    case GIMP_BUTTON_PRESS_DOUBLE:
      text_tool->select_words = TRUE;

      if (! gtk_text_iter_starts_word (&cursor))
        gtk_text_iter_backward_visible_word_starts (&cursor, 1);

      if (! gtk_text_iter_ends_word (&selection) &&
          ! gtk_text_iter_forward_visible_word_ends (&selection, 1))
        gtk_text_iter_forward_to_line_end (&selection);

      gtk_text_buffer_select_range (buffer, &cursor, &selection);
      break;

    case GIMP_BUTTON_PRESS_TRIPLE:
      text_tool->select_lines = TRUE;

      gtk_text_iter_set_line_offset (&cursor, 0);
      gtk_text_iter_forward_to_line_end (&selection);

      gtk_text_buffer_select_range (buffer, &cursor, &selection);
      break;
    }
}
示例#2
0
static void
gimp_text_tool_delete_from_cursor (GimpTextTool  *text_tool,
                                   GtkDeleteType  type,
                                   gint           count)
{
  GtkTextBuffer *buffer = GTK_TEXT_BUFFER (text_tool->buffer);
  GtkTextIter    cursor;
  GtkTextIter    end;

  GIMP_LOG (TEXT_EDITING, "%s count = %d",
            g_enum_get_value (g_type_class_ref (GTK_TYPE_DELETE_TYPE),
                              type)->value_name,
            count);

  gimp_text_tool_reset_im_context (text_tool);

  gtk_text_buffer_get_iter_at_mark (buffer, &cursor,
                                    gtk_text_buffer_get_insert (buffer));
  end = cursor;

  switch (type)
    {
    case GTK_DELETE_CHARS:
      if (gtk_text_buffer_get_has_selection (buffer))
        {
          gtk_text_buffer_delete_selection (buffer, TRUE, TRUE);
          return;
        }
      else
        {
          gtk_text_iter_forward_cursor_positions (&end, count);
        }
      break;

    case GTK_DELETE_WORD_ENDS:
      if (count < 0)
        {
          if (! gtk_text_iter_starts_word (&cursor))
            gtk_text_iter_backward_visible_word_starts (&cursor, 1);
        }
      else if (count > 0)
        {
          if (! gtk_text_iter_ends_word (&end) &&
              ! gtk_text_iter_forward_visible_word_ends (&end, 1))
            gtk_text_iter_forward_to_line_end (&end);
        }
      break;

    case GTK_DELETE_WORDS:
      if (! gtk_text_iter_starts_word (&cursor))
        gtk_text_iter_backward_visible_word_starts (&cursor, 1);

      if (! gtk_text_iter_ends_word (&end) &&
          ! gtk_text_iter_forward_visible_word_ends (&end, 1))
        gtk_text_iter_forward_to_line_end (&end);
      break;

    case GTK_DELETE_DISPLAY_LINES:
      break;

    case GTK_DELETE_DISPLAY_LINE_ENDS:
      break;

    case GTK_DELETE_PARAGRAPH_ENDS:
      if (count < 0)
        {
          gtk_text_iter_set_line_offset (&cursor, 0);
        }
      else if (count > 0)
        {
          if (! gtk_text_iter_ends_line (&end))
            gtk_text_iter_forward_to_line_end (&end);
          else
            gtk_text_iter_forward_cursor_positions (&end, 1);
        }
      break;

    case GTK_DELETE_PARAGRAPHS:
      break;

    case GTK_DELETE_WHITESPACE:
      find_whitepace_region (&cursor, &cursor, &end);
      break;
    }

  if (! gtk_text_iter_equal (&cursor, &end))
    {
      gtk_text_buffer_delete_interactive (buffer, &cursor, &end, TRUE);
    }
}
示例#3
0
static void
gimp_text_tool_move_cursor (GimpTextTool    *text_tool,
                            GtkMovementStep  step,
                            gint             count,
                            gboolean         extend_selection)
{
  GtkTextBuffer *buffer = GTK_TEXT_BUFFER (text_tool->buffer);
  GtkTextIter    cursor;
  GtkTextIter    selection;
  GtkTextIter   *sel_start;
  gboolean       cancel_selection = FALSE;
  gint           x_pos  = -1;

  GIMP_LOG (TEXT_EDITING, "%s count = %d, select = %s",
            g_enum_get_value (g_type_class_ref (GTK_TYPE_MOVEMENT_STEP),
                              step)->value_name,
            count,
            extend_selection ? "TRUE" : "FALSE");

  gtk_text_buffer_get_iter_at_mark (buffer, &cursor,
                                    gtk_text_buffer_get_insert (buffer));
  gtk_text_buffer_get_iter_at_mark (buffer, &selection,
                                    gtk_text_buffer_get_selection_bound (buffer));

  if (extend_selection)
    {
      sel_start = &selection;
    }
  else
    {
      /*  when there is a selection, moving the cursor without
       *  extending it should move the cursor to the end of the
       *  selection that is in moving direction
       */
      if (count > 0)
        gtk_text_iter_order (&selection, &cursor);
      else
        gtk_text_iter_order (&cursor, &selection);

      sel_start = &cursor;

      /* if we actually have a selection, just move *to* the beginning/end
       * of the selection and not *from* there on LOGICAL_POSITIONS
       * and VISUAL_POSITIONS movement
       */
      if (! gtk_text_iter_equal (&cursor, &selection))
        cancel_selection = TRUE;
    }

  switch (step)
    {
    case GTK_MOVEMENT_LOGICAL_POSITIONS:
      if (! cancel_selection)
        gtk_text_iter_forward_visible_cursor_positions (&cursor, count);
      break;

    case GTK_MOVEMENT_VISUAL_POSITIONS:
      if (! cancel_selection)
        {
          PangoLayout *layout;
          const gchar *text;

          if (! gimp_text_tool_ensure_layout (text_tool))
            break;

          layout = gimp_text_layout_get_pango_layout (text_tool->layout);
          text = pango_layout_get_text (layout);

          while (count != 0)
            {
              const gunichar word_joiner = 8288; /*g_utf8_get_char(WORD_JOINER);*/
              gint index;
              gint trailing = 0;
              gint new_index;

              index = gimp_text_buffer_get_iter_index (text_tool->buffer,
                                                       &cursor, TRUE);

              if (count > 0)
                {
                  if (g_utf8_get_char (text + index) == word_joiner)
                    pango_layout_move_cursor_visually (layout, TRUE,
                                                       index, 0, 1,
                                                       &new_index, &trailing);
                  else
                    new_index = index;

                  pango_layout_move_cursor_visually (layout, TRUE,
                                                     new_index, trailing, 1,
                                                     &new_index, &trailing);
                  count--;
                }
              else
                {
                  pango_layout_move_cursor_visually (layout, TRUE,
                                                     index, 0, -1,
                                                     &new_index, &trailing);

                  if (new_index != -1 && new_index != G_MAXINT &&
                      g_utf8_get_char (text + new_index) == word_joiner)
                    {
                      pango_layout_move_cursor_visually (layout, TRUE,
                                                         new_index, trailing, -1,
                                                         &new_index, &trailing);
                    }

                  count++;
                }

              if (new_index != G_MAXINT && new_index != -1)
                index = new_index;
              else
                break;

              gimp_text_buffer_get_iter_at_index (text_tool->buffer,
                                                  &cursor, index, TRUE);
              gtk_text_iter_forward_chars (&cursor, trailing);
            }
        }
      break;

    case GTK_MOVEMENT_WORDS:
      if (count < 0)
        {
          gtk_text_iter_backward_visible_word_starts (&cursor, -count);
        }
      else if (count > 0)
        {
	  if (! gtk_text_iter_forward_visible_word_ends (&cursor, count))
	    gtk_text_iter_forward_to_line_end (&cursor);
        }
      break;

    case GTK_MOVEMENT_DISPLAY_LINES:
      {
        GtkTextIter      start;
        GtkTextIter      end;
        gint             cursor_index;
        PangoLayout     *layout;
        PangoLayoutLine *layout_line;
        PangoLayoutIter *layout_iter;
        PangoRectangle   logical;
        gint             line;
        gint             trailing;
        gint             i;

        gtk_text_buffer_get_bounds (buffer, &start, &end);

        cursor_index = gimp_text_buffer_get_iter_index (text_tool->buffer,
                                                        &cursor, TRUE);

        if (! gimp_text_tool_ensure_layout (text_tool))
          break;

        layout = gimp_text_layout_get_pango_layout (text_tool->layout);

        pango_layout_index_to_line_x (layout, cursor_index, FALSE,
                                      &line, &x_pos);

        layout_iter = pango_layout_get_iter (layout);
        for (i = 0; i < line; i++)
          pango_layout_iter_next_line (layout_iter);

        pango_layout_iter_get_line_extents (layout_iter, NULL, &logical);

        x_pos += logical.x;

        pango_layout_iter_free (layout_iter);

        /*  try to go to the remembered x_pos if it exists *and* we are at
         *  the beginning or at the end of the current line
         */
        if (text_tool->x_pos != -1 && (x_pos <= logical.x ||
                                       x_pos >= logical.x + logical.width))
          x_pos = text_tool->x_pos;

        line += count;

        if (line < 0)
          {
            cursor = start;
            break;
          }
        else if (line >= pango_layout_get_line_count (layout))
          {
            cursor = end;
            break;
          }

        layout_iter = pango_layout_get_iter (layout);
        for (i = 0; i < line; i++)
          pango_layout_iter_next_line (layout_iter);

        layout_line = pango_layout_iter_get_line_readonly (layout_iter);
        pango_layout_iter_get_line_extents (layout_iter, NULL, &logical);

        pango_layout_iter_free (layout_iter);

        pango_layout_line_x_to_index (layout_line, x_pos - logical.x,
                                      &cursor_index, &trailing);

        gimp_text_buffer_get_iter_at_index (text_tool->buffer, &cursor,
                                            cursor_index, TRUE);

        while (trailing--)
          gtk_text_iter_forward_char (&cursor);
      }
      break;

    case GTK_MOVEMENT_PAGES: /* well... */
    case GTK_MOVEMENT_BUFFER_ENDS:
      if (count < 0)
        {
          gtk_text_buffer_get_start_iter (buffer, &cursor);
        }
      else if (count > 0)
        {
          gtk_text_buffer_get_end_iter (buffer, &cursor);
        }
      break;

    case GTK_MOVEMENT_PARAGRAPH_ENDS:
      if (count < 0)
        {
          gtk_text_iter_set_line_offset (&cursor, 0);
        }
      else if (count > 0)
        {
          if (! gtk_text_iter_ends_line (&cursor))
            gtk_text_iter_forward_to_line_end (&cursor);
        }
      break;

    case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
      if (count < 0)
        {
          gtk_text_iter_set_line_offset (&cursor, 0);
        }
      else if (count > 0)
        {
          if (! gtk_text_iter_ends_line (&cursor))
            gtk_text_iter_forward_to_line_end (&cursor);
        }
      break;

    default:
      return;
    }

  text_tool->x_pos = x_pos;

  gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));

  gimp_text_tool_reset_im_context (text_tool);

  gtk_text_buffer_select_range (buffer, &cursor, sel_start);

  gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
}
示例#4
0
void
gimp_text_tool_editor_motion (GimpTextTool *text_tool,
                              gdouble       x,
                              gdouble       y)
{
  GtkTextBuffer *buffer = GTK_TEXT_BUFFER (text_tool->buffer);
  GtkTextIter    old_cursor;
  GtkTextIter    old_selection;
  GtkTextIter    cursor;
  GtkTextIter    selection;

  gtk_text_buffer_get_iter_at_mark (buffer, &old_cursor,
                                    gtk_text_buffer_get_insert (buffer));
  gtk_text_buffer_get_iter_at_mark (buffer, &old_selection,
                                    gtk_text_buffer_get_selection_bound (buffer));

  gimp_text_tool_xy_to_iter (text_tool, x, y, &cursor);
  selection = text_tool->select_start_iter;

  if (text_tool->select_words ||
      text_tool->select_lines)
    {
      GtkTextIter start;
      GtkTextIter end;

      if (gtk_text_iter_compare (&cursor, &selection) < 0)
        {
          start = cursor;
          end   = selection;
        }
      else
        {
          start = selection;
          end   = cursor;
        }

      if (text_tool->select_words)
        {
          if (! gtk_text_iter_starts_word (&start))
            gtk_text_iter_backward_visible_word_starts (&start, 1);

          if (! gtk_text_iter_ends_word (&end) &&
              ! gtk_text_iter_forward_visible_word_ends (&end, 1))
            gtk_text_iter_forward_to_line_end (&end);
        }
      else if (text_tool->select_lines)
        {
          gtk_text_iter_set_line_offset (&start, 0);
          gtk_text_iter_forward_to_line_end (&end);
        }

      if (gtk_text_iter_compare (&cursor, &selection) < 0)
        {
          cursor    = start;
          selection = end;
        }
      else
        {
          selection = start;
          cursor    = end;
        }
    }

  if (! gtk_text_iter_equal (&cursor,    &old_cursor) ||
      ! gtk_text_iter_equal (&selection, &old_selection))
    {
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));

      gtk_text_buffer_select_range (buffer, &cursor, &selection);

      gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
    }
}
void
_ide_source_view_apply_movement (IdeSourceView         *self,
                                 IdeSourceViewMovement  movement,
                                 gboolean               extend_selection,
                                 gboolean               exclusive,
                                 guint                  count,
                                 gunichar               command,
                                 gunichar               modifier,
                                 gunichar               search_char,
                                 gint                  *target_offset)
{
  Movement mv = { 0 };
  GtkTextBuffer *buffer;
  GtkTextMark *insert;
  gsize i;

  g_return_if_fail (IDE_IS_SOURCE_VIEW (self));

#ifdef IDE_ENABLE_TRACE
  {
    GEnumValue *enum_value;
    GEnumClass *enum_class;

    enum_class = g_type_class_ref (IDE_TYPE_SOURCE_VIEW_MOVEMENT);
    enum_value = g_enum_get_value (enum_class, movement);
    IDE_TRACE_MSG ("movement(%s, extend_selection=%s, exclusive=%s, count=%u)",
                   enum_value->value_nick,
                   extend_selection ? "YES" : "NO",
                   exclusive ? "YES" : "NO",
                   count);
    g_type_class_unref (enum_class);
  }
#endif

  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self));
  insert = gtk_text_buffer_get_insert (buffer);

  mv.self = self;
  mv.target_offset = target_offset;
  mv.type = movement;
  mv.extend_selection = extend_selection;
  mv.exclusive = exclusive;
  mv.count = count;
  mv.ignore_select = FALSE;
  mv.ignore_target_offset = FALSE;
  mv.command = command;
  mv.modifier = modifier;

  ide_source_view_movements_get_selection (&mv);

  switch (movement)
    {
    case IDE_SOURCE_VIEW_MOVEMENT_PREVIOUS_OFFSET:
      gtk_text_iter_backward_chars (&mv.insert, MAX (1, mv.count));
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NEXT_OFFSET:
      gtk_text_iter_forward_chars (&mv.insert, MAX (1, mv.count));
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NTH_CHAR:
      ide_source_view_movements_nth_char (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_PREVIOUS_CHAR:
      ide_source_view_movements_previous_char (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NEXT_CHAR:
      ide_source_view_movements_next_char (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_FIRST_CHAR:
      ide_source_view_movements_first_char (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_FIRST_NONSPACE_CHAR:
      ide_source_view_movements_first_nonspace_char (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_MIDDLE_CHAR:
      ide_source_view_movements_middle_char (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_LAST_CHAR:
      ide_source_view_movements_last_char (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_PREVIOUS_FULL_WORD_START:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_previous_full_word_start (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NEXT_FULL_WORD_START:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_next_full_word_start (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_PREVIOUS_FULL_WORD_END:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_previous_full_word_end (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NEXT_FULL_WORD_END:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_next_full_word_end (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_PREVIOUS_SUB_WORD_START:
      gtk_text_iter_backward_visible_word_starts (&mv.insert, MAX (1, mv.count));
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NEXT_SUB_WORD_START:
      if (!gtk_text_iter_forward_visible_word_ends (&mv.insert, MAX (1, mv.count)))
        gtk_text_iter_forward_to_line_end (&mv.insert);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_PREVIOUS_WORD_START:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_previous_word_start (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NEXT_WORD_START:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_next_word_start (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_PREVIOUS_WORD_END:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_previous_word_end (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NEXT_WORD_END:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_next_word_end (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_SENTENCE_START:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_sentence_start (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_SENTENCE_END:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_sentence_end (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_PARAGRAPH_START:
      for (i = MAX (1, mv.count); i > 0; i--)
        {
          mv.exclusive = exclusive && i == 1;
          ide_source_view_movements_paragraph_start (&mv);
        }
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_PARAGRAPH_END:
      for (i = MAX (1, mv.count); i > 0; i--)
        {
          mv.exclusive = exclusive && i == 1;
          ide_source_view_movements_paragraph_end (&mv);
        }
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_PREVIOUS_LINE:
      mv.ignore_target_offset = TRUE;
      mv.ignore_select = TRUE;
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_previous_line (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NEXT_LINE:
      mv.ignore_target_offset = TRUE;
      mv.ignore_select = TRUE;
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_next_line (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_FIRST_LINE:
      ide_source_view_movements_first_line (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NTH_LINE:
      ide_source_view_movements_nth_line (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_LAST_LINE:
      ide_source_view_movements_last_line (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_LINE_PERCENTAGE:
      ide_source_view_movements_line_percentage (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_LINE_CHARS:
      ide_source_view_movements_line_chars (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_LINE_END:
      ide_source_view_movements_line_end (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_HALF_PAGE_UP:
    case IDE_SOURCE_VIEW_MOVEMENT_HALF_PAGE_DOWN:
    case IDE_SOURCE_VIEW_MOVEMENT_PAGE_UP:
    case IDE_SOURCE_VIEW_MOVEMENT_PAGE_DOWN:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_move_page (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_SCREEN_DOWN:
    case IDE_SOURCE_VIEW_MOVEMENT_SCREEN_UP:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_scroll (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_SCREEN_TOP:
      ide_source_view_movements_screen_top (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_SCREEN_MIDDLE:
      ide_source_view_movements_screen_middle (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_SCREEN_BOTTOM:
      ide_source_view_movements_screen_bottom (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_MATCH_SPECIAL:
      ide_source_view_movements_match_special (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_SCROLL_SCREEN_TOP:
    case IDE_SOURCE_VIEW_MOVEMENT_SCROLL_SCREEN_CENTER:
    case IDE_SOURCE_VIEW_MOVEMENT_SCROLL_SCREEN_BOTTOM:
      ide_source_view_movements_scroll_center (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_PREVIOUS_UNMATCHED_BRACE:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_previous_unmatched (&mv, '{', '}');
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NEXT_UNMATCHED_BRACE:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_next_unmatched (&mv, '}', '{');
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_PREVIOUS_UNMATCHED_PAREN:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_previous_unmatched (&mv, '(', ')');
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NEXT_UNMATCHED_PAREN:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_next_unmatched (&mv, ')', '(');
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NEXT_MATCH_MODIFIER:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_next_match_modifier (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_PREVIOUS_MATCH_MODIFIER:
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movements_previous_match_modifier (&mv);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_PREVIOUS_MATCH_SEARCH_CHAR:
      mv.modifier = search_char;
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movement_match_search_char (&mv, FALSE);
      break;

    case IDE_SOURCE_VIEW_MOVEMENT_NEXT_MATCH_SEARCH_CHAR:
      mv.modifier = search_char;
      for (i = MAX (1, mv.count); i > 0; i--)
        ide_source_view_movement_match_search_char (&mv, TRUE);
      break;

    default:
      g_return_if_reached ();
    }

  if (!mv.ignore_select)
    ide_source_view_movements_select_range (&mv);

  if (!mv.ignore_target_offset)
    *target_offset = gtk_text_iter_get_line_offset (&mv.insert);

  if (!mv.ignore_scroll_to_insert)
    ide_source_view_scroll_mark_onscreen (self, insert, TRUE, 0.5, 0.5);
}