[gnome-text-editor] document: refactor loading/saving to support encoding/line endings



commit 2527998ad834ff30985931761fafcbe7bfc4649e
Author: Christian Hergert <chergert redhat com>
Date:   Tue Jun 22 17:15:58 2021 -0700

    document: refactor loading/saving to support encoding/line endings
    
    This cleans up how we handle encodings but also allows us to specify line
    endings when saving (and preserve what was loaded).

 src/editor-document-private.h |  95 +++++++++++++++--------------
 src/editor-document.c         |  78 +++++++++++++-----------
 src/editor-page.c             |  19 ++++--
 src/editor-session.c          |   8 +--
 src/editor-session.h          | 104 +++++++++++++++----------------
 src/editor-utils-private.h    |  53 +++++++++-------
 src/editor-utils.c            | 138 ++++++++++++++++++++++++++++++++++++++++++
 src/editor-window-actions.c   |  57 +----------------
 8 files changed, 332 insertions(+), 220 deletions(-)
---
diff --git a/src/editor-document-private.h b/src/editor-document-private.h
index b6efa25..157afc4 100644
--- a/src/editor-document-private.h
+++ b/src/editor-document-private.h
@@ -24,51 +24,54 @@
 
 G_BEGIN_DECLS
 
-EditorDocument *_editor_document_new                     (GFile                *file,
-                                                          const gchar          *draft_id);
-const gchar    *_editor_document_get_draft_id            (EditorDocument       *self);
-void            _editor_document_set_draft_id            (EditorDocument       *self,
-                                                          const gchar          *draft_id);
-GFile          *_editor_document_get_draft_file          (EditorDocument       *self);
-gchar          *_editor_document_dup_uri                 (EditorDocument       *self);
-void            _editor_document_mark_busy               (EditorDocument       *self);
-void            _editor_document_unmark_busy             (EditorDocument       *self);
-void            _editor_document_set_externally_modified (EditorDocument       *self,
-                                                          gboolean              externally_modified);
-gboolean        _editor_document_get_was_restored        (EditorDocument       *self);
-void            _editor_document_set_was_restored        (EditorDocument       *self,
-                                                          gboolean              was_restored);
-void            _editor_document_set_encoding            (EditorDocument       *document,
-                                                          const char           *encoding);
-void            _editor_document_load_async              (EditorDocument       *self,
-                                                          EditorWindow         *window,
-                                                          GCancellable         *cancellable,
-                                                          GAsyncReadyCallback   callback,
-                                                          gpointer              user_data);
-gboolean        _editor_document_load_finish             (EditorDocument       *self,
-                                                          GAsyncResult         *result,
-                                                          GError              **error);
-void            _editor_document_save_async              (EditorDocument       *self,
-                                                          GFile                *file,
-                                                          GCancellable         *cancellable,
-                                                          GAsyncReadyCallback   callback,
-                                                          gpointer              user_data);
-gboolean        _editor_document_save_finish             (EditorDocument       *self,
-                                                          GAsyncResult         *result,
-                                                          GError              **error);
-void            _editor_document_save_draft_async        (EditorDocument       *self,
-                                                          GCancellable         *cancellable,
-                                                          GAsyncReadyCallback   callback,
-                                                          gpointer              user_data);
-gboolean        _editor_document_save_draft_finish       (EditorDocument       *self,
-                                                          GAsyncResult         *result,
-                                                          GError              **error);
-void            _editor_document_guess_language_async    (EditorDocument       *self,
-                                                          GCancellable         *cancellable,
-                                                          GAsyncReadyCallback   callback,
-                                                          gpointer              user_data);
-gboolean        _editor_document_guess_language_finish   (EditorDocument       *self,
-                                                          GAsyncResult         *result,
-                                                          GError              **error);
+EditorDocument       *_editor_document_new                     (GFile                    *file,
+                                                                const gchar              *draft_id);
+const gchar          *_editor_document_get_draft_id            (EditorDocument           *self);
+void                  _editor_document_set_draft_id            (EditorDocument           *self,
+                                                                const gchar              *draft_id);
+GFile                *_editor_document_get_draft_file          (EditorDocument           *self);
+gchar                *_editor_document_dup_uri                 (EditorDocument           *self);
+void                  _editor_document_mark_busy               (EditorDocument           *self);
+void                  _editor_document_unmark_busy             (EditorDocument           *self);
+void                  _editor_document_set_externally_modified (EditorDocument           *self,
+                                                                gboolean                  
externally_modified);
+gboolean              _editor_document_get_was_restored        (EditorDocument           *self);
+void                  _editor_document_set_was_restored        (EditorDocument           *self,
+                                                                gboolean                  was_restored);
+void                  _editor_document_set_encoding            (EditorDocument           *document,
+                                                                const GtkSourceEncoding  *encoding);
+GtkSourceNewlineType  _editor_document_get_newline_type        (EditorDocument           *self);
+void                  _editor_document_set_newline_type        (EditorDocument           *self,
+                                                                GtkSourceNewlineType      newline_type);
+void                  _editor_document_load_async              (EditorDocument           *self,
+                                                                EditorWindow             *window,
+                                                                GCancellable             *cancellable,
+                                                                GAsyncReadyCallback       callback,
+                                                                gpointer                  user_data);
+gboolean              _editor_document_load_finish             (EditorDocument           *self,
+                                                                GAsyncResult             *result,
+                                                                GError                  **error);
+void                  _editor_document_save_async              (EditorDocument           *self,
+                                                                GFile                    *file,
+                                                                GCancellable             *cancellable,
+                                                                GAsyncReadyCallback       callback,
+                                                                gpointer                  user_data);
+gboolean              _editor_document_save_finish             (EditorDocument           *self,
+                                                                GAsyncResult             *result,
+                                                                GError                  **error);
+void                  _editor_document_save_draft_async        (EditorDocument           *self,
+                                                                GCancellable             *cancellable,
+                                                                GAsyncReadyCallback       callback,
+                                                                gpointer                  user_data);
+gboolean              _editor_document_save_draft_finish       (EditorDocument           *self,
+                                                                GAsyncResult             *result,
+                                                                GError                  **error);
+void                  _editor_document_guess_language_async    (EditorDocument           *self,
+                                                                GCancellable             *cancellable,
+                                                                GAsyncReadyCallback       callback,
+                                                                gpointer                  user_data);
+gboolean              _editor_document_guess_language_finish   (EditorDocument           *self,
+                                                                GAsyncResult             *result,
+                                                                GError                  **error);
 
 G_END_DECLS
