From 5b7c1d936e257bf870c2c01a3d1055254b4811da Mon Sep 17 00:00:00 2001 From: okaestne Date: Sun, 11 Apr 2021 22:11:58 +0200 Subject: [PATCH] Implement #225: Options to render whitespace Add preferences to enable displaying whitespace (tabs, spaces, nbsp and newlines). Options allow to choose locations (leading, inside text, trailing) of whitespace to display and to disable rendering of newline chars. --- data/org.x.editor.gschema.xml.in | 30 +++ xed/resources/ui/xed-preferences-dialog.ui | 206 ++++++++++++++++++++- xed/xed-preferences-dialog.c | 52 ++++++ xed/xed-settings.c | 40 +++- xed/xed-settings.h | 5 + xed/xed-view.c | 86 +++++++++ xed/xed-view.h | 2 + 7 files changed, 418 insertions(+), 3 deletions(-) diff --git a/data/org.x.editor.gschema.xml.in b/data/org.x.editor.gschema.xml.in index d16e3df..575b430 100644 --- a/data/org.x.editor.gschema.xml.in +++ b/data/org.x.editor.gschema.xml.in @@ -167,6 +167,36 @@ Whether xed will ensure that documents always end with a trailing newline. + + false + Draw whitespace + Whether xed should render whitespace + + + + false + Draw leading whitespace + Whether xed should render leading whitespace + + + + false + Draw whitespace within text + Whether xed should render whitespace between words and characters + + + + false + Draw trailing whitespace + Whether xed should render trailing whitespace + + + + false + Draw newline characters + Whether xed should render newline characters + + diff --git a/xed/resources/ui/xed-preferences-dialog.ui b/xed/resources/ui/xed-preferences-dialog.ui index 3fa8168..2929d33 100644 --- a/xed/resources/ui/xed-preferences-dialog.ui +++ b/xed/resources/ui/xed-preferences-dialog.ui @@ -1,5 +1,5 @@ - + @@ -309,6 +309,210 @@ 3 + + + True + False + 6 + + + True + False + Draw whitespace + + + False + True + 0 + + + + + True + True + + + False + True + end + 1 + + + + + False + True + 5 + + + + + True + False + 175 + + + True + False + 16 + vertical + + + True + False + 6 + + + True + False + Leading whitespace + 0 + + + False + True + 0 + + + + + True + True + + + False + True + end + 1 + + + + + False + True + 0 + + + + + True + False + 6 + + + True + False + Trailing whitespace + 0 + + + False + True + 0 + + + + + True + True + + + False + True + end + 1 + + + + + False + True + 1 + + + + + True + False + 6 + + + True + False + Whitespace inside of text + 0 + + + False + True + 0 + + + + + True + True + + + False + True + end + 1 + + + + + False + True + 2 + + + + + True + False + 6 + + + True + False + Newline character + 0 + + + False + True + 0 + + + + + True + True + + + False + True + end + 1 + + + + + False + True + 3 + + + + + + + False + True + 6 + + False diff --git a/xed/xed-preferences-dialog.c b/xed/xed-preferences-dialog.c index b060b8a..fe44e45 100644 --- a/xed/xed-preferences-dialog.c +++ b/xed/xed-preferences-dialog.c @@ -99,6 +99,14 @@ struct _XedPreferencesDialog GtkWidget *right_margin_spin; GtkWidget *right_margin_revealer; + /* Draw whitespace */ + GtkWidget *draw_whitespace_switch; + GtkWidget *draw_whitespace_revealer; + GtkWidget *draw_whitespace_leading_switch; + GtkWidget *draw_whitespace_trailing_switch; + GtkWidget *draw_whitespace_inside_switch; + GtkWidget *draw_whitespace_newline_switch; + /* Highlight current line */ GtkWidget *highlight_current_line_switch; @@ -169,6 +177,12 @@ xed_preferences_dialog_class_init (XedPreferencesDialogClass *klass) gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, display_right_margin_switch); gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, right_margin_spin); gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, right_margin_revealer); + gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, draw_whitespace_switch); + gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, draw_whitespace_revealer); + gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, draw_whitespace_leading_switch); + gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, draw_whitespace_trailing_switch); + gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, draw_whitespace_inside_switch); + gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, draw_whitespace_newline_switch); gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, highlight_current_line_switch); gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, highlight_matching_bracket_switch); gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, tab_width_spin); @@ -317,6 +331,44 @@ setup_editor_page (XedPreferencesDialog *dlg) "value", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + /* whitespace */ + + g_settings_bind (dlg->editor_settings, + XED_SETTINGS_DRAW_WHITESPACE, + dlg->draw_whitespace_switch, + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + g_object_bind_property (dlg->draw_whitespace_switch, + "active", + dlg->draw_whitespace_revealer, + "reveal-child", + G_BINDING_SYNC_CREATE | G_BINDING_DEFAULT); + + g_settings_bind (dlg->editor_settings, + XED_SETTINGS_DRAW_WHITESPACE_LEADING, + dlg->draw_whitespace_leading_switch, + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + g_settings_bind (dlg->editor_settings, + XED_SETTINGS_DRAW_WHITESPACE_TRAILING, + dlg->draw_whitespace_trailing_switch, + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + g_settings_bind (dlg->editor_settings, + XED_SETTINGS_DRAW_WHITESPACE_INSIDE, + dlg->draw_whitespace_inside_switch, + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + g_settings_bind (dlg->editor_settings, + XED_SETTINGS_DRAW_WHITESPACE_NEWLINE, + dlg->draw_whitespace_newline_switch, + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + /* Highlighting */ g_settings_bind (dlg->editor_settings, XED_SETTINGS_HIGHLIGHT_CURRENT_LINE, diff --git a/xed/xed-settings.c b/xed/xed-settings.c index 3168dac..5002a42 100644 --- a/xed/xed-settings.c +++ b/xed/xed-settings.c @@ -331,6 +331,32 @@ on_max_recents_changed (GSettings *settings, * update of the inline recents in the File menu */ } +static void +on_draw_whitespace_changed (GSettings *settings, + const gchar *key, + XedSettings *xs) +{ + GList *views; + gboolean draw_whitespace; + + views = xed_app_get_views (XED_APP (g_application_get_default ())); + draw_whitespace = g_settings_get_boolean (settings, key); + + g_list_foreach (views, (GFunc)xed_view_set_draw_whitespace, GINT_TO_POINTER (draw_whitespace)); +} + +static void +on_draw_whitespace_locations_or_types_changed (GSettings *settings, + const gchar *key, + XedSettings *xs) +{ + GList *views; + + views = xed_app_get_views (XED_APP (g_application_get_default ())); + + g_list_foreach (views, (GFunc)xed_view_update_draw_whitespace_locations_and_types, NULL); +} + static void xed_settings_init (XedSettings *xs) { @@ -361,10 +387,20 @@ xed_settings_init (XedSettings *xs) G_CALLBACK (on_auto_save_interval_changed), xs); g_signal_connect (xs->priv->editor, "changed::syntax-highlighting", G_CALLBACK (on_syntax_highlighting_changed), xs); - g_signal_connect (xs->priv->ui, "changed::enable-tab-scrolling", - G_CALLBACK (on_enable_tab_scrolling_changed), xs); + g_signal_connect (xs->priv->editor, "changed::draw-whitespace", + G_CALLBACK (on_draw_whitespace_changed), xs); + g_signal_connect (xs->priv->editor, "changed::draw-whitespace-leading", + G_CALLBACK (on_draw_whitespace_locations_or_types_changed), xs); + g_signal_connect (xs->priv->editor, "changed::draw-whitespace-trailing", + G_CALLBACK (on_draw_whitespace_locations_or_types_changed), xs); + g_signal_connect (xs->priv->editor, "changed::draw-whitespace-inside", + G_CALLBACK (on_draw_whitespace_locations_or_types_changed), xs); + g_signal_connect (xs->priv->editor, "changed::draw-whitespace-newline", + G_CALLBACK (on_draw_whitespace_locations_or_types_changed), xs); /* ui changes */ + g_signal_connect (xs->priv->ui, "changed::enable-tab-scrolling", + G_CALLBACK (on_enable_tab_scrolling_changed), xs); g_signal_connect (xs->priv->ui, "changed::max-recents", G_CALLBACK (on_max_recents_changed), xs); } diff --git a/xed/xed-settings.h b/xed/xed-settings.h index 9114a33..8106ca5 100644 --- a/xed/xed-settings.h +++ b/xed/xed-settings.h @@ -88,6 +88,11 @@ void xed_settings_set_list (GSettings *settings, #define XED_SETTINGS_BRACKET_MATCHING "bracket-matching" #define XED_SETTINGS_DISPLAY_RIGHT_MARGIN "display-right-margin" #define XED_SETTINGS_RIGHT_MARGIN_POSITION "right-margin-position" +#define XED_SETTINGS_DRAW_WHITESPACE "draw-whitespace" +#define XED_SETTINGS_DRAW_WHITESPACE_LEADING "draw-whitespace-leading" +#define XED_SETTINGS_DRAW_WHITESPACE_TRAILING "draw-whitespace-trailing" +#define XED_SETTINGS_DRAW_WHITESPACE_INSIDE "draw-whitespace-inside" +#define XED_SETTINGS_DRAW_WHITESPACE_NEWLINE "draw-whitespace-newline" #define XED_SETTINGS_SMART_HOME_END "smart-home-end" #define XED_SETTINGS_WRITABLE_VFS_SCHEMES "writable-vfs-schemes" #define XED_SETTINGS_RESTORE_CURSOR_POSITION "restore-cursor-position" diff --git a/xed/xed-view.c b/xed/xed-view.c index ca4d3fe..43581cd 100644 --- a/xed/xed-view.c +++ b/xed/xed-view.c @@ -162,6 +162,7 @@ xed_view_constructed (GObject *object) XedViewPrivate *priv; gboolean use_default_font; GtkSourceGutter *gutter; + gboolean draw_whitespace; view = XED_VIEW (object); priv = view->priv; @@ -241,6 +242,15 @@ xed_view_constructed (GObject *object) "smart-home-end", G_SETTINGS_BIND_GET); + draw_whitespace = g_settings_get_boolean (priv->editor_settings, XED_SETTINGS_DRAW_WHITESPACE); + + if (draw_whitespace) + { + xed_view_set_draw_whitespace (view, draw_whitespace); + } + + xed_view_update_draw_whitespace_locations_and_types (view); + g_object_set (G_OBJECT (view), "indent_on_tab", TRUE, NULL); @@ -830,3 +840,79 @@ xed_view_set_font (XedView *view, gtk_widget_modify_font (GTK_WIDGET (view), font_desc); pango_font_description_free (font_desc); } + +static guint +xed_view_get_draw_whitespace_locations_from_settings (GSettings* settings) +{ + guint locations; + + locations = 0; + + locations |= g_settings_get_boolean (settings, XED_SETTINGS_DRAW_WHITESPACE_LEADING) + ? GTK_SOURCE_SPACE_LOCATION_LEADING : 0; + locations |= g_settings_get_boolean (settings, XED_SETTINGS_DRAW_WHITESPACE_INSIDE) + ? GTK_SOURCE_SPACE_LOCATION_INSIDE_TEXT : 0; + locations |= g_settings_get_boolean (settings, XED_SETTINGS_DRAW_WHITESPACE_TRAILING) + ? GTK_SOURCE_SPACE_LOCATION_TRAILING : 0; + + return locations; +} + +static guint +xed_view_get_draw_whitespace_types_from_settings (GSettings* settings) +{ + if (!g_settings_get_boolean (settings, XED_SETTINGS_DRAW_WHITESPACE_NEWLINE)) + { + return GTK_SOURCE_SPACE_TYPE_ALL & ~GTK_SOURCE_SPACE_TYPE_NEWLINE; + } + + return GTK_SOURCE_SPACE_TYPE_ALL; +} + +/** + * xed_view_set_draw_whitespace: + * @view: a #XedView + * @enable: whether whitespace should be drawn + * + * Enables or disables rendering of any whitespace. + * The locations and types of whitespace to render is set by + * xed_view_update_draw_whitespace_locations_and_types() + * + **/ + +void +xed_view_set_draw_whitespace (XedView *view, gboolean enable) +{ + GtkSourceSpaceDrawer *spacedrawer; + + spacedrawer = gtk_source_view_get_space_drawer (GTK_SOURCE_VIEW (view)); + gtk_source_space_drawer_set_enable_matrix (spacedrawer, enable); +} + + +/** + * xed_view_update_draw_whitespace_locations_and_types: + * @view: a #XedView + * + * Updates the view to render whitespace at the locations and for types + * set in the preferences + * + **/ + +void +xed_view_update_draw_whitespace_locations_and_types (XedView *view) +{ + GtkSourceSpaceDrawer *spacedrawer; + guint locations, types; + + spacedrawer = gtk_source_view_get_space_drawer (GTK_SOURCE_VIEW (view)); + locations = xed_view_get_draw_whitespace_locations_from_settings (view->priv->editor_settings); + types = xed_view_get_draw_whitespace_types_from_settings (view->priv->editor_settings); + + // disable other locations + gtk_source_space_drawer_set_types_for_locations (spacedrawer, + GTK_SOURCE_SPACE_LOCATION_ALL & ~locations, + GTK_SOURCE_SPACE_TYPE_NONE); + // enable chosen locations and types + gtk_source_space_drawer_set_types_for_locations (spacedrawer, locations, types); +} diff --git a/xed/xed-view.h b/xed/xed-view.h index eab7295..1a0ef86 100644 --- a/xed/xed-view.h +++ b/xed/xed-view.h @@ -61,6 +61,8 @@ void xed_view_delete_selection (XedView *view); void xed_view_select_all (XedView *view); void xed_view_scroll_to_cursor (XedView *view); void xed_view_set_font (XedView *view, gboolean def, const gchar *font_name); +void xed_view_set_draw_whitespace (XedView *view, gboolean enable); +void xed_view_update_draw_whitespace_locations_and_types (XedView *view); G_END_DECLS