[gnome-text-editor] session: allow opening documents with specific encoding



commit bd25fba6f2232499eeebe7cc634e0c3bcc00822f
Author: Christian Hergert <chergert redhat com>
Date:   Tue Jun 22 16:39:12 2021 -0700

    session: allow opening documents with specific encoding
    
    And also keep that encoding when saving back to disk if it was specified.

 src/editor-document-private.h |  2 ++
 src/editor-document.c         | 37 ++++++++++++++++++++++++++
 src/editor-page.c             |  2 +-
 src/editor-session.c          |  6 +++--
 src/editor-session.h          |  3 ++-
 src/editor-sidebar-item.c     |  3 ++-
 src/editor-window-actions.c   | 60 +++++++++++++++++++++++++++++++++++++++++--
 src/editor-window-dnd.c       |  2 +-
 8 files changed, 107 insertions(+), 8 deletions(-)
---
diff --git a/src/editor-document-private.h b/src/editor-document-private.h
index c44b398..b6efa25 100644
--- a/src/editor-document-private.h
+++ b/src/editor-document-private.h
@@ -38,6 +38,8 @@ void            _editor_document_set_externally_modified (EditorDocument       *
 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,
diff --git a/src/editor-document.c b/src/editor-document.c
index 88a6ccd..b5d7f14 100644
--- a/src/editor-document.c
+++ b/src/editor-document.c
@@ -43,6 +43,7 @@ struct _EditorDocument
   GtkSourceFile       *file;
   gchar               *draft_id;
   GtkTextTag          *line_spacing_tag;
+  char                *encoding;
 
   guint                busy_count;
   gdouble              busy_progress;
@@ -311,6 +312,7 @@ 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);
 }
@@ -616,6 +618,12 @@ _editor_document_save_draft_async (EditorDocument      *self,
                                    (GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_INVALID_CHARS |
                                     GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_MODIFICATION_TIME));
 
+  if (self->encoding != NULL)
+    {
+      const GtkSourceEncoding *encoding = gtk_source_encoding_get_from_charset (self->encoding);
+      gtk_source_file_saver_set_encoding (saver, encoding);
+    }
+
   /* TODO: Probably want to make this async. We can just create an
    * async variant in editor-utils.c for this.
    */
@@ -853,6 +861,12 @@ _editor_document_save_async (EditorDocument      *self,
                                    (GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_INVALID_CHARS |
                                     GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_MODIFICATION_TIME));
 
+  if (self->encoding != NULL)
+    {
+      const GtkSourceEncoding *encoding = gtk_source_encoding_get_from_charset (self->encoding);
+      gtk_source_file_saver_set_encoding (saver, encoding);
+    }
+
   _editor_document_mark_busy (self);
 
   editor_document_set_busy_progress (self, 0, 2, .25);
