Hi all. It's me again, with another little patch (probably the last one from me for a long period of time).

I discovered that Geany doesn't provide key bindings for the abovementioned scintilla commands. I think they are very useful while editing text, or HTML, or other markup, especially when you don't like when your text exceeds 80 char boundary (like me). With these shortcuts, you no longer need to manually reformat your text after you make a slight change in it, you know. There are such shortcuts in other editors like (afair) Eclipse and Notepad++ for Windows.

Unfortunately, SCI_LINESJOIN and SCI_LINESSPLIT commands are not very smart, e.g., they do not respect indentation. I had to write some code so that these commands could be useful. Particularly, in lines_split() function I had to change line indentations and text selection (see comments in the code for more information)... My knowledge of Scintilla's features is not perfect; if you could suggest more user-friendly ways to deal with indentation, please do.

When implementing this, I had to add couple of sciwrappers, so I placed them at the end of sciwrappers.{c,h}.

The patch also adds corresponding entries to key bindings properties in the preferences dialog. Maybe "Split lines" entry should be renamed as it may be ambiguous.

The patch is against rev. 3951. Alternative link: http://pastie.org/543980. Hope you'll find it useful.

Best regards,
Eugene.
diff --git a/src/editor.c b/src/editor.c
index 2efdaec..75aaf50 100644
--- a/src/editor.c
+++ b/src/editor.c
@@ -101,7 +101,6 @@ static void auto_table(GeanyEditor *editor, gint pos);
 static void close_block(GeanyEditor *editor, gint pos);
 static void editor_highlight_braces(GeanyEditor *editor, gint cur_pos);
 static void editor_auto_latex(GeanyEditor *editor, gint pos);
-static void editor_strip_line_trailing_spaces(GeanyEditor *editor, gint line);
 
 
 void editor_snippets_free(void)
@@ -4271,7 +4270,7 @@ void editor_replace_spaces(GeanyEditor *editor)
 }
 
 
-static void editor_strip_line_trailing_spaces(GeanyEditor *editor, gint line)
+void editor_strip_line_trailing_spaces(GeanyEditor *editor, gint line)
 {
 	gint line_start = sci_get_position_from_line(editor->sci, line);
 	gint line_end = sci_get_line_end_position(editor->sci, line);
diff --git a/src/editor.h b/src/editor.h
index 50eafb6..2d21738 100644
--- a/src/editor.h
+++ b/src/editor.h
@@ -100,7 +100,7 @@ typedef struct GeanyEditorPrefs
 	gboolean	show_white_space;
 	gboolean	show_indent_guide;
 	gboolean	show_line_endings;
-	gint		long_line_type;
+	gint		long_line_type; /* 0 - line, 1 - background, 2 - none */
 	gint		long_line_column;
 	gchar		*long_line_color;
 	gboolean	show_markers_margin;		/* view menu */
@@ -251,6 +251,8 @@ void editor_replace_tabs(GeanyEditor *editor);
 
 void editor_replace_spaces(GeanyEditor *editor);
 
+void editor_strip_line_trailing_spaces(GeanyEditor *editor, gint line);
+
 void editor_strip_trailing_spaces(GeanyEditor *editor);
 
 void editor_ensure_final_newline(GeanyEditor *editor);
diff --git a/src/keybindings.c b/src/keybindings.c
index 6c25932..877680a 100644
--- a/src/keybindings.c
+++ b/src/keybindings.c
@@ -263,6 +263,10 @@ static void init_default_kb(void)
 		GDK_space, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "edit_calltip", _("Show calltip"), NULL);
 	keybindings_set_item(group, GEANY_KEYS_EDITOR_MACROLIST, cb_func_editor_action,
 		GDK_Return, GDK_CONTROL_MASK, "edit_macrolist", _("Show macro list"), NULL);
+	keybindings_set_item(group, GEANY_KEYS_EDITOR_SPLITLINES, cb_func_editor_action,
+		0, 0, "edit_splitlines", _("Split lines"), NULL);
+	keybindings_set_item(group, GEANY_KEYS_EDITOR_JOINLINES, cb_func_editor_action,
+		0, 0, "edit_joinlines", _("Join lines"), NULL);
 
 	group = ADD_KB_GROUP(CLIPBOARD, _("Clipboard"));
 
@@ -1830,6 +1834,124 @@ static void delete_lines(GeanyEditor *editor)
 }
 
 
+static void join_lines(GeanyEditor *editor)
+{
+	gint start, end, i;
+
+	start = sci_get_line_from_position(editor->sci,
+		sci_get_selection_start(editor->sci));
+	end = sci_get_line_from_position(editor->sci,
+		sci_get_selection_end(editor->sci));
+
+	/* if there is only one line in selection, join it with the following one */
+	if (end == start)
+		end = start + 1;
+
+	/*
+	 * remove trailing spaces for every line except the last one
+	 * so that these spaces won't appear within text after joining
+	 */
+	for (i = start; i < end; i++)
+		editor_strip_line_trailing_spaces(editor, i);
+
+	/* remove starting spaces from second and following lines due to the same reason */
+	for (i = start+1; i <= end; i++)
+		sci_set_line_indentation(editor->sci, i, 0);
+
+	/*
+	 * SCI_LINESJOIN automatically adds spaces between joined lines, including
+	 * empty ones. We should drop empty lines if we want only one space to be
+	 * inserted (see also example below). I don't think we should care of that.
+	 */
+
+	sci_set_target_start(editor->sci,
+		sci_get_position_from_line(editor->sci, start));
+	sci_set_target_end(editor->sci,
+		sci_get_position_from_line(editor->sci, end));
+	sci_lines_join(editor->sci);
+
+	/*
+	 * Example: joining
+	 *
+	 * [TAB]if (something_wrong)
+	 * [TAB]{
+	 * [TAB][TAB]
+	 * [TAB][TAB]exit(1);[SPACE][SPACE]
+	 * [TAB]}[SPACE]
+	 *
+	 * gives
+	 *
+	 * [TAB]if (something_wrong) {  exit(1); }[SPACE]
+	 */
+}
+
+
+static void split_lines(GeanyEditor *editor)
+{
+	gint start, end, indent, i;
+
+	/* do nothing if long line marker is disabled */
+	if (editor_prefs.long_line_type == 2)
+		return;
+
+	start = sci_get_line_from_position(editor->sci,
+		sci_get_selection_start(editor->sci));
+
+	/*
+	 * If several lines are selected, first join them.
+	 * This allows to reformat text paragpaphs easily.
+	 */
+	if (sci_get_lines_selected(editor->sci) > 1)
+		join_lines(editor);
+
+	/*
+	 * We have to manipulate line indentation so that indentation
+	 * of the resulting lines would be consistent. For example,
+	 * the result of splitting "[TAB]very long content":
+	 *
+	 * +-------------+-------------+
+	 * |   proper    |    wrong    |
+	 * +-------------+-------------+
+	 * | [TAB]very   | [TAB]very   |
+	 * | [TAB]long   | long        |
+	 * | [TAB]content| content     |
+	 * +-------------+-------------+
+	 *
+	 * WARNING: Unfortunately, removing and restoring indentation causes the
+	 * document to be marked as changed, even if no actual splitting was
+	 * performed. I see no obvious way to fix it.
+	 */
+	indent = sci_get_line_indentation(editor->sci, start);
+	sci_set_line_indentation(editor->sci, start, 0);
+
+	/*
+	 * We have to manually select all the line, so that we could
+	 * determine amount of lines added during splitting. SCI_LINESSPLIT
+	 * should better return something like amount of added lines...
+	 *
+	 * NOTE: so after splitting all the resulting text will be selected.
+	 *
+	 * Alternatively, we could using a temporary marker.
+	 * Should we reserve one for such usage?
+	 */
+	sci_set_selection_start(editor->sci,
+		sci_get_position_from_line(editor->sci, start));
+	sci_set_selection_end(editor->sci,
+		sci_get_line_end_position(editor->sci, start));
+
+	sci_target_from_selection(editor->sci);
+	sci_lines_split(editor->sci,
+		(editor_prefs.long_line_column - indent) *
+		sci_text_width(editor->sci, STYLE_DEFAULT, " "));
+
+	/* Fix indentation. */
+	end = sci_get_line_from_position(editor->sci,
+		sci_get_selection_end(editor->sci));
+	for (i = start; i <= end; i++)
+		sci_set_line_indentation(editor->sci, i, indent);
+}
+
+
 /* common function for editor keybindings, only valid when scintilla has focus. */
 static void cb_func_editor_action(guint key_id)
 {
@@ -1905,6 +2027,16 @@ static void cb_func_editor_action(guint key_id)
 			}
 			break;
 		}
+		case GEANY_KEYS_EDITOR_SPLITLINES:
+			sci_start_undo_action(doc->editor->sci);
+			split_lines(doc->editor);
+			sci_end_undo_action(doc->editor->sci);
+			break;
+		case GEANY_KEYS_EDITOR_JOINLINES:
+			sci_start_undo_action(doc->editor->sci);
+			join_lines(doc->editor);
+			sci_end_undo_action(doc->editor->sci);
+			break;
 	}
 }
 
diff --git a/src/keybindings.h b/src/keybindings.h
index 8dd8a29..5e0f9bd 100644
--- a/src/keybindings.h
+++ b/src/keybindings.h
@@ -133,6 +133,8 @@ enum
 	GEANY_KEYS_EDITOR_CALLTIP,
 	GEANY_KEYS_EDITOR_MACROLIST,
 	GEANY_KEYS_EDITOR_DELETELINETOEND,
+	GEANY_KEYS_EDITOR_SPLITLINES,
+	GEANY_KEYS_EDITOR_JOINLINES,
 	GEANY_KEYS_EDITOR_COUNT
 };
 
diff --git a/src/sciwrappers.c b/src/sciwrappers.c
index 6f916bf..e17a61f 100644
--- a/src/sciwrappers.c
+++ b/src/sciwrappers.c
@@ -1084,4 +1084,27 @@ gint sci_get_position_after(ScintillaObject *sci, gint start)
 	return SSM(sci, SCI_POSITIONAFTER, start, 0);
 }
 
+void sci_lines_split(ScintillaObject *sci, gint pixelWidth)
+{
+	SSM(sci, SCI_LINESSPLIT, pixelWidth, 0);
+}
 
+void sci_lines_join(ScintillaObject *sci)
+{
+	SSM(sci, SCI_LINESJOIN, 0, 0);
+}
+
+void sci_set_target_start(ScintillaObject *sci, gint pos)
+{
+	SSM(sci, SCI_SETTARGETSTART, pos, 0);
+}
+
+void sci_set_target_end(ScintillaObject *sci, gint pos)
+{
+	SSM(sci, SCI_SETTARGETEND, pos, 0);
+}
+
+gint sci_text_width(ScintillaObject *sci, gint styleNumber, const gchar *text)
+{
+	return SSM(sci, SCI_TEXTWIDTH, styleNumber, (sptr_t) text);
+}
diff --git a/src/sciwrappers.h b/src/sciwrappers.h
index 624c77d..d4f9d53 100644
--- a/src/sciwrappers.h
+++ b/src/sciwrappers.h
@@ -59,7 +59,7 @@ gint				sci_marker_previous			(ScintillaObject* sci, gint line, gint marker_mask
 
 gint 				sci_get_col_from_position	(ScintillaObject* sci, gint position);
 gint 				sci_get_line_from_position	(ScintillaObject* sci, gint position);
-gint 				sci_get_position_from_line	(ScintillaObject* sci, gint line );
+gint 				sci_get_position_from_line	(ScintillaObject* sci, gint line);
 gint 				sci_get_current_position	(ScintillaObject* sci);
 void 				sci_set_current_position	(ScintillaObject* sci, gint position, gboolean scroll_to_caret);
 void 				sci_set_current_line		(ScintillaObject* sci, gint line);
@@ -176,4 +176,11 @@ void				sci_cancel					(ScintillaObject *sci);
 gint				sci_get_target_end			(ScintillaObject *sci);
 gint				sci_get_position_after		(ScintillaObject *sci, gint start);
 
+void				sci_lines_split				(ScintillaObject *sci, gint pixelWidth);
+void				sci_lines_join				(ScintillaObject *sci);
+void				sci_set_target_start		(ScintillaObject *sci, gint pos);
+void				sci_set_target_end			(ScintillaObject *sci, gint pos);
+gint				sci_text_width				(ScintillaObject *sci, int styleNumber, const char * text);
+
+
 #endif
_______________________________________________
Geany-devel mailing list
[email protected]
http://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel

Reply via email to