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.
This commit is contained in:
okaestne 2021-04-11 22:11:58 +02:00 committed by Michael Webster
parent 423f214a70
commit 5b7c1d936e
7 changed files with 418 additions and 3 deletions

View File

@ -167,6 +167,36 @@
<description>Whether xed will ensure that documents always end with a trailing newline.</description> <description>Whether xed will ensure that documents always end with a trailing newline.</description>
</key> </key>
<key name="draw-whitespace" type="b">
<default>false</default>
<summary>Draw whitespace</summary>
<description>Whether xed should render whitespace</description>
</key>
<key name="draw-whitespace-leading" type="b">
<default>false</default>
<summary>Draw leading whitespace</summary>
<description>Whether xed should render leading whitespace</description>
</key>
<key name="draw-whitespace-inside" type="b">
<default>false</default>
<summary>Draw whitespace within text</summary>
<description>Whether xed should render whitespace between words and characters</description>
</key>
<key name="draw-whitespace-trailing" type="b">
<default>false</default>
<summary>Draw trailing whitespace</summary>
<description>Whether xed should render trailing whitespace</description>
</key>
<key name="draw-whitespace-newline" type="b">
<default>false</default>
<summary>Draw newline characters</summary>
<description>Whether xed should render newline characters</description>
</key>
</schema> </schema>
<schema gettext-domain="@GETTEXT_PACKAGE@" id="org.x.editor.preferences.ui" path="/org/x/editor/preferences/ui/"> <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.x.editor.preferences.ui" path="/org/x/editor/preferences/ui/">

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 --> <!-- Generated with glade 3.22.2 -->
<interface> <interface>
<requires lib="gtk+" version="3.12"/> <requires lib="gtk+" version="3.12"/>
<requires lib="gtksourceview" version="3.0"/> <requires lib="gtksourceview" version="3.0"/>
@ -309,6 +309,210 @@
<property name="position">3</property> <property name="position">3</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkBox" id="draw_whitespace_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">6</property>
<child>
<object class="GtkLabel" id="draw_whitespace_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Draw whitespace</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="draw_whitespace_switch">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkRevealer" id="draw_whitespace_revealer">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_duration">175</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">16</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="draw_whitespace_leading_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">6</property>
<child>
<object class="GtkLabel" id="draw_whitespace_leading_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Leading whitespace</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="draw_whitespace_leading_switch">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="draw_whitespace_trailing_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">6</property>
<child>
<object class="GtkLabel" id="draw_whitespace_trailing_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Trailing whitespace</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="draw_whitespace_trailing_switch">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="draw_whitespace_inside_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">6</property>
<child>
<object class="GtkLabel" id="draw_whitespace_inside_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Whitespace inside of text</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="draw_whitespace_inside_switch">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="draw_whitespace_newline_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">6</property>
<child>
<object class="GtkLabel" id="draw_whitespace_newline_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Newline character</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="draw_whitespace_newline_switch">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>

View File

@ -99,6 +99,14 @@ struct _XedPreferencesDialog
GtkWidget *right_margin_spin; GtkWidget *right_margin_spin;
GtkWidget *right_margin_revealer; 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 */ /* Highlight current line */
GtkWidget *highlight_current_line_switch; 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, 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_spin);
gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, right_margin_revealer); 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_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, highlight_matching_bracket_switch);
gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, tab_width_spin); gtk_widget_class_bind_template_child (widget_class, XedPreferencesDialog, tab_width_spin);
@ -317,6 +331,44 @@ setup_editor_page (XedPreferencesDialog *dlg)
"value", "value",
G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); 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 */ /* Highlighting */
g_settings_bind (dlg->editor_settings, g_settings_bind (dlg->editor_settings,
XED_SETTINGS_HIGHLIGHT_CURRENT_LINE, XED_SETTINGS_HIGHLIGHT_CURRENT_LINE,

View File

@ -331,6 +331,32 @@ on_max_recents_changed (GSettings *settings,
* update of the inline recents in the File menu */ * 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 static void
xed_settings_init (XedSettings *xs) xed_settings_init (XedSettings *xs)
{ {
@ -361,10 +387,20 @@ xed_settings_init (XedSettings *xs)
G_CALLBACK (on_auto_save_interval_changed), xs); G_CALLBACK (on_auto_save_interval_changed), xs);
g_signal_connect (xs->priv->editor, "changed::syntax-highlighting", g_signal_connect (xs->priv->editor, "changed::syntax-highlighting",
G_CALLBACK (on_syntax_highlighting_changed), xs); G_CALLBACK (on_syntax_highlighting_changed), xs);
g_signal_connect (xs->priv->ui, "changed::enable-tab-scrolling", g_signal_connect (xs->priv->editor, "changed::draw-whitespace",
G_CALLBACK (on_enable_tab_scrolling_changed), xs); 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 */ /* 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_signal_connect (xs->priv->ui, "changed::max-recents",
G_CALLBACK (on_max_recents_changed), xs); G_CALLBACK (on_max_recents_changed), xs);
} }

View File

@ -88,6 +88,11 @@ void xed_settings_set_list (GSettings *settings,
#define XED_SETTINGS_BRACKET_MATCHING "bracket-matching" #define XED_SETTINGS_BRACKET_MATCHING "bracket-matching"
#define XED_SETTINGS_DISPLAY_RIGHT_MARGIN "display-right-margin" #define XED_SETTINGS_DISPLAY_RIGHT_MARGIN "display-right-margin"
#define XED_SETTINGS_RIGHT_MARGIN_POSITION "right-margin-position" #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_SMART_HOME_END "smart-home-end"
#define XED_SETTINGS_WRITABLE_VFS_SCHEMES "writable-vfs-schemes" #define XED_SETTINGS_WRITABLE_VFS_SCHEMES "writable-vfs-schemes"
#define XED_SETTINGS_RESTORE_CURSOR_POSITION "restore-cursor-position" #define XED_SETTINGS_RESTORE_CURSOR_POSITION "restore-cursor-position"

View File

@ -162,6 +162,7 @@ xed_view_constructed (GObject *object)
XedViewPrivate *priv; XedViewPrivate *priv;
gboolean use_default_font; gboolean use_default_font;
GtkSourceGutter *gutter; GtkSourceGutter *gutter;
gboolean draw_whitespace;
view = XED_VIEW (object); view = XED_VIEW (object);
priv = view->priv; priv = view->priv;
@ -241,6 +242,15 @@ xed_view_constructed (GObject *object)
"smart-home-end", "smart-home-end",
G_SETTINGS_BIND_GET); 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), g_object_set (G_OBJECT (view),
"indent_on_tab", TRUE, "indent_on_tab", TRUE,
NULL); NULL);
@ -830,3 +840,79 @@ xed_view_set_font (XedView *view,
gtk_widget_modify_font (GTK_WIDGET (view), font_desc); gtk_widget_modify_font (GTK_WIDGET (view), font_desc);
pango_font_description_free (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);
}

View File

@ -61,6 +61,8 @@ void xed_view_delete_selection (XedView *view);
void xed_view_select_all (XedView *view); void xed_view_select_all (XedView *view);
void xed_view_scroll_to_cursor (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_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 G_END_DECLS