Strip the line trailing spaces at newline

From: Catalin Marinas <catalin.marinas@gmail.com>

This patch allows the automated stripping of the trailing spaces from
a line when <newline> is inserted. It adds an editor preference
checkbox and a pref_editor_newline_strip configuration option (off by
default).
---

 geany.glade     |   20 ++++++++++++++++++++
 src/document.c  |   38 ++++++++++++++++++++++----------------
 src/document.h  |    2 ++
 src/editor.c    |    7 +++++++
 src/editor.h    |    1 +
 src/interface.c |    8 ++++++++
 src/keyfile.c   |    2 ++
 src/prefs.c     |    6 ++++++
 8 files changed, 68 insertions(+), 16 deletions(-)


diff --git a/geany.glade b/geany.glade
index fcf31ac..8f255cd 100644
--- a/geany.glade
+++ b/geany.glade
@@ -5776,6 +5776,26 @@ Match braces</property>
 			      <property name="fill">False</property>
 			    </packing>
 			  </child>
+
+			  <child>
+			    <widget class="GtkCheckButton" id="check_newline_strip">
+			      <property name="visible">True</property>
+			      <property name="tooltip" translatable="yes">Enable newline to strip the trailing spaces on the previous line.</property>
+			      <property name="can_focus">True</property>
+			      <property name="label" translatable="yes">Newline strips trailing spaces</property>
+			      <property name="use_underline">True</property>
+			      <property name="relief">GTK_RELIEF_NORMAL</property>
+			      <property name="focus_on_click">False</property>
+			      <property name="active">False</property>
+			      <property name="inconsistent">False</property>
+			      <property name="draw_indicator">True</property>
+			    </widget>
+			    <packing>
+			      <property name="padding">0</property>
+			      <property name="expand">False</property>
+			      <property name="fill">False</property>
+			    </packing>
+			  </child>
 			</widget>
 		      </child>
 		    </widget>
diff --git a/src/document.c b/src/document.c
index 20b9dd9..5add346 100644
--- a/src/document.c
+++ b/src/document.c
@@ -2016,6 +2016,27 @@ void document_replace_tabs(gint idx)
 }
 
 
+void document_strip_line_trailing_spaces(gint idx, gint line)
+{
+	gint line_start = sci_get_position_from_line(doc_list[idx].sci, line);
+	gint line_end = sci_get_line_end_position(doc_list[idx].sci, line);
+	gint i = line_end - 1;
+	gchar ch = sci_get_char_at(doc_list[idx].sci, i);
+
+	while ((i >= line_start) && ((ch == ' ') || (ch == '\t')))
+	{
+		i--;
+		ch = sci_get_char_at(doc_list[idx].sci, i);
+	}
+	if (i < (line_end-1))
+	{
+		sci_target_start(doc_list[idx].sci, i + 1);
+		sci_target_end(doc_list[idx].sci, line_end);
+		sci_target_replace(doc_list[idx].sci, "", FALSE);
+	}
+}
+
+
 void document_strip_trailing_spaces(gint idx)
 {
 	gint max_lines = sci_get_line_count(doc_list[idx].sci);
@@ -2025,22 +2046,7 @@ void document_strip_trailing_spaces(gint idx)
 
 	for (line = 0; line < max_lines; line++)
 	{
-		gint line_start = sci_get_position_from_line(doc_list[idx].sci, line);
-		gint line_end = sci_get_line_end_position(doc_list[idx].sci, line);
-		gint i = line_end - 1;
-		gchar ch = sci_get_char_at(doc_list[idx].sci, i);
-
-		while ((i >= line_start) && ((ch == ' ') || (ch == '\t')))
-		{
-			i--;
-			ch = sci_get_char_at(doc_list[idx].sci, i);
-		}
-		if (i < (line_end-1))
-		{
-			sci_target_start(doc_list[idx].sci, i + 1);
-			sci_target_end(doc_list[idx].sci, line_end);
-			sci_target_replace(doc_list[idx].sci, "", FALSE);
-		}
+		document_strip_line_trailing_spaces(idx, line);
 	}
 	sci_end_undo_action(doc_list[idx].sci);
 }
diff --git a/src/document.h b/src/document.h
index 915ca4c..f0669a5 100644
--- a/src/document.h
+++ b/src/document.h
@@ -190,6 +190,8 @@ void document_print(gint idx);
 
 void document_replace_tabs(gint idx);
 
+void document_strip_line_trailing_spaces(gint idx, gint line);
+
 void document_strip_trailing_spaces(gint idx);
 
 void document_ensure_final_newline(gint idx);
diff --git a/src/editor.c b/src/editor.c
index 9e2af5e..aea3e76 100644
--- a/src/editor.c
+++ b/src/editor.c
@@ -398,6 +398,7 @@ get_whitespace(gint width, gboolean alternative)
 static void on_new_line_added(ScintillaObject *sci, gint idx)
 {
 	gint pos = sci_get_current_position(sci);
+	gint line = sci_get_current_line(sci);
 
 	// simple indentation
 	if (doc_list[idx].auto_indent)
@@ -427,6 +428,12 @@ static void on_new_line_added(ScintillaObject *sci, gint idx)
 
 		editor_auto_latex(idx, pos);
 	}
+
+	if (editor_prefs.newline_strip)
+	{
+		// strip the trailing spaces on the previous line
+		document_strip_line_trailing_spaces(idx, line - 1);
+	}
 }
 
 
diff --git a/src/editor.h b/src/editor.h
index 12b5272..f33ec56 100644
--- a/src/editor.h
+++ b/src/editor.h
@@ -66,6 +66,7 @@ typedef struct EditorPrefs
 	IndentMode	indent_mode;
 	gboolean	disable_dnd;
 	gboolean	smart_home_key;