@@ -1110,6 +1124,13 @@ editor_document_do_load (EditorDocument *self,
 
   loader = gtk_source_file_loader_new (GTK_SOURCE_BUFFER (self), file);
 
+  if (self->encoding != NULL)
+    {
+      const GtkSourceEncoding *encoding = gtk_source_encoding_get_from_charset (self->encoding);
+      GSList encodings = { .next = NULL, .data = (gpointer)encoding };
+      gtk_source_file_loader_set_candidate_encodings (loader, &encodings);
+    }
+
   gtk_source_file_loader_load_async (loader,
                                      G_PRIORITY_DEFAULT,
                                      g_task_get_cancellable (task),
@@ -1600,3 +1621,19 @@ _editor_document_get_was_restored (EditorDocument *self)
 
   return self->was_restored;
 }
+
+void
+_editor_document_set_encoding (EditorDocument *self,
+                               const char     *encoding)
+{
+  g_return_if_fail (EDITOR_IS_DOCUMENT (self));
+
+  if (g_strcmp0 (encoding, "auto") == 0)
+    encoding = NULL;
+
+  if (g_strcmp0 (self->encoding, encoding) != 0)
+    {
+      g_free (self->encoding);
+      self->encoding = g_strdup (encoding);
+    }
+}
diff --git a/src/editor-page.c b/src/editor-page.c
index acacb39..b3407f2 100644
--- a/src/editor-page.c
+++ b/src/editor-page.c
@@ -346,7 +346,7 @@ editor_page_drop_target_drop (EditorPage     *self,
       EditorSession *session = editor_application_get_session (EDITOR_APPLICATION_DEFAULT);
       EditorWindow *window = EDITOR_WINDOW (gtk_widget_get_root (GTK_WIDGET (self)));
 
-      editor_session_open (session, window, file);
+      editor_session_open (session, window, file, NULL);
     }
 
   return FALSE;
diff --git a/src/editor-session.c b/src/editor-session.c
index 3404ed6..5f05e0d 100644
--- a/src/editor-session.c
+++ b/src/editor-session.c
@@ -1216,7 +1216,8 @@ get_draft_id_for_file (EditorSession *self,
 EditorPage *
 editor_session_open (EditorSession *self,
                      EditorWindow  *window,
-                     GFile         *file)
+                     GFile         *file,
+                     const char    *encoding)
 {
   g_autoptr(EditorDocument) document = NULL;
   g_autofree gchar *uri = NULL;
@@ -1245,6 +1246,7 @@ editor_session_open (EditorSession *self,
     remove = page;
 
   document = editor_document_new_for_file (file);
+  _editor_document_set_encoding (document, encoding);
 
   if ((draft_id = get_draft_id_for_file (self, file)))
     _editor_document_set_draft_id (document, draft_id);
@@ -1268,7 +1270,7 @@ editor_session_open_files (EditorSession  *self,
   g_return_if_fail (EDITOR_IS_SESSION (self));
 
   for (guint i = 0; i < n_files; i++)
-    editor_session_open (self, NULL, files[i]);
+    editor_session_open (self, NULL, files[i], NULL);
 }
 
 /**
diff --git a/src/editor-session.h b/src/editor-session.h
index 1f77bb9..f7487e9 100644
--- a/src/editor-session.h
+++ b/src/editor-session.h
@@ -36,7 +36,8 @@ EditorWindow *editor_session_create_window       (EditorSession        *self);
 GListModel   *editor_session_get_recents         (EditorSession        *self);
 EditorPage   *editor_session_open                (EditorSession        *self,
                                                   EditorWindow         *window,
-                                                  GFile                *file);
+                                                  GFile                *file,
+                                                  const char           *encoding);
 void          editor_session_open_files          (EditorSession        *self,
                                                   GFile               **files,
                                                   gint                  n_files);
diff --git a/src/editor-sidebar-item.c b/src/editor-sidebar-item.c
index 2873198..5bb25bc 100644
--- a/src/editor-sidebar-item.c
+++ b/src/editor-sidebar-item.c
@@ -485,7 +485,8 @@ _editor_sidebar_item_open (EditorSidebarItem *self,
   if (self->page != NULL)
     _editor_page_raise (self->page);
   else if (self->file != NULL)
-    editor_session_open (session, window, self->file);
+    /* TODO: This should stash the encoding and reuse it */
+    editor_session_open (session, window, self->file, NULL);
   else if (self->draft_id != NULL)
     _editor_session_open_draft (session, window, self->draft_id);
   else
diff --git a/src/editor-window-actions.c b/src/editor-window-actions.c
index 660beee..9ad0ffa 100644
--- a/src/editor-window-actions.c
+++ b/src/editor-window-actions.c
@@ -306,13 +306,67 @@ 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");
 
-      editor_session_open (EDITOR_SESSION_DEFAULT, self, file);
+      editor_session_open (EDITOR_SESSION_DEFAULT, self, file, encoding);
     }
 
   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,
@@ -357,12 +411,14 @@ editor_window_actions_open_cb (GtkWidget  *widget,
   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), g_object_ref (text_files));
 
 #ifdef __APPLE__
-  /* Apple cotent-type detect is pretty bad */
+  /* Apple content-type detect is pretty bad */
   gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (native), all_files);
 #else
   gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (native), text_files);
 #endif
 
+  editor_window_actions_add_encodings (GTK_FILE_CHOOSER (native));
+
   g_signal_connect_object (native,
                            "response",
                            G_CALLBACK (editor_window_actions_open_response_cb),
diff --git a/src/editor-window-dnd.c b/src/editor-window-dnd.c
index 1d1261e..607f1b5 100644
--- a/src/editor-window-dnd.c
+++ b/src/editor-window-dnd.c
@@ -50,7 +50,7 @@ editor_window_dnd_drag_data_received_cb (EditorWindow     *self,
       g_autoptr(GFile) file = g_file_new_for_uri (uris[i]);
 
       if (file != NULL)
-        editor_session_open (EDITOR_SESSION_DEFAULT, self, file);
+        editor_session_open (EDITOR_SESSION_DEFAULT, self, file, NULL);
     }
 
   gtk_window_present_with_time (GTK_WINDOW (self), time_);


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