diff --git a/src/editor-document.c b/src/editor-document.c
index b5d7f14..12b9203 100644
--- a/src/editor-document.c
+++ b/src/editor-document.c
@@ -37,21 +37,22 @@
 
 struct _EditorDocument
 {
-  GtkSourceBuffer      parent_instance;
-
-  EditorBufferMonitor *monitor;
-  GtkSourceFile       *file;
-  gchar               *draft_id;
-  GtkTextTag          *line_spacing_tag;
-  char                *encoding;
-
-  guint                busy_count;
-  gdouble              busy_progress;
-
-  guint                readonly : 1;
-  guint                needs_autosave : 1;
-  guint                was_restored : 1;
-  guint                externally_modified : 1;
+  GtkSourceBuffer          parent_instance;
+
+  EditorBufferMonitor     *monitor;
+  GtkSourceFile           *file;
+  gchar                   *draft_id;
+  GtkTextTag              *line_spacing_tag;
+  const GtkSourceEncoding *encoding;
+
+  GtkSourceNewlineType     newline_type;
+  guint                    busy_count;
+  gdouble                  busy_progress;
+
+  guint                    readonly : 1;
+  guint                    needs_autosave : 1;
+  guint                    was_restored : 1;
+  guint                    externally_modified : 1;
 };
 
 typedef struct
@@ -312,7 +313,6 @@ editor_document_finalize (GObject *object)
   g_clear_object (&self->monitor);
   g_clear_object (&self->file);
   g_clear_pointer (&self->draft_id, g_free);