+	gboolean	newline_strip;
 	gboolean	auto_complete_symbols;
 	gboolean	auto_close_xml_tags;
 	gboolean	auto_complete_constructs;
diff --git a/src/interface.c b/src/interface.c
index fe059c4..c6cc040 100644
--- a/src/interface.c
+++ b/src/interface.c
@@ -2535,6 +2535,7 @@ create_prefs_dialog (void)
   GtkWidget *check_folding;
   GtkWidget *check_unfold_children;
   GtkWidget *check_indicators;
+  GtkWidget *check_newline_strip;
   GtkWidget *label172;
   GtkWidget *frame18;
   GtkWidget *alignment21;
@@ -3546,6 +3547,12 @@ create_prefs_dialog (void)
   gtk_tooltips_set_tip (tooltips, check_indicators, _("Whether to use indicators (a squiggly underline) to highlight the lines where the compiler found a warning or an error."), NULL);
   gtk_button_set_focus_on_click (GTK_BUTTON (check_indicators), FALSE);
 
+  check_newline_strip = gtk_check_button_new_with_mnemonic (_("Newline strips trailing spaces"));
+  gtk_widget_show (check_newline_strip);
+  gtk_box_pack_start (GTK_BOX (vbox17), check_newline_strip, FALSE, FALSE, 0);
+  gtk_tooltips_set_tip (tooltips, check_newline_strip, _("Enable newline to strip the trailing spaces on the previous line."), NULL);
+  gtk_button_set_focus_on_click (GTK_BUTTON (check_newline_strip), FALSE);
+
   label172 = gtk_label_new (_("<b>Features</b>"));
   gtk_widget_show (label172);
   gtk_frame_set_label_widget (GTK_FRAME (frame14), label172);
@@ -4303,6 +4310,7 @@ create_prefs_dialog (void)
   GLADE_HOOKUP_OBJECT (prefs_dialog, check_folding, "check_folding");
   GLADE_HOOKUP_OBJECT (prefs_dialog, check_unfold_children, "check_unfold_children");
   GLADE_HOOKUP_OBJECT (prefs_dialog, check_indicators, "check_indicators");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, check_newline_strip, "check_newline_strip");
   GLADE_HOOKUP_OBJECT (prefs_dialog, label172, "label172");
   GLADE_HOOKUP_OBJECT (prefs_dialog, frame18, "frame18");
   GLADE_HOOKUP_OBJECT (prefs_dialog, alignment21, "alignment21");
diff --git a/src/keyfile.c b/src/keyfile.c
index 6a5669a..94d3daf 100644
--- a/src/keyfile.c
+++ b/src/keyfile.c
@@ -193,6 +193,7 @@ static void save_dialog_prefs(GKeyFile *config)
 	g_key_file_set_boolean(config, PACKAGE, "pref_editor_use_tabs", editor_prefs.use_tabs);
 	g_key_file_set_boolean(config, PACKAGE, "pref_editor_disable_dnd", editor_prefs.disable_dnd);
 	g_key_file_set_boolean(config, PACKAGE, "pref_editor_smart_home_key", editor_prefs.smart_home_key);
+	g_key_file_set_boolean(config, PACKAGE, "pref_editor_newline_strip", editor_prefs.newline_strip);
 
 	// files
 	g_key_file_set_string(config, PACKAGE, "pref_editor_default_new_encoding", encodings[prefs.default_new_encoding].charset);
@@ -465,6 +466,7 @@ static void load_dialog_prefs(GKeyFile *config)
 	editor_prefs.use_tabs = utils_get_setting_boolean(config, PACKAGE, "pref_editor_use_tabs", TRUE);
 	editor_prefs.disable_dnd = utils_get_setting_boolean(config, PACKAGE, "pref_editor_disable_dnd", FALSE);
 	editor_prefs.smart_home_key = utils_get_setting_boolean(config, PACKAGE, "pref_editor_smart_home_key", TRUE);
+	editor_prefs.newline_strip = utils_get_setting_boolean(config, PACKAGE, "pref_editor_newline_strip", FALSE);
 	editor_prefs.use_gtk_word_boundaries = utils_get_setting_boolean(config, PACKAGE, "use_gtk_word_boundaries", TRUE);
 	editor_prefs.auto_complete_whilst_editing = utils_get_setting_boolean(config, PACKAGE, "auto_complete_whilst_editing", FALSE);
 
diff --git a/src/prefs.c b/src/prefs.c
index bb166e5..bc3c037 100644
--- a/src/prefs.c
+++ b/src/prefs.c
@@ -307,6 +307,9 @@ void prefs_init_dialog(void)
 	widget = lookup_widget(ui_widgets.prefs_dialog, "check_smart_home");
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), editor_prefs.smart_home_key);
 
+	widget = lookup_widget(ui_widgets.prefs_dialog, "check_newline_strip");
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), editor_prefs.newline_strip);
+
 	if (editor_prefs.use_tabs)
 		widget = lookup_widget(ui_widgets.prefs_dialog, "radio_indent_tabs");
 	else
@@ -684,6 +687,9 @@ on_prefs_button_clicked(GtkDialog *dialog, gint response, gpointer user_data)
 		widget = lookup_widget(ui_widgets.prefs_dialog, "check_smart_home");
 		editor_prefs.smart_home_key = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
 
+		widget = lookup_widget(ui_widgets.prefs_dialog, "check_newline_strip");
+		editor_prefs.newline_strip = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+
 		widget = lookup_widget(ui_widgets.prefs_dialog, "radio_indent_tabs");
 		editor_prefs.use_tabs = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
 
