Line endings menu

This commit is contained in:
Yevgen Muntyan 2009-12-06 13:54:27 -08:00
parent f1db5fefe0
commit c9ceee964d
6 changed files with 242 additions and 73 deletions

View File

@ -218,6 +218,8 @@ moo_edit_action_get_doc
_moo_get_pid_string
moo_get_user_data_dir
moo_text_view_get_cursor_line
moo_text_buffer_get_type
moo_text_buffer_add_fold
_moo_tree_helper_new
moo_prefs_page_new
moo_prefs_page_new

View File

@ -102,6 +102,7 @@
<separator/>
<item action="LanguageMenu"/>
<item action="EncodingMenu"/>
<item action="LineEndMenu"/>
<separator/>
<item action="ToggleBookmark"/>
<item action="PreviousBookmark"/>

View File

@ -29,6 +29,7 @@
#include "mooutils/mooencodings.h"
#include "mooutils/mooi18n.h"
#include "mooutils/mootype-macros.h"
#include "mooutils/mooutils-messages.h"
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
@ -199,6 +200,37 @@ set_encoding_error (GError **error)
}
MooLineEndType
_moo_edit_get_line_end_type (MooEdit *edit)
{
g_return_val_if_fail (MOO_IS_EDIT (edit), MOO_LE_DEFAULT);
return edit->priv->line_end_type;
}
static void
moo_edit_set_line_end_type_full (MooEdit *edit,
MooLineEndType le,
gboolean quiet)
{
moo_return_if_fail (MOO_IS_EDIT (edit));
moo_return_if_fail (le > 0);
if (edit->priv->line_end_type != le)
{
edit->priv->line_end_type = le;
if (!quiet)
g_object_notify (G_OBJECT (edit), "line-end-type");
}
}
void
_moo_edit_set_line_end_type (MooEdit *edit,
MooLineEndType le)
{
moo_edit_set_line_end_type_full (edit, le, FALSE);
}
/***************************************************************************/
/* File loading
*/
@ -349,6 +381,7 @@ moo_edit_load_local (MooEdit *edit,
gboolean undo;
LoadResult result = ERROR_FILE;
char *freeme = NULL;
MooLineEndType saved_le;
g_return_val_if_fail (MOO_IS_EDIT (edit), FALSE);
g_return_val_if_fail (file != NULL, FALSE);
@ -373,6 +406,8 @@ moo_edit_load_local (MooEdit *edit,
moo_text_buffer_begin_non_interactive_action (MOO_TEXT_BUFFER (buffer));
saved_le = edit->priv->line_end_type;
if (!encoding)
{
GSList *encodings;
@ -431,6 +466,8 @@ moo_edit_load_local (MooEdit *edit,
edit->priv->status = 0;
moo_edit_set_modified (edit, FALSE);
_moo_edit_set_file (edit, file, encoding);
if (edit->priv->line_end_type != saved_le)
g_object_notify (G_OBJECT (edit), "line-end-type");
_moo_edit_start_file_watch (edit);
}
else
@ -459,7 +496,7 @@ do_load (MooEdit *edit,
GIOChannel *file = NULL;
GIOStatus status;
GtkTextBuffer *buffer;
MooEditLineEndType le = MOO_EDIT_LINE_END_NONE;
MooLineEndType le = edit->priv->line_end_type;
GString *text = NULL;
char *line = NULL;
LoadResult result = ERROR_FILE;
@ -495,7 +532,7 @@ do_load (MooEdit *edit,
{
gboolean insert_line_term = FALSE;
gsize len, line_term_pos;
MooEditLineEndType le_here = 0;
MooLineEndType le_here = 0;
status = g_io_channel_read_line (file, &line, &len, &line_term_pos, error);
@ -533,21 +570,21 @@ do_load (MooEdit *edit,
}
else if (!strcmp (line_term, "\r"))
{
le_here = MOO_EDIT_LINE_END_MAC;
le_here = MOO_LE_MAC;
}
else if (!strcmp (line_term, "\n"))
{
le_here = MOO_EDIT_LINE_END_UNIX;
le_here = MOO_LE_UNIX;
}
else if (!strcmp (line_term, "\r\n"))
{
le_here = MOO_EDIT_LINE_END_WIN32;
le_here = MOO_LE_WIN32;
}
if (le_here)
{
if (le && le != le_here)
le = MOO_EDIT_LINE_END_MIX;
le = MOO_LE_MIX;
else
le = le_here;
}
@ -580,7 +617,14 @@ do_load (MooEdit *edit,
if (text->len)
gtk_text_buffer_insert_at_cursor (buffer, text->str, text->len);
edit->priv->line_end_type = le;
switch (edit->priv->line_end_type)
{
case MOO_LE_MIX:
break;
default:
moo_edit_set_line_end_type_full (edit, le, TRUE);
break;
}
g_string_free (text, TRUE);
g_clear_error (error);
@ -733,60 +777,13 @@ moo_edit_reload_local (MooEdit *edit,
/* File saving
*/
#ifdef G_OS_WIN32
#define DEFAULT_LE_TYPE MOO_EDIT_LINE_END_WIN32
#else
#define DEFAULT_LE_TYPE MOO_EDIT_LINE_END_UNIX
#endif
static GString *
get_contents (MooEdit *edit)
static char *
get_contents_with_fixed_line_end (GtkTextBuffer *buffer, const char *le, guint le_len)
{
MooEditLineEndType le_type = DEFAULT_LE_TYPE;
const char *le = "\n";
gsize le_len = 1;
GtkTextIter line_start;
GtkTextBuffer *buffer;
GString *contents;
switch (edit->priv->line_end_type)
{
case MOO_EDIT_LINE_END_NONE:
le_type = DEFAULT_LE_TYPE;
break;
case MOO_EDIT_LINE_END_UNIX:
case MOO_EDIT_LINE_END_WIN32:
case MOO_EDIT_LINE_END_MAC:
le_type = edit->priv->line_end_type;
break;
case MOO_EDIT_LINE_END_MIX:
edit->priv->line_end_type = le_type = DEFAULT_LE_TYPE;
break;
}
switch (le_type)
{
case MOO_EDIT_LINE_END_UNIX:
le = "\n";
le_len = 1;
break;
case MOO_EDIT_LINE_END_WIN32:
le = "\r\n";
le_len = 2;
break;
case MOO_EDIT_LINE_END_MAC:
le = "\r";
le_len = 1;
break;
case MOO_EDIT_LINE_END_MIX:
case MOO_EDIT_LINE_END_NONE:
g_assert_not_reached ();
}
contents = g_string_new (NULL);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
gtk_text_buffer_get_start_iter (buffer, &line_start);
do
@ -799,7 +796,7 @@ get_contents (MooEdit *edit)
gsize len;
gtk_text_iter_forward_to_line_end (&line_end);
line = gtk_text_buffer_get_slice (buffer, &line_start, &line_end, TRUE);
line = gtk_text_buffer_get_text (buffer, &line_start, &line_end, TRUE);
len = strlen (line);
g_string_append_len (contents, line, len);
@ -812,6 +809,56 @@ get_contents (MooEdit *edit)
}
while (gtk_text_iter_forward_line (&line_start));
return g_string_free (contents, FALSE);
}
static char *
get_contents (MooEdit *edit)
{
gboolean normalize_le = FALSE;
const char *le;
gsize le_len;
GtkTextBuffer *buffer;
char *contents;
switch (edit->priv->line_end_type)
{
case MOO_LE_UNIX:
normalize_le = TRUE;
le = "\n";
le_len = 1;
break;
case MOO_LE_WIN32:
normalize_le = TRUE;
le = "\r\n";
le_len = 2;
break;
case MOO_LE_MAC:
normalize_le = TRUE;
le = "\r";
le_len = 1;
break;
case MOO_LE_MIX:
break;
default:
moo_assert_not_reached ();
}
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit));
if (normalize_le)
{
contents = get_contents_with_fixed_line_end (buffer, le, le_len);
}
else
{
GtkTextIter start, end;
gtk_text_buffer_get_bounds (buffer, &start, &end);
contents = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
}
return contents;
}
@ -847,7 +894,7 @@ do_save_local (MooEdit *edit,
GError **error,
gboolean *retval)
{
GString *utf8_contents;
char *utf8_contents;
const char *to_save;
gsize to_save_size;
GError *encoding_error = NULL;
@ -858,6 +905,8 @@ do_save_local (MooEdit *edit,
*retval = TRUE;
utf8_contents = get_contents (edit);
moo_release_assert (utf8_contents != NULL);
if (encoding && (!g_ascii_strcasecmp (encoding, "UTF-8") || !g_ascii_strcasecmp (encoding, "UTF8")))
encoding = NULL;
@ -865,7 +914,7 @@ do_save_local (MooEdit *edit,
{
gsize bytes_read;
gsize bytes_written;
char *encoded = g_convert (utf8_contents->str, utf8_contents->len,
char *encoded = g_convert (utf8_contents, -1,
encoding, "UTF-8",
&bytes_read, &bytes_written,
&encoding_error);
@ -878,14 +927,14 @@ do_save_local (MooEdit *edit,
else
{
*retval = FALSE;
to_save = utf8_contents->str;
to_save_size = utf8_contents->len;
to_save = utf8_contents;
to_save_size = strlen (utf8_contents);
}
}
else
{
to_save = utf8_contents->str;
to_save_size = utf8_contents->len;
to_save = utf8_contents;
to_save_size = strlen (utf8_contents);
}
if (!do_write (file, to_save, to_save_size, flags, error))
@ -900,7 +949,7 @@ do_save_local (MooEdit *edit,
}
g_free (freeme);
g_string_free (utf8_contents, TRUE);
g_free (utf8_contents);
return success;
}

View File

@ -102,6 +102,23 @@ void _moo_edit_set_encoding (MooEdit *edit,
const char *_moo_edit_get_default_encoding (void);
void _moo_edit_ensure_newline (MooEdit *edit);
/* Keep in sync with line_end_menu_items in mooeditwindow.c */
typedef enum {
MOO_LE_UNIX = 1,
MOO_LE_WIN32,
MOO_LE_MAC,
MOO_LE_MIX,
#ifdef __WIN32__
MOO_LE_DEFAULT = MOO_LE_WIN32
#else
MOO_LE_DEFAULT = MOO_LE_UNIX
#endif
} MooLineEndType;
MooLineEndType _moo_edit_get_line_end_type (MooEdit *edit);
void _moo_edit_set_line_end_type (MooEdit *edit,
MooLineEndType le);
void _moo_edit_stop_file_watch (MooEdit *edit);
void _moo_edit_set_status (MooEdit *edit,
@ -127,14 +144,6 @@ struct MooEditFileInfo {
char *encoding;
};
typedef enum {
MOO_EDIT_LINE_END_NONE,
MOO_EDIT_LINE_END_UNIX,
MOO_EDIT_LINE_END_WIN32,
MOO_EDIT_LINE_END_MAC,
MOO_EDIT_LINE_END_MIX
} MooEditLineEndType;
struct MooEditPrivate {
MooEditor *editor;
@ -150,7 +159,7 @@ struct MooEditPrivate {
char *display_basename;
char *encoding;
MooEditLineEndType line_end_type;
MooLineEndType line_end_type;
MooEditStatus status;
guint file_monitor_id;

View File

@ -111,6 +111,7 @@ enum {
PROP_EDITOR,
PROP_ENABLE_BOOKMARKS,
PROP_HAS_COMMENTS,
PROP_LINE_END_TYPE,
PROP_ENCODING
};
@ -169,6 +170,10 @@ moo_edit_class_init (MooEditClass *klass)
FALSE,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class, PROP_LINE_END_TYPE,
g_param_spec_int ("line-end-type", "line-end-type", "line-end-type",
MOO_LE_UNIX, MOO_LE_MIX, MOO_LE_UNIX, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_ENCODING,
g_param_spec_string ("encoding",
@ -269,6 +274,8 @@ moo_edit_init (MooEdit *edit)
edit->priv->actions = moo_action_collection_new ("MooEdit", "MooEdit");
edit->priv->line_end_type = MOO_LE_DEFAULT;
indent = moo_indenter_new (edit);
moo_text_view_set_indenter (MOO_TEXT_VIEW (edit), indent);
g_object_unref (indent);
@ -529,6 +536,10 @@ moo_edit_set_property (GObject *object,
_moo_edit_set_encoding (edit, g_value_get_string (value));
break;
case PROP_LINE_END_TYPE:
_moo_edit_set_line_end_type (edit, g_value_get_int (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -562,6 +573,10 @@ moo_edit_get_property (GObject *object,
g_value_set_string (value, edit->priv->encoding);
break;
case PROP_LINE_END_TYPE:
g_value_set_int (value, edit->priv->line_end_type);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View File

@ -149,6 +149,9 @@ static void edit_filename_changed (MooEditWindow *window,
static void edit_encoding_changed (MooEditWindow *window,
GParamSpec *pspec,
MooEdit *doc);
static void edit_line_end_changed (MooEditWindow *window,
GParamSpec *pspec,
MooEdit *doc);
static void edit_lang_changed (MooEditWindow *window,
guint var_id,
GParamSpec *pspec,
@ -217,6 +220,7 @@ static void action_open (MooEditWindow *window);
static void action_reload (MooEditWindow *window);
static GtkAction *create_reopen_with_encoding_action (MooEditWindow *window);
static GtkAction *create_doc_encoding_action (MooEditWindow *window);
static GtkAction *create_doc_line_end_action (MooEditWindow *window);
static void action_save (MooEditWindow *window);
static void action_save_as (MooEditWindow *window);
static void action_close_tab (MooEditWindow *window);
@ -389,6 +393,10 @@ moo_edit_window_class_init (MooEditWindowClass *klass)
(MooWindowActionFunc) create_doc_encoding_action,
NULL, NULL);
moo_window_class_new_action_custom (window_class, "LineEndMenu", NULL,
(MooWindowActionFunc) create_doc_line_end_action,
NULL, NULL);
moo_window_class_new_action (window_class, "Save", NULL,
"display-name", GTK_STOCK_SAVE,
"label", GTK_STOCK_SAVE,
@ -1228,6 +1236,80 @@ create_doc_encoding_action (MooEditWindow *window)
}
static const char *line_end_menu_items[] = {
NULL, /* MOO_LE_NONE */
"LineEndWin32", /* MOO_LE_UNIX */
"LineEndUnix", /* MOO_LE_WIN32 */
"LineEndMac", /* MOO_LE_MAC */
"LineEndMix" /* MOO_LE_MIX */
};
static void
update_doc_line_end_item (MooEditWindow *window)
{
MooEdit *doc;
GtkAction *action;
MooLineEndType le;
if (!(doc = ACTIVE_DOC (window)))
return;
action = moo_window_get_action (MOO_WINDOW (window), "LineEndMenu");
g_return_if_fail (action != NULL);
le = _moo_edit_get_line_end_type (doc);
g_return_if_fail (le > 0 && le < G_N_ELEMENTS(line_end_menu_items));
moo_menu_mgr_set_active (moo_menu_action_get_mgr (MOO_MENU_ACTION (action)),
line_end_menu_items[le], TRUE);
}
static void
doc_line_end_item_set_active (MooEditWindow *window, gpointer data)
{
MooEdit *doc;
doc = ACTIVE_DOC (window);
g_return_if_fail (doc != NULL);
_moo_edit_set_line_end_type (doc, GPOINTER_TO_INT (data));
}
static GtkAction *
create_doc_line_end_action (MooEditWindow *window)
{
GtkAction *action;
MooMenuMgr *mgr;
action = moo_menu_action_new ("LineEndMenu", _("Line E_ndings"));
mgr = moo_menu_action_get_mgr (MOO_MENU_ACTION (action));
g_signal_connect_swapped (mgr, "radio-set-active", G_CALLBACK (doc_line_end_item_set_active), window);
moo_menu_mgr_append (mgr, NULL,
line_end_menu_items[MOO_LE_WIN32],
_("_Windows (CR+LF)"), NULL, MOO_MENU_ITEM_RADIO,
GINT_TO_POINTER (MOO_LE_WIN32), NULL);
moo_menu_mgr_insert (mgr, NULL, MOO_OS_WIN32 ? 1 : 0,
line_end_menu_items[MOO_LE_UNIX],
_("_Unix (LF)"), NULL, MOO_MENU_ITEM_RADIO,
GINT_TO_POINTER (MOO_LE_UNIX), NULL);
moo_menu_mgr_append (mgr, NULL,
line_end_menu_items[MOO_LE_MAC],
_("_Mac (CR)"), NULL, MOO_MENU_ITEM_RADIO,
GINT_TO_POINTER (MOO_LE_MAC), NULL);
moo_menu_mgr_append (mgr, NULL,
line_end_menu_items[MOO_LE_MIX],
_("Mi_xed"), NULL, MOO_MENU_ITEM_RADIO,
GINT_TO_POINTER (MOO_LE_MIX), NULL);
moo_bind_bool_property (action, "sensitive",
window, "has-open-document", FALSE);
return action;
}
static void
action_save (MooEditWindow *window)
{
@ -1947,6 +2029,15 @@ edit_encoding_changed (MooEditWindow *window,
update_doc_encoding_item (window);
}
static void
edit_line_end_changed (MooEditWindow *window,
G_GNUC_UNUSED GParamSpec *pspec,
MooEdit *doc)
{
if (doc == ACTIVE_DOC (window))
update_doc_line_end_item (window);
}
static void
edit_overwrite_changed (MooEditWindow *window,
G_GNUC_UNUSED GParamSpec *pspec,
@ -2188,6 +2279,8 @@ _moo_edit_window_insert_doc (MooEditWindow *window,
G_CALLBACK (edit_changed), window);
g_signal_connect_swapped (edit, "notify::encoding",
G_CALLBACK (edit_encoding_changed), window);
g_signal_connect_swapped (edit, "notify::line-end",
G_CALLBACK (edit_line_end_changed), window);
g_signal_connect_swapped (edit, "notify::overwrite",
G_CALLBACK (edit_overwrite_changed), window);
g_signal_connect_swapped (edit, "notify::wrap-mode",