-  g_clear_pointer (&self->encoding, g_free);
 
   G_OBJECT_CLASS (editor_document_parent_class)->finalize (object);
 }
@@ -427,6 +427,7 @@ editor_document_class_init (EditorDocumentClass *klass)
 static void
 editor_document_init (EditorDocument *self)
 {
+  self->newline_type = GTK_SOURCE_NEWLINE_TYPE_DEFAULT;
   self->file = gtk_source_file_new ();
   self->draft_id = g_uuid_string_random ();
 
@@ -617,12 +618,10 @@ _editor_document_save_draft_async (EditorDocument      *self,
   gtk_source_file_saver_set_flags (saver,
                                    (GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_INVALID_CHARS |
                                     GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_MODIFICATION_TIME));
+  gtk_source_file_saver_set_newline_type (saver, self->newline_type);
 
   if (self->encoding != NULL)
-    {
-      const GtkSourceEncoding *encoding = gtk_source_encoding_get_from_charset (self->encoding);
-      gtk_source_file_saver_set_encoding (saver, encoding);
-    }
+    gtk_source_file_saver_set_encoding (saver, self->encoding);
 
   /* TODO: Probably want to make this async. We can just create an
    * async variant in editor-utils.c for this.
@@ -860,12 +859,10 @@ _editor_document_save_async (EditorDocument      *self,
   gtk_source_file_saver_set_flags (saver,
                                    (GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_INVALID_CHARS |
                                     GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_MODIFICATION_TIME));
+  gtk_source_file_saver_set_newline_type (saver, self->newline_type);
 
   if (self->encoding != NULL)
-    {
-      const GtkSourceEncoding *encoding = gtk_source_encoding_get_from_charset (self->encoding);
-      gtk_source_file_saver_set_encoding (saver, encoding);
-    }
+    gtk_source_file_saver_set_encoding (saver, self->encoding);
 
   _editor_document_mark_busy (self);
 
@@ -1060,6 +1057,8 @@ editor_document_load_cb (GObject      *object,
 
       g_assert (!file || G_IS_FILE (file));
 
+      self->newline_type = gtk_source_file_loader_get_newline_type (loader);
+
       _editor_document_set_externally_modified (self, FALSE);
 
       gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (self), &begin);
@@ -1126,8 +1125,7 @@ editor_document_do_load (EditorDocument *self,
 
   if (self->encoding != NULL)
     {
-      const GtkSourceEncoding *encoding = gtk_source_encoding_get_from_charset (self->encoding);
-      GSList encodings = { .next = NULL, .data = (gpointer)encoding };
+      GSList encodings = { .next = NULL, .data = (gpointer)self->encoding };
       gtk_source_file_loader_set_candidate_encodings (loader, &encodings);
     }
 
@@ -1623,17 +1621,27 @@ _editor_document_get_was_restored (EditorDocument *self)
 }
 
 void
-_editor_document_set_encoding (EditorDocument *self,
-                               const char     *encoding)
+_editor_document_set_encoding (EditorDocument          *self,
+                               const GtkSourceEncoding *encoding)
 {
   g_return_if_fail (EDITOR_IS_DOCUMENT (self));
 
-  if (g_strcmp0 (encoding, "auto") == 0)
-    encoding = NULL;
+  self->encoding = encoding;
+}
 
-  if (g_strcmp0 (self->encoding, encoding) != 0)
-    {
-      g_free (self->encoding);
-      self->encoding = g_strdup (encoding);
-    }
+GtkSourceNewlineType
+_editor_document_get_newline_type (EditorDocument *self)
+{
+  g_return_val_if_fail (EDITOR_IS_DOCUMENT (self), 0);
+
+  return self->newline_type;
+}
+
+void
+_editor_document_set_newline_type (EditorDocument       *self,
+                                   GtkSourceNewlineType  newline_type)
+{
+  g_return_if_fail (EDITOR_IS_DOCUMENT (self));
+
+  self->newline_type = newline_type;
 }
diff --git a/src/editor-page.c b/src/editor-page.c
index b3407f2..d28ee8f 100644
--- a/src/editor-page.c
+++ b/src/editor-page.c
@@ -836,11 +836,16 @@ editor_page_save_as_cb (EditorPage           *self,
       g_autoptr(GFile) dest = NULL;
 
       if ((dest = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (native))))
-        _editor_document_save_async (self->document,
-                                     dest,
-                                     NULL,
-                                     editor_page_save_cb,
-                                     g_object_ref (self));
+        {
+          GtkSourceNewlineType crlf = _editor_file_chooser_get_line_ending (GTK_FILE_CHOOSER (native));
+
+          _editor_document_set_newline_type (self->document, crlf);
+          _editor_document_save_async (self->document,
+                                       dest,
+                                       NULL,
+                                       editor_page_save_cb,
+                                       g_object_ref (self));
+        }
     }
 
   gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (native));
@@ -863,6 +868,10 @@ _editor_page_save_as (EditorPage *self)
                                         _("Save"),
                                         _("Cancel"));
 
+  _editor_file_chooser_add_encodings (GTK_FILE_CHOOSER (native));
+  _editor_file_chooser_add_line_endings (GTK_FILE_CHOOSER (native),
+                                         _editor_document_get_newline_type (self->document));
+
   g_signal_connect_object (native,
                            "response",
                            G_CALLBACK (editor_page_save_as_cb),
diff --git a/src/editor-session.c b/src/editor-session.c
index 5f05e0d..62e8b71 100644
--- a/src/editor-session.c
+++ b/src/editor-session.c
@@ -1214,10 +1214,10 @@ get_draft_id_for_file (EditorSession *self,
 }
 
 EditorPage *
-editor_session_open (EditorSession *self,
-                     EditorWindow  *window,
-                     GFile         *file,
-                     const char    *encoding)
+editor_session_open (EditorSession           *self,
+                     EditorWindow            *window,
+                     GFile                   *file,
+                     const GtkSourceEncoding *encoding)
 {
   g_autoptr(EditorDocument) document = NULL;
   g_autofree gchar *uri = NULL;
diff --git a/src/editor-session.h b/src/editor-session.h
index f7487e9..ab5aa5b 100644
--- a/src/editor-session.h
+++ b/src/editor-session.h
@@ -30,57 +30,57 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (EditorSession, editor_session, EDITOR, SESSION, GObject)
 
-void          editor_session_add_window          (EditorSession        *self,
-                                                  EditorWindow         *window);
-EditorWindow *editor_session_create_window       (EditorSession        *self);
-GListModel   *editor_session_get_recents         (EditorSession        *self);
-EditorPage   *editor_session_open                (EditorSession        *self,
-                                                  EditorWindow         *window,
-                                                  GFile                *file,
-                                                  const char           *encoding);
-void          editor_session_open_files          (EditorSession        *self,
-                                                  GFile               **files,
-                                                  gint                  n_files);
-void          editor_session_add_page            (EditorSession        *self,
-                                                  EditorWindow         *window,
-                                                  EditorPage           *page);
-EditorPage   *editor_session_add_document        (EditorSession        *self,
-                                                  EditorWindow         *window,
-                                                  EditorDocument       *document);
-EditorPage   *editor_session_add_draft           (EditorSession        *self,
-                                                  EditorWindow         *window);
-void          editor_session_remove_page         (EditorSession        *self,
-                                                  EditorPage           *page);
-void          editor_session_remove_document     (EditorSession        *self,
-                                                  EditorDocument       *document);
-EditorPage   *editor_session_find_page_by_file   (EditorSession        *self,
-                                                  GFile                *file);
-void          editor_session_restore_async       (EditorSession        *self,
-                                                  GCancellable         *cancellable,
-                                                  GAsyncReadyCallback   callback,
-                                                  gpointer              user_data);
-gboolean      editor_session_restore_finish      (EditorSession        *self,
-                                                  GAsyncResult         *result,
-                                                  GError              **error);
-void          editor_session_save_async          (EditorSession        *self,
-                                                  GCancellable         *cancellable,
-                                                  GAsyncReadyCallback   callback,
-                                                  gpointer              user_data);
-gboolean      editor_session_save_finish         (EditorSession        *self,
-                                                  GAsyncResult         *result,
-                                                  GError              **error);
-void          editor_session_load_recent_async   (EditorSession        *self,
-                                                  GCancellable         *cancellable,
-                                                  GAsyncReadyCallback   callback,
-                                                  gpointer              user_data);
-GPtrArray    *editor_session_load_recent_finish  (EditorSession        *self,
-                                                  GAsyncResult         *result,
-                                                  GError              **error);
-gboolean      editor_session_get_auto_save       (EditorSession        *self);
-void          editor_session_set_auto_save       (EditorSession        *self,
-                                                  gboolean              auto_save);
-guint         editor_session_get_auto_save_delay (EditorSession        *self);
-void          editor_session_set_auto_save_delay (EditorSession        *self,
-                                                  guint                 auto_save_delay);
+void          editor_session_add_window          (EditorSession            *self,
+                                                  EditorWindow             *window);
+EditorWindow *editor_session_create_window       (EditorSession            *self);
+GListModel   *editor_session_get_recents         (EditorSession            *self);
+EditorPage   *editor_session_open                (EditorSession            *self,
+                                                  EditorWindow             *window,
+                                                  GFile                    *file,
+                                                  const GtkSourceEncoding  *encoding);
+void          editor_session_open_files          (EditorSession            *self,
+                                                  GFile                   **files,
+                                                  gint                      n_files);
+void          editor_session_add_page            (EditorSession            *self,
+                                                  EditorWindow             *window,
+                                                  EditorPage               *page);
+EditorPage   *editor_session_add_document        (EditorSession            *self,
+                                                  EditorWindow             *window,
+                                                  EditorDocument           *document);
+EditorPage   *editor_session_add_draft           (EditorSession            *self,
+                                                  EditorWindow             *window);
+void          editor_session_remove_page         (EditorSession            *self,
+                                                  EditorPage               *page);
+void          editor_session_remove_document     (EditorSession            *self,
+                                                  EditorDocument           *document);
+EditorPage   *editor_session_find_page_by_file   (EditorSession            *self,
+                                                  GFile                    *file);
+void          editor_session_restore_async       (EditorSession            *self,
+                                                  GCancellable             *cancellable,
+                                                  GAsyncReadyCallback       callback,
+                                                  gpointer                  user_data);
+gboolean      editor_session_restore_finish      (EditorSession            *self,
+                                                  GAsyncResult             *result,
+                                                  GError                  **error);
+void          editor_session_save_async          (EditorSession            *self,
+                                                  GCancellable             *cancellable,
+                                                  GAsyncReadyCallback       callback,
+                                                  gpointer                  user_data);
+gboolean      editor_session_save_finish         (EditorSession            *self,
+                                                  GAsyncResult             *result,
+                                                  GError                  **error);
+void          editor_session_load_recent_async   (EditorSession            *self,
+                                                  GCancellable             *cancellable,
+                                                  GAsyncReadyCallback       callback,
+                                                  gpointer                  user_data);
+GPtrArray    *editor_session_load_recent_finish  (EditorSession            *self,
+                                                  GAsyncResult             *result,
+                                                  GError                  **error);
+gboolean      editor_session_get_auto_save       (EditorSession            *self);
+void          editor_session_set_auto_save       (EditorSession            *self,
+                                                  gboolean                  auto_save);
+guint         editor_session_get_auto_save_delay (EditorSession            *self);
+void          editor_session_set_auto_save_delay (EditorSession            *self,
+                                                  guint                     auto_save_delay);
 
 G_END_DECLS
diff --git a/src/editor-utils-private.h b/src/editor-utils-private.h
index 40c8152..b7fe25a 100644
--- a/src/editor-utils-private.h
+++ b/src/editor-utils-private.h
@@ -20,32 +20,39 @@
 
 #pragma once
 
+#include <gtksourceview/gtksource.h>
+
 #include "editor-types.h"
 
 G_BEGIN_DECLS
 
-gchar    *_editor_font_description_to_css        (const PangoFontDescription *font_desc);
-void      _editor_widget_hide_with_fade          (GtkWidget                  *widget);
-gboolean  _editor_gchararray_to_boolean          (GBinding                   *binding,
-                                                  const GValue               *from_value,
-                                                  GValue                     *to_value,
-                                                  gpointer                    user_data);
-gboolean  _editor_gboolean_to_wrap_mode          (GBinding                   *binding,
-                                                  const GValue               *from_value,
-                                                  GValue                     *to_value,
-                                                  gpointer                    user_data);
-gboolean  _editor_gboolean_to_background_pattern (GBinding                   *binding,
-                                                  const GValue               *from_value,
-                                                  GValue                     *to_value,
-                                                  gpointer                    user_data);
-gboolean  _editor_gboolean_to_scroll_policy      (GBinding                   *binding,
-                                                  const GValue               *from_value,
-                                                  GValue                     *to_value,
-                                                  gpointer                    user_data);
-gboolean  _editor_gchararray_to_style_scheme     (GBinding                   *binding,
-                                                  const GValue               *from_value,
-                                                  GValue                     *to_value,
-                                                  gpointer                    user_data);
-gchar    *_editor_date_time_format               (GDateTime                  *self);
+char                    *_editor_font_description_to_css        (const PangoFontDescription *font_desc);
+void                     _editor_widget_hide_with_fade          (GtkWidget                  *widget);
+gboolean                 _editor_gchararray_to_boolean          (GBinding                   *binding,
+                                                                 const GValue               *from_value,
+                                                                 GValue                     *to_value,
+                                                                 gpointer                    user_data);
+gboolean                 _editor_gboolean_to_wrap_mode          (GBinding                   *binding,
+                                                                 const GValue               *from_value,
+                                                                 GValue                     *to_value,
+                                                                 gpointer                    user_data);
+gboolean                 _editor_gboolean_to_background_pattern (GBinding                   *binding,
+                                                                 const GValue               *from_value,
+                                                                 GValue                     *to_value,
+                                                                 gpointer                    user_data);
+gboolean                 _editor_gboolean_to_scroll_policy      (GBinding                   *binding,
+                                                                 const GValue               *from_value,
+                                                                 GValue                     *to_value,
+                                                                 gpointer                    user_data);
+gboolean                 _editor_gchararray_to_style_scheme     (GBinding                   *binding,
+                                                                 const GValue               *from_value,
+                                                                 GValue                     *to_value,
+                                                                 gpointer                    user_data);
+char                    *_editor_date_time_format               (GDateTime                  *self);
+void                     _editor_file_chooser_add_encodings     (GtkFileChooser             *chooser);
+void                     _editor_file_chooser_add_line_endings  (GtkFileChooser             *chooser,
+                                                                 GtkSourceNewlineType        selected);
+const GtkSourceEncoding *_editor_file_chooser_get_encoding      (GtkFileChooser             *chooser);
+GtkSourceNewlineType     _editor_file_chooser_get_line_ending   (GtkFileChooser             *chooser);
 
 G_END_DECLS
diff --git a/src/editor-utils.c b/src/editor-utils.c
index 66b735c..f80330d 100644
--- a/src/editor-utils.c
+++ b/src/editor-utils.c
@@ -337,3 +337,141 @@ _editor_date_time_format (GDateTime *self)
 
   return g_strdup_printf (ngettext ("About %u year ago", "About %u years ago", years), years);
 }
+
+static const struct {
+  GtkSourceNewlineType type;
+  const char *id;
+  const char *label;
+} line_endings[] = {
+  { GTK_SOURCE_NEWLINE_TYPE_LF, "unix", N_("Unix/Linux") },
+  { GTK_SOURCE_NEWLINE_TYPE_CR, "mac", N_("Mac OS Classic") },
+  { GTK_SOURCE_NEWLINE_TYPE_CR_LF, "windows", N_("Windows") },
+};
+
+static int
+sort_by_name (gconstpointer a,
+              gconstpointer b)
+{
+  return g_strcmp0 (gtk_source_encoding_get_name (a),
+                    gtk_source_encoding_get_name (b));
+}
+
+void
+_editor_file_chooser_add_encodings (GtkFileChooser *chooser)
+{
+  GPtrArray *choices;
+  GPtrArray *labels;
+  GSList *all;
+
+  g_assert (GTK_IS_FILE_CHOOSER (chooser));
+
+  all = g_slist_sort (gtk_source_encoding_get_all (), sort_by_name);
+  choices = g_ptr_array_new ();
+  labels = g_ptr_array_new_with_free_func (g_free);
+
+#define ADD_ENCODING(id, name)             \
+  G_STMT_START {                           \
+    g_ptr_array_add(choices, (char *)id);  \
+    g_ptr_array_add(labels, (char *)name); \
+  } G_STMT_END
+
+  ADD_ENCODING ("auto", g_strdup (N_("Automatically Detected")));
+
+  for (const GSList *l = all; l; l = l->next)
+    {
+      GtkSourceEncoding *encoding = l->data;
+      char *title = g_strdup_printf ("%s (%s)",
+                                     gtk_source_encoding_get_name (encoding),
+                                     gtk_source_encoding_get_charset (encoding));
+      ADD_ENCODING (gtk_source_encoding_get_charset (encoding), title);
+    }
+
+  ADD_ENCODING (NULL, NULL);
+#undef ADD_ENCODING
+
+  gtk_file_chooser_add_choice (chooser,
+                               "encoding",
+                               _("Character Encoding:"),
+                               (const char **)(gpointer)choices->pdata,
+                               (const char **)(gpointer)labels->pdata);
+  gtk_file_chooser_set_choice (chooser, "encoding", "auto");
+
+  g_slist_free (all);
+  g_clear_pointer (&choices, g_ptr_array_unref);
+  g_clear_pointer (&labels, g_ptr_array_unref);
+}
+
+void
+_editor_file_chooser_add_line_endings (GtkFileChooser       *chooser,
+                                       GtkSourceNewlineType  selected)
+{
+  static GArray *choices;
+  static GArray *labels;
+
+  g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser));
+
+  if (choices == NULL)
+    {
+      choices = g_array_new (TRUE, FALSE, sizeof (char *));
+      labels = g_array_new (TRUE, FALSE, sizeof (char *));
+
+      for (guint i = 0; i < G_N_ELEMENTS (line_endings); i++)
+        {
+          const char *msg = g_dgettext (GETTEXT_PACKAGE, line_endings[i].label);
+
+          g_array_append_val (choices, line_endings[i].id);
+          g_array_append_val (labels, msg);
+        }
+    }
+
+  gtk_file_chooser_add_choice (chooser,
+                               "line-ending",
+                               _("Line Ending:"),
+                               (const char **)(gpointer)choices->data,
+                               (const char **)(gpointer)labels->data);
+  gtk_file_chooser_set_choice (chooser, "line-endings", "unix");
+
+  for (guint i = 0; i < G_N_ELEMENTS (line_endings); i++)
+    {
+      if (line_endings[i].type == selected)
+        {
+          gtk_file_chooser_set_choice (chooser, "line-endings", line_endings[i].id);
+          break;
+        }
+    }
+}
+
+const GtkSourceEncoding *
+_editor_file_chooser_get_encoding (GtkFileChooser *chooser)
+{
+  const char *encoding;
+
+  g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
+
+  if ((encoding = gtk_file_chooser_get_choice (chooser, "encoding")))
+    {
+      if (strcmp (encoding, "auto") != 0)
+        return gtk_source_encoding_get_from_charset (encoding);
+    }
+
+  return NULL;
+}
+
+GtkSourceNewlineType
+_editor_file_chooser_get_line_ending (GtkFileChooser *chooser)
+{
+  const char *ending;
+
+  g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), 0);
+
+  if ((ending = gtk_file_chooser_get_choice (chooser, "line-ending")))
+    {
+      for (guint i = 0; i < G_N_ELEMENTS (line_endings); i++)
+        {
+          if (g_strcmp0 (ending, line_endings[i].id) == 0)
+            return line_endings[i].type;
+        }
+    }
+
+  return GTK_SOURCE_NEWLINE_TYPE_LF;
+}
diff --git a/src/editor-window-actions.c b/src/editor-window-actions.c
index 9ad0ffa..80c57ce 100644
--- a/src/editor-window-actions.c
+++ b/src/editor-window-actions.c
@@ -306,7 +306,7 @@ editor_window_actions_open_response_cb (EditorWindow         *self,
   if (response_id == GTK_RESPONSE_ACCEPT)
     {
       g_autoptr(GFile) file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (native));
-      const char *encoding = gtk_file_chooser_get_choice (GTK_FILE_CHOOSER (native), "encoding");
+      const GtkSourceEncoding *encoding = _editor_file_chooser_get_encoding (GTK_FILE_CHOOSER (native));
 
       editor_session_open (EDITOR_SESSION_DEFAULT, self, file, encoding);
     }
@@ -314,59 +314,6 @@ editor_window_actions_open_response_cb (EditorWindow         *self,
   gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (native));
 }
 
-static int
-sort_by_name (gconstpointer a,
-              gconstpointer b)
-{
-  return g_strcmp0 (gtk_source_encoding_get_name (a),
-                    gtk_source_encoding_get_name (b));
-}
-
-static void
-editor_window_actions_add_encodings (GtkFileChooser *chooser)
-{
-  GPtrArray *choices;
-  GPtrArray *labels;
-  GSList *all;
-
-  g_assert (GTK_IS_FILE_CHOOSER (chooser));
-
-  all = g_slist_sort (gtk_source_encoding_get_all (), sort_by_name);
-  choices = g_ptr_array_new ();
-  labels = g_ptr_array_new_with_free_func (g_free);
-
-#define ADD_ENCODING(id, name)             \
-  G_STMT_START {                           \
-    g_ptr_array_add(choices, (char *)id);  \
-    g_ptr_array_add(labels, (char *)name); \
-  } G_STMT_END
-
-  ADD_ENCODING ("auto", g_strdup (N_("Automatically Detected")));
-
-  for (const GSList *l = all; l; l = l->next)
-    {
-      GtkSourceEncoding *encoding = l->data;
-      char *title = g_strdup_printf ("%s (%s)",
-                                     gtk_source_encoding_get_name (encoding),
-                                     gtk_source_encoding_get_charset (encoding));
-      ADD_ENCODING (gtk_source_encoding_get_charset (encoding), title);
-    }
-
-  ADD_ENCODING (NULL, NULL);
-#undef ADD_ENCODING
-
-  gtk_file_chooser_add_choice (chooser,
-                               "encoding",
-                               _("Character Encoding:"),
-                               (const char **)(gpointer)choices->pdata,
-                               (const char **)(gpointer)labels->pdata);
-  gtk_file_chooser_set_choice (chooser, "encoding", "auto");
-
-  g_slist_free (all);
-  g_clear_pointer (&choices, g_ptr_array_unref);
-  g_clear_pointer (&labels, g_ptr_array_unref);
-}
-
 static void
 editor_window_actions_open_cb (GtkWidget  *widget,
                                const char *action_name,
@@ -417,7 +364,7 @@ editor_window_actions_open_cb (GtkWidget  *widget,
   gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (native), text_files);
 #endif
 
-  editor_window_actions_add_encodings (GTK_FILE_CHOOSER (native));
+  _editor_file_chooser_add_encodings (GTK_FILE_CHOOSER (native));
 
   g_signal_connect_object (native,
                            "response",


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]