[gnome-builder] sourceview: move by visual column
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] sourceview: move by visual column
- Date: Wed, 19 Apr 2017 00:51:09 +0000 (UTC)
commit 08573b8d549fb31f470d4e63b3863502357ecce2
Author: Andreas Brauchli <andreas brauchli sensirion com>
Date: Thu Apr 6 20:51:24 2017 +0200
sourceview: move by visual column
Change movements to stick to the visual column instead of the line
offset. This make movements between lines with different (or buggy)
indentation more coherent with what the user expects.
Column index 0 is the first column which is shown as column 1 to the
user (this reflects the previous offset behavior).
* Convert saved line offset instances to columns
* Make ide_source_view_get_visual_column a wrapper for GtkSourceView's
gtk_source_view_get_visual_column
* Use multiples of tab_width as tab stops. This might not universally hold
in the future but it's a good start.
* ide_source_view_get_iter_at_visual_column is based on the column
calculation of GtkSourceView's gtk_source_view_get_visual_column,
including the FIXME comment about invisible characters.
IdeSourceLocation positions remain in character offsets because
tab_width of different files might be different.
https://bugzilla.gnome.org/show_bug.cgi?id=781342
libide/sourceview/ide-source-view-movements.c | 53 ++++++------
libide/sourceview/ide-source-view-movements.h | 2 +-
libide/sourceview/ide-source-view.c | 121 ++++++++++++++++++-------
libide/sourceview/ide-source-view.h | 7 ++-
4 files changed, 121 insertions(+), 62 deletions(-)
---
diff --git a/libide/sourceview/ide-source-view-movements.c b/libide/sourceview/ide-source-view-movements.c
index 892f889..69b3de5 100644
--- a/libide/sourceview/ide-source-view-movements.c
+++ b/libide/sourceview/ide-source-view-movements.c
@@ -39,12 +39,11 @@
typedef struct
{
IdeSourceView *self;
- /* The target_offset contains the ideal character line_offset. This can
- * sometimes be further forward than designed when the line does not have
- * enough characters to get back to the original position. -1 indicates
- * no preference.
+ /* The target_column contains the ideal character column (visual offset).
+ * This can sometimes be further forward than designed when the line does not
+ * have enough characters to get back to the original position.
*/
- gint *target_offset;
+ guint *target_column;
IdeSourceViewMovement type; /* Type of movement */
GtkTextIter insert; /* Current insert cursor location */
GtkTextIter selection; /* Current selection cursor location */
@@ -56,7 +55,7 @@ typedef struct
guint extend_selection : 1; /* If selection should be extended */
guint exclusive : 1; /* See ":help exclusive" in vim */
guint ignore_select : 1; /* Don't update selection after movement */
- guint ignore_target_offset : 1; /* Don't propagate new line offset */
+ guint ignore_target_column : 1; /* Don't propagate new line column */
guint ignore_scroll_to_insert : 1; /* Don't scroll to insert mark */
} Movement;
@@ -500,7 +499,7 @@ ide_source_view_movements_next_line (Movement *mv)
GtkTextBuffer *buffer;
gboolean has_selection;
guint line;
- guint offset = 0;
+ guint column = *mv->target_column;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (mv->self));
@@ -509,9 +508,6 @@ ide_source_view_movements_next_line (Movement *mv)
line = gtk_text_iter_get_line (&mv->insert);
- if ((*mv->target_offset) > 0)
- offset = *mv->target_offset;
-
/*
* If we have a whole line selected (from say `V`), then we need to swap
* the cursor and selection. This feels to me like a slight bit of a hack.
@@ -542,10 +538,14 @@ ide_source_view_movements_next_line (Movement *mv)
if (is_single_char_selection (&mv->insert, &mv->selection))
{
if (gtk_text_iter_compare (&mv->insert, &mv->selection) < 0)
- *mv->target_offset = ++offset;
+ *mv->target_column = ++column;
}
- gtk_text_buffer_get_iter_at_line_offset (buffer, &mv->insert, line + 1, offset);
+ gtk_text_buffer_get_iter_at_line (buffer, &mv->insert, line + 1);
+ if (gtk_text_iter_get_line (&mv->insert) == line + 1)
+ ide_source_view_get_iter_at_visual_column (mv->self, *mv->target_column, &mv->insert);
+ else
+ gtk_text_buffer_get_end_iter (buffer, &mv->insert);
select_to_end:
@@ -573,7 +573,7 @@ ide_source_view_movements_previous_line (Movement *mv)
GtkTextBuffer *buffer;
gboolean has_selection;
guint line;
- guint offset = 0;
+ guint column = 0;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (mv->self));
@@ -582,8 +582,8 @@ ide_source_view_movements_previous_line (Movement *mv)
line = gtk_text_iter_get_line (&mv->insert);
- if ((*mv->target_offset) > 0)
- offset = *mv->target_offset;
+ if ((*mv->target_column) > 0)
+ column = *mv->target_column;
if (line == 0)
return FALSE;
@@ -607,16 +607,16 @@ ide_source_view_movements_previous_line (Movement *mv)
{
if (gtk_text_iter_compare (&mv->insert, &mv->selection) > 0)
{
- if (offset)
- --offset;
- *mv->target_offset = offset;
+ if (column)
+ --column;
+ *mv->target_column = column;
}
}
gtk_text_buffer_get_iter_at_line (buffer, &mv->insert, line - 1);
if (line == ((guint)gtk_text_iter_get_line (&mv->insert) + 1))
{
- gtk_text_buffer_get_iter_at_line_offset (buffer, &mv->insert, line - 1, offset);
+ ide_source_view_get_iter_at_visual_column (mv->self, column, &mv->insert);
if (has_selection)
{
@@ -1936,7 +1936,7 @@ _ide_source_view_apply_movement (IdeSourceView *self,
gunichar command,
gunichar modifier,
gunichar search_char,
- gint *target_offset)
+ guint *target_column)
{
Movement mv = { 0 };
GtkTextBuffer *buffer;
@@ -1945,6 +1945,7 @@ _ide_source_view_apply_movement (IdeSourceView *self,
gint min_count = 1;
gint end_line;
gsize i;
+ guint line;
g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
@@ -1981,13 +1982,13 @@ _ide_source_view_apply_movement (IdeSourceView *self,
end_line = gtk_text_iter_get_line (&end_iter);
mv.self = self;
- mv.target_offset = target_offset;
+ mv.target_column = target_column;
mv.type = movement;
mv.extend_selection = extend_selection;
mv.exclusive = exclusive;
mv.count = count;
mv.ignore_select = FALSE;
- mv.ignore_target_offset = FALSE;
+ mv.ignore_target_column = FALSE;
mv.command_str = command_str;
mv.command = command;
mv.modifier = modifier;
@@ -2115,7 +2116,7 @@ _ide_source_view_apply_movement (IdeSourceView *self,
break;
case IDE_SOURCE_VIEW_MOVEMENT_PREVIOUS_LINE:
- mv.ignore_target_offset = TRUE;
+ mv.ignore_target_column = TRUE;
mv.ignore_select = TRUE;
mv.count = MIN (mv.count, end_line);
/*
@@ -2129,7 +2130,7 @@ _ide_source_view_apply_movement (IdeSourceView *self,
break;
case IDE_SOURCE_VIEW_MOVEMENT_NEXT_LINE:
- mv.ignore_target_offset = TRUE;
+ mv.ignore_target_column = TRUE;
mv.ignore_select = TRUE;
mv.count = MIN (mv.count, end_line);
/*
@@ -2269,8 +2270,8 @@ _ide_source_view_apply_movement (IdeSourceView *self,
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_target_column)
+ ide_source_view_get_visual_position (mv.self, &line, target_column);
if (!mv.ignore_scroll_to_insert)
ide_source_view_scroll_mark_onscreen (self, insert, TRUE, 0.5, 0.5);
diff --git a/libide/sourceview/ide-source-view-movements.h b/libide/sourceview/ide-source-view-movements.h
index c867e4f..a24b2dc 100644
--- a/libide/sourceview/ide-source-view-movements.h
+++ b/libide/sourceview/ide-source-view-movements.h
@@ -32,7 +32,7 @@ void _ide_source_view_apply_movement (IdeSourceView *source_view,
gunichar command,
gunichar modifier,
gunichar search_char,
- gint *target_offset);
+ guint *target_column);
void _ide_source_view_select_inner (IdeSourceView *self,
gunichar inner_left,
diff --git a/libide/sourceview/ide-source-view.c b/libide/sourceview/ide-source-view.c
index b5d7c5b..3d7410a 100644
--- a/libide/sourceview/ide-source-view.c
+++ b/libide/sourceview/ide-source-view.c
@@ -131,7 +131,7 @@ typedef struct
guint change_sequence;
- gint target_line_offset;
+ guint target_line_column;
GString *command_str;
gunichar command;
gunichar modifier;
@@ -145,9 +145,9 @@ typedef struct
gint cached_char_width;
guint saved_line;
- guint saved_line_offset;
+ guint saved_line_column;
guint saved_selection_line;
- guint saved_selection_line_offset;
+ guint saved_selection_line_column;
GdkRGBA bubble_color1;
GdkRGBA bubble_color2;
@@ -337,7 +337,7 @@ static void ide_source_view_real_restore_insert_mark (IdeSourceView *sel
static void ide_source_view_real_set_mode (IdeSourceView *self,
const gchar *name,
IdeSourceViewModeType type);
-static void ide_source_view_save_offset (IdeSourceView *self);
+static void ide_source_view_save_column (IdeSourceView *self);
static void ide_source_view_maybe_overwrite (IdeSourceView *self,
GtkTextIter *iter,
const gchar *text,
@@ -1480,9 +1480,10 @@ ide_source_view__buffer_loaded_cb (IdeSourceView *self,
insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (buffer));
- /* Store the line offset so movements are correct. */
+ /* Store the line column (visual offset) so movements are correct. */
gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer), &iter, insert);
- priv->target_line_offset = gtk_text_iter_get_line_offset (&iter);
+ priv->target_line_column = gtk_source_view_get_visual_column (GTK_SOURCE_VIEW (self),
+ &iter);
/* Only scroll if the user hasn't started an intermediate scroll */
adj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (self));
@@ -2672,10 +2673,10 @@ ide_source_view_real_button_press_event (GtkWidget *widget,
}
/*
- * Update our target offset so movements don't cause us to revert
- * to the previous offset.
+ * Update our target column so movements don't cause us to revert
+ * to the previous column.
*/
- ide_source_view_save_offset (self);
+ ide_source_view_save_column (self);
return ret;
}
@@ -3163,7 +3164,7 @@ ide_source_view_real_delete_selection (IdeSourceView *self)
gtk_text_buffer_delete_selection (buffer, TRUE, editable);
}
- ide_source_view_save_offset (self);
+ ide_source_view_save_column (self);
}
static void
@@ -3326,7 +3327,7 @@ ide_source_view_real_jump (IdeSourceView *self,
GtkTextBuffer *buffer;
gchar *fragment;
guint line;
- guint line_offset;
+ guint line_column;
IDE_ENTRY;
@@ -3334,9 +3335,9 @@ ide_source_view_real_jump (IdeSourceView *self,
g_assert (location);
line = gtk_text_iter_get_line (location);
- line_offset = gtk_text_iter_get_line_offset (location);
+ line_column = ide_source_view_get_visual_column (self, location);
- IDE_TRACE_MSG ("Jump to %d:%d", line + 1, line_offset + 1);
+ IDE_TRACE_MSG ("Jump to %d:%d", line + 1, line_column + 1);
if (priv->back_forward_list == NULL)
IDE_EXIT;
@@ -3353,7 +3354,7 @@ ide_source_view_real_jump (IdeSourceView *self,
IDE_EXIT;
uri = ide_uri_new_from_file (ide_file_get_file (file));
- fragment = g_strdup_printf ("L%u_%u", line + 1, line_offset + 1);
+ fragment = g_strdup_printf ("L%u_%u", line + 1, line_column + 1);
ide_uri_set_fragment (uri, fragment);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self));
mark = gtk_text_buffer_create_mark (buffer, NULL, location, FALSE);
@@ -3381,7 +3382,7 @@ ide_source_view_real_paste_clipboard_extended (IdeSourceView *self,
GtkTextMark *insert;
GtkTextIter iter;
guint target_line;
- guint target_line_offset;
+ guint target_line_column;
/*
* NOTE:
@@ -3406,7 +3407,7 @@ ide_source_view_real_paste_clipboard_extended (IdeSourceView *self,
gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
target_line = gtk_text_iter_get_line (&iter);
- target_line_offset = gtk_text_iter_get_line_offset (&iter);
+ target_line_column = gtk_source_view_get_visual_column (GTK_SOURCE_VIEW (self), &iter);
gtk_text_buffer_begin_user_action (buffer);
@@ -3453,7 +3454,8 @@ ide_source_view_real_paste_clipboard_extended (IdeSourceView *self,
{
gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
target_line = gtk_text_iter_get_line (&iter);
- target_line_offset = gtk_text_iter_get_line_offset (&iter);
+ target_line_column = gtk_source_view_get_visual_column (GTK_SOURCE_VIEW (self),
+ &iter);
}
gtk_clipboard_set_text (clipboard, trimmed, -1);
@@ -3476,11 +3478,13 @@ ide_source_view_real_paste_clipboard_extended (IdeSourceView *self,
{
gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
target_line = gtk_text_iter_get_line (&iter);
- target_line_offset = gtk_text_iter_get_line_offset (&iter);
+ target_line_column = gtk_source_view_get_visual_column (GTK_SOURCE_VIEW (self),
+ &iter);
}
}
- gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, target_line, target_line_offset);
+ gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, target_line, 0);
+ ide_source_view_get_iter_at_visual_column (self, target_line_column, &iter);
gtk_text_buffer_select_range (buffer, &iter, &iter);
gtk_text_buffer_end_user_action (buffer);
@@ -3527,7 +3531,7 @@ ide_source_view_real_selection_theatric (IdeSourceView *self,
}
static void
-ide_source_view_save_offset (IdeSourceView *self)
+ide_source_view_save_column (IdeSourceView *self)
{
IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
GtkTextView *text_view = (GtkTextView *)self;
@@ -3540,7 +3544,7 @@ ide_source_view_save_offset (IdeSourceView *self)
buffer = gtk_text_view_get_buffer (text_view);
insert = gtk_text_buffer_get_insert (buffer);
gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
- priv->target_line_offset = gtk_text_iter_get_line_offset (&iter);
+ priv->target_line_column = ide_source_view_get_visual_column (self, &iter);
}
static void
@@ -3588,7 +3592,7 @@ ide_source_view_real_set_mode (IdeSourceView *self,
}
#endif
- ide_source_view_save_offset (self);
+ ide_source_view_save_column (self);
if (priv->mode)
{
@@ -3679,7 +3683,7 @@ ide_source_view_real_movement (IdeSourceView *self,
priv->command,
priv->modifier,
priv->search_char,
- &priv->target_line_offset);
+ &priv->target_line_column);
}
static void
@@ -4036,11 +4040,15 @@ ide_source_view_real_restore_insert_mark_full (IdeSourceView *self,
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self));
- gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, priv->saved_line, priv->saved_line_offset);
+ gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, priv->saved_line, 0);
+ ide_source_view_get_iter_at_visual_column (self, priv->saved_line_column, &iter);
gtk_text_buffer_get_iter_at_line_offset (buffer,
&selection,
priv->saved_selection_line,
- priv->saved_selection_line_offset);
+ 0);
+ ide_source_view_get_iter_at_visual_column (self,
+ priv->saved_selection_line_column,
+ &selection);
gtk_text_buffer_select_range (buffer, &iter, &selection);
@@ -4081,11 +4089,11 @@ ide_source_view_real_save_insert_mark (IdeSourceView *self)
gtk_text_buffer_get_iter_at_mark (buffer, &selection, selection_bound);
priv->saved_line = gtk_text_iter_get_line (&iter);
- priv->saved_line_offset = gtk_text_iter_get_line_offset (&iter);
+ priv->saved_line_column = ide_source_view_get_visual_column (self, &iter);
priv->saved_selection_line = gtk_text_iter_get_line (&selection);
- priv->saved_selection_line_offset = gtk_text_iter_get_line_offset (&selection);
+ priv->saved_selection_line_column = ide_source_view_get_visual_column (self, &selection);
- priv->target_line_offset = priv->saved_line_offset;
+ priv->target_line_column = priv->saved_line_column;
}
static void
@@ -4977,7 +4985,7 @@ ide_source_view_focus_in_event (GtkWidget *widget,
if (!workbench || ide_workbench_get_selection_owner (workbench) != G_OBJECT (self))
{
priv->saved_selection_line = priv->saved_line;
- priv->saved_selection_line_offset = priv->saved_line_offset;
+ priv->saved_selection_line_column = priv->saved_line_column;
}
ide_source_view_real_restore_insert_mark_full (self, FALSE);
@@ -7365,7 +7373,7 @@ ide_source_view_init (IdeSourceView *self)
EGG_COUNTER_INC (instances);
- priv->target_line_offset = -1;
+ priv->target_line_column = 0;
priv->snippets = g_queue_new ();
priv->selections = g_queue_new ();
priv->show_line_diagnostics = TRUE;
@@ -7668,6 +7676,39 @@ ide_source_view_get_insert_matching_brace (IdeSourceView *self)
return priv->insert_matching_brace;
}
+void
+ide_source_view_get_iter_at_visual_column (IdeSourceView *self,
+ guint column,
+ GtkTextIter *location)
+{
+ gunichar tab_char;
+ guint visual_col = 0;
+ guint tab_width;
+
+ g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
+
+ tab_char = g_utf8_get_char ("\t");
+ tab_width = gtk_source_view_get_tab_width (GTK_SOURCE_VIEW (self));
+ gtk_text_iter_set_line_offset (location, 0);
+
+ while (!gtk_text_iter_ends_line (location))
+ {
+ if (gtk_text_iter_get_char (location) == tab_char)
+ visual_col += (tab_width - (visual_col % tab_width));
+ else
+ ++visual_col;
+
+ if (visual_col > column)
+ break;
+
+ /* FIXME: this does not handle invisible text correctly, but
+ * * gtk_text_iter_forward_visible_cursor_position is too
+ * slow */
+ if (!gtk_text_iter_forward_char (location))
+ break;
+ }
+}
+
const gchar *
ide_source_view_get_mode_name (IdeSourceView *self)
{
@@ -8703,10 +8744,19 @@ ide_source_view_set_highlight_current_line (IdeSourceView *self,
}
}
+guint
+ide_source_view_get_visual_column (IdeSourceView *self,
+ const GtkTextIter *location)
+{
+ g_return_val_if_fail (IDE_IS_SOURCE_VIEW (self), 0);
+
+ return gtk_source_view_get_visual_column(GTK_SOURCE_VIEW (self), location);
+}
+
void
ide_source_view_get_visual_position (IdeSourceView *self,
guint *line,
- guint *column)
+ guint *line_column)
{
IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
GtkTextBuffer *buffer;
@@ -8717,7 +8767,10 @@ ide_source_view_get_visual_position (IdeSourceView *self,
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self));
if (!gtk_widget_has_focus (GTK_WIDGET (self)))
- gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, priv->saved_line, priv->saved_line_offset);
+ {
+ gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, priv->saved_line, 0);
+ ide_source_view_get_iter_at_visual_column (self, priv->saved_line_column, &iter);
+ }
else
{
GtkTextMark *mark;
@@ -8729,8 +8782,8 @@ ide_source_view_get_visual_position (IdeSourceView *self,
if (line)
*line = gtk_text_iter_get_line (&iter);
- if (column)
- *column = gtk_source_view_get_visual_column (GTK_SOURCE_VIEW (self), &iter);
+ if (line_column)
+ *line_column = gtk_source_view_get_visual_column (GTK_SOURCE_VIEW (self), &iter);
}
void
diff --git a/libide/sourceview/ide-source-view.h b/libide/sourceview/ide-source-view.h
index 8684bfe..c898f23 100644
--- a/libide/sourceview/ide-source-view.h
+++ b/libide/sourceview/ide-source-view.h
@@ -328,15 +328,20 @@ struct _IdeSourceViewClass
void ide_source_view_clear_snippets (IdeSourceView *self);
IdeSourceSnippet *ide_source_view_get_current_snippet (IdeSourceView *self);
IdeBackForwardList *ide_source_view_get_back_forward_list (IdeSourceView *self);
+guint ide_source_view_get_visual_column (IdeSourceView *self,
+ const GtkTextIter *location);
void ide_source_view_get_visual_position (IdeSourceView *self,
guint *line,
- guint
*line_offset);
+ guint
*line_column);
gint ide_source_view_get_count (IdeSourceView *self);
gboolean ide_source_view_get_enable_word_completion(IdeSourceView *self);
IdeFileSettings *ide_source_view_get_file_settings (IdeSourceView *self);
const PangoFontDescription *ide_source_view_get_font_desc (IdeSourceView *self);
gboolean ide_source_view_get_highlight_current_line(IdeSourceView *self);
gboolean ide_source_view_get_insert_matching_brace (IdeSourceView *self);
+void ide_source_view_get_iter_at_visual_column (IdeSourceView *self,
+ guint column,
+ GtkTextIter *location);
const gchar *ide_source_view_get_mode_display_name (IdeSourceView *self);
const gchar *ide_source_view_get_mode_name (IdeSourceView *self);
gboolean ide_source_view_get_overwrite_braces (IdeSourceView *self);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]