[gedit] Added new GeditDocumentInputStream for doc save
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gedit] Added new GeditDocumentInputStream for doc save
- Date: Sat, 23 Jan 2010 19:38:00 +0000 (UTC)
commit be71072115d6b78b47683ce8b898bdfdf19c3018
Author: Jesse van den Kieboom <jesse icecrew nl>
Date: Sat Jan 23 20:13:46 2010 +0100
Added new GeditDocumentInputStream for doc save
gedit/Makefile.am | 2 +
gedit/gedit-document-input-stream.c | 425 +++++++++++++++++++++++++++++++++++
gedit/gedit-document-input-stream.h | 68 ++++++
gedit/gedit-document-loader.c | 28 +++
gedit/gedit-document-loader.h | 3 +
gedit/gedit-document-saver.c | 36 +++-
gedit/gedit-document-saver.h | 10 +-
gedit/gedit-document.c | 63 +++++-
gedit/gedit-document.h | 19 ++
gedit/gedit-gio-document-loader.c | 87 +++++++-
gedit/gedit-gio-document-saver.c | 250 ++++++++++++---------
11 files changed, 856 insertions(+), 135 deletions(-)
---
diff --git a/gedit/Makefile.am b/gedit/Makefile.am
index 0c54c47..5757ac0 100644
--- a/gedit/Makefile.am
+++ b/gedit/Makefile.am
@@ -65,6 +65,7 @@ endif
NOINST_H_FILES = \
gedit-close-button.h \
gedit-dirs.h \
+ gedit-document-input-stream.h \
gedit-document-loader.h \
gedit-document-saver.h \
gedit-documents-panel.h \
@@ -151,6 +152,7 @@ libgedit_la_SOURCES = \
gedit-debug.c \
gedit-dirs.c \
gedit-document.c \
+ gedit-document-input-stream.c \
gedit-document-loader.c \
gedit-gio-document-loader.c \
gedit-document-saver.c \
diff --git a/gedit/gedit-document-input-stream.c b/gedit/gedit-document-input-stream.c
new file mode 100644
index 0000000..0bd5900
--- /dev/null
+++ b/gedit/gedit-document-input-stream.c
@@ -0,0 +1,425 @@
+/*
+ * gedit-document-input-stream.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+
+#include "config.h"
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <string.h>
+
+#include "gedit-document-input-stream.h"
+#include "gedit-enum-types.h"
+
+G_DEFINE_TYPE (GeditDocumentInputStream, gedit_document_input_stream, G_TYPE_INPUT_STREAM);
+
+struct _GeditDocumentInputStreamPrivate
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter pos;
+ guint bytes_partial;
+
+ GeditDocumentNewlineType newline_type;
+
+ guint newline_added : 1;
+ guint is_initialized : 1;
+};
+
+enum
+{
+ PROP_0,
+ PROP_BUFFER,
+ PROP_NEWLINE_TYPE
+};
+
+static gssize gedit_document_input_stream_read (GInputStream *stream,
+ void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error);
+static gboolean gedit_document_input_stream_close (GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error);
+
+static void
+gedit_document_input_stream_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GeditDocumentInputStream *stream = GEDIT_DOCUMENT_INPUT_STREAM (object);
+
+ switch (prop_id)
+ {
+ case PROP_BUFFER:
+ stream->priv->buffer = GTK_TEXT_BUFFER (g_value_get_object (value));
+ break;
+
+ case PROP_NEWLINE_TYPE:
+ stream->priv->newline_type = g_value_get_enum (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_document_input_stream_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditDocumentInputStream *stream = GEDIT_DOCUMENT_INPUT_STREAM (object);
+
+ switch (prop_id)
+ {
+ case PROP_BUFFER:
+ g_value_set_object (value, stream->priv->buffer);
+ break;
+
+ case PROP_NEWLINE_TYPE:
+ g_value_set_enum (value, stream->priv->newline_type);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_document_input_stream_class_init (GeditDocumentInputStreamClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GeditDocumentInputStreamPrivate));
+
+ gobject_class->get_property = gedit_document_input_stream_get_property;
+ gobject_class->set_property = gedit_document_input_stream_set_property;
+
+ stream_class->read_fn = gedit_document_input_stream_read;
+ stream_class->close_fn = gedit_document_input_stream_close;
+
+ g_object_class_install_property (gobject_class,
+ PROP_BUFFER,
+ g_param_spec_object ("buffer",
+ "Buffer",
+ "The buffer which is read",
+ GTK_TYPE_TEXT_BUFFER,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ /**
+ * GeditDocumentInputStream:newline-type:
+ *
+ * The :newline-type property determines what is considered
+ * as a line ending when reading complete lines from the stream.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_NEWLINE_TYPE,
+ g_param_spec_enum ("newline-type",
+ "Newline type",
+ "The accepted types of line ending",
+ GEDIT_TYPE_DOCUMENT_NEWLINE_TYPE,
+ GEDIT_DOCUMENT_NEWLINE_TYPE_LF,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gedit_document_input_stream_init (GeditDocumentInputStream *stream)
+{
+ stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
+ GEDIT_TYPE_DOCUMENT_INPUT_STREAM,
+ GeditDocumentInputStreamPrivate);
+}
+
+static gsize
+get_new_line_size (GeditDocumentInputStream *stream)
+{
+ gsize ret;
+
+ switch (stream->priv->newline_type)
+ {
+ case GEDIT_DOCUMENT_NEWLINE_TYPE_CR:
+ case GEDIT_DOCUMENT_NEWLINE_TYPE_LF:
+ ret = 1;
+ break;
+
+ case GEDIT_DOCUMENT_NEWLINE_TYPE_CR_LF:
+ ret = 2;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * gedit_document_input_stream_new:
+ * @buffer: a #GtkTextBuffer
+ *
+ * Reads the data from @buffer.
+ *
+ * Returns: a new #GInputStream to read @buffer
+ */
+GInputStream *
+gedit_document_input_stream_new (GtkTextBuffer *buffer,
+ GeditDocumentNewlineType type)
+{
+ GeditDocumentInputStream *stream;
+
+ g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+
+ stream = g_object_new (GEDIT_TYPE_DOCUMENT_INPUT_STREAM,
+ "buffer", buffer,
+ "newline-type", type,
+ NULL);
+
+ return G_INPUT_STREAM (stream);
+}
+
+gsize
+gedit_document_input_stream_get_total_size (GeditDocumentInputStream *stream)
+{
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT_INPUT_STREAM (stream), 0);
+
+ return gtk_text_buffer_get_char_count (stream->priv->buffer);
+}
+
+gsize
+gedit_document_input_stream_tell (GeditDocumentInputStream *stream)
+{
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT_INPUT_STREAM (stream), 0);
+
+ /* FIXME: is this potentially inefficient? If yes, we could keep
+ track of the offset internally, assuming the mark doesn't move
+ during the operation */
+ if (!stream->priv->is_initialized)
+ {
+ return 0;
+ }
+ else
+ {
+ return gtk_text_iter_get_offset (&stream->priv->pos);
+ }
+}
+
+static const gchar *
+get_new_line (GeditDocumentInputStream *stream)
+{
+ const gchar *ret;
+
+ switch (stream->priv->newline_type)
+ {
+ case GEDIT_DOCUMENT_NEWLINE_TYPE_CR:
+ ret = "\r";
+ break;
+
+ case GEDIT_DOCUMENT_NEWLINE_TYPE_LF:
+ ret = "\n";
+ break;
+
+ case GEDIT_DOCUMENT_NEWLINE_TYPE_CR_LF:
+ ret = "\r\n";
+ break;
+ }
+
+ return ret;
+}
+
+static gsize
+read_line (GeditDocumentInputStream *stream,
+ gchar *outbuf,
+ gsize space_left)
+{
+ GtkTextIter *start, next, end;
+ gchar *buf;
+ gsize read, bytes, newline_size, bytes_to_write;
+ const gchar *newline;
+ gboolean is_last;
+
+ start = &stream->priv->pos;
+
+ end = next = *start;
+ newline = get_new_line (stream);
+ newline_size = get_new_line_size (stream);
+
+ if (gtk_text_iter_is_end (start))
+ return 0;
+
+ /* Check needed for empty lines */
+ if (!gtk_text_iter_ends_line (&end))
+ gtk_text_iter_forward_to_line_end (&end);
+
+ gtk_text_iter_forward_line (&next);
+
+ buf = gtk_text_iter_get_slice (start, &end);
+
+ /* the bytes of a line includes also the newline, so with the
+ offsets we remove the newline and we add the new newline size */
+ bytes = gtk_text_iter_get_bytes_in_line (start) - stream->priv->bytes_partial;
+
+ /* bytes_in_line includes the newlines, so we remove that assuming that
+ they are single byte characters */
+ bytes = bytes - (gtk_text_iter_get_offset (&next) - gtk_text_iter_get_offset (&end));
+ is_last = gtk_text_iter_is_end (&end);
+
+ /* bytes_to_write contains the amount of bytes we would like to write.
+ This means its the amount of bytes in the line (without the newline
+ in the buffer) + the amount of bytes for the newline we want to
+ write (newline_size) */
+ bytes_to_write = bytes;
+
+ /* do not add the new newline_size for the last line */
+ if (!is_last)
+ bytes_to_write += newline_size;
+
+ if (bytes_to_write > space_left)
+ {
+ gchar *ptr;
+ gint offset;
+ gsize to_write;
+ gsize next_size;
+
+ /* Here the line does not fit in the buffer, we thus write
+ the amount of bytes we can still fit, storing the position
+ for the next read with the mark. Do not try to write the
+ new newline in this case, it will be handled in the next
+ iteration */
+ to_write = MIN (space_left, bytes);
+ ptr = buf;
+ next_size = 0;
+ offset = 0;
+
+ do
+ {
+ read = next_size;
+ ptr = g_utf8_next_char (ptr);
+ next_size = ptr - buf;
+
+ ++offset;
+ } while (next_size <= to_write);
+
+ memcpy (outbuf, buf, read);
+
+ /* Note: offset is one past what we wrote */
+ gtk_text_iter_forward_chars (start, offset - 1);
+
+ stream->priv->bytes_partial += read;
+ }
+ else
+ {
+ /* First just copy the bytes without the newline */
+ memcpy (outbuf, buf, bytes);
+
+ /* Then add the newline, but not for the last line */
+ if (!is_last)
+ {
+ memcpy (outbuf + bytes, newline, newline_size);
+ }
+
+ read = bytes_to_write;
+ *start = next;
+
+ stream->priv->bytes_partial = 0;
+ }
+
+ g_free (buf);
+ return read;
+}
+
+static gssize
+gedit_document_input_stream_read (GInputStream *stream,
+ void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GeditDocumentInputStream *dstream;
+ gssize space_left, read, n, newline_size;
+
+ dstream = GEDIT_DOCUMENT_INPUT_STREAM (stream);
+
+ if (count < 6)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
+ "Not enougth space in destination");
+ return -1;
+ }
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return -1;
+
+ /* Initialize the mark to the first char in the text buffer */
+ if (!dstream->priv->is_initialized)
+ {
+ gtk_text_buffer_get_start_iter (dstream->priv->buffer, &dstream->priv->pos);
+ dstream->priv->is_initialized = TRUE;
+ }
+
+ space_left = count;
+ read = 0;
+
+ do
+ {
+ n = read_line (dstream, buffer + read, space_left);
+ read += n;
+ space_left -= n;
+ } while (space_left > 0 && n != 0 && dstream->priv->bytes_partial == 0);
+
+ /* make sure files are always terminated with \n (see bug #95676). Note
+ that we strip the trailing \n when loading the file */
+ newline_size = get_new_line_size (dstream);
+
+ if (gtk_text_iter_is_end (&dstream->priv->pos) &&
+ space_left >= newline_size &&
+ !dstream->priv->newline_added)
+ {
+ const gchar *newline;
+
+ newline = get_new_line (dstream);
+
+ memcpy (buffer + read, newline, newline_size);
+
+ read += newline_size;
+ dstream->priv->newline_added = TRUE;
+ }
+
+ return read;
+}
+
+static gboolean
+gedit_document_input_stream_close (GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GeditDocumentInputStream *dstream = GEDIT_DOCUMENT_INPUT_STREAM (stream);
+
+ dstream->priv->newline_added = FALSE;
+
+ return TRUE;
+}
diff --git a/gedit/gedit-document-input-stream.h b/gedit/gedit-document-input-stream.h
new file mode 100644
index 0000000..01f6a49
--- /dev/null
+++ b/gedit/gedit-document-input-stream.h
@@ -0,0 +1,68 @@
+/*
+ * gedit-document-input-stream.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GEDIT_DOCUMENT_INPUT_STREAM_H__
+#define __GEDIT_DOCUMENT_INPUT_STREAM_H__
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+#include "gedit-document.h"
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_DOCUMENT_INPUT_STREAM (gedit_document_input_stream_get_type ())
+#define GEDIT_DOCUMENT_INPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_DOCUMENT_INPUT_STREAM, GeditDocumentInputStream))
+#define GEDIT_DOCUMENT_INPUT_STREAM_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_DOCUMENT_INPUT_STREAM, GeditDocumentInputStream const))
+#define GEDIT_DOCUMENT_INPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_DOCUMENT_INPUT_STREAM, GeditDocumentInputStreamClass))
+#define GEDIT_IS_DOCUMENT_INPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_DOCUMENT_INPUT_STREAM))
+#define GEDIT_IS_DOCUMENT_INPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_DOCUMENT_INPUT_STREAM))
+#define GEDIT_DOCUMENT_INPUT_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_DOCUMENT_INPUT_STREAM, GeditDocumentInputStreamClass))
+
+typedef struct _GeditDocumentInputStream GeditDocumentInputStream;
+typedef struct _GeditDocumentInputStreamClass GeditDocumentInputStreamClass;
+typedef struct _GeditDocumentInputStreamPrivate GeditDocumentInputStreamPrivate;
+
+struct _GeditDocumentInputStream
+{
+ GInputStream parent;
+
+ GeditDocumentInputStreamPrivate *priv;
+};
+
+struct _GeditDocumentInputStreamClass
+{
+ GInputStreamClass parent_class;
+};
+
+GType gedit_document_input_stream_get_type (void) G_GNUC_CONST;
+
+GInputStream *gedit_document_input_stream_new (GtkTextBuffer *buffer,
+ GeditDocumentNewlineType type);
+
+gsize gedit_document_input_stream_get_total_size (GeditDocumentInputStream *stream);
+
+gsize gedit_document_input_stream_tell (GeditDocumentInputStream *stream);
+
+G_END_DECLS
+
+#endif /* __GEDIT_DOCUMENT_INPUT_STREAM_H__ */
diff --git a/gedit/gedit-document-loader.c b/gedit/gedit-document-loader.c
index 390c6c1..54d7bba 100644
--- a/gedit/gedit-document-loader.c
+++ b/gedit/gedit-document-loader.c
@@ -41,6 +41,7 @@
#include "gedit-utils.h"
#include "gedit-convert.h"
#include "gedit-marshal.h"
+#include "gedit-enum-types.h"
/* Those are for the the gedit_document_loader_new() factory */
#include "gedit-gio-document-loader.h"
@@ -64,6 +65,7 @@ enum
PROP_DOCUMENT,
PROP_URI,
PROP_ENCODING,
+ PROP_NEWLINE_TYPE
};
static void
@@ -88,6 +90,9 @@ gedit_document_loader_set_property (GObject *object,
g_return_if_fail (loader->encoding == NULL);
loader->encoding = g_value_get_boxed (value);
break;
+ case PROP_NEWLINE_TYPE:
+ loader->auto_detected_newline_type = g_value_get_enum (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -113,6 +118,9 @@ gedit_document_loader_get_property (GObject *object,
case PROP_ENCODING:
g_value_set_boxed (value, gedit_document_loader_get_encoding (loader));
break;
+ case PROP_NEWLINE_TYPE:
+ g_value_set_enum (value, loader->auto_detected_newline_type);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -185,6 +193,16 @@ gedit_document_loader_class_init (GeditDocumentLoaderClass *klass)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_NEWLINE_TYPE,
+ g_param_spec_enum ("newline-type",
+ "Newline type",
+ "The accepted types of line ending",
+ GEDIT_TYPE_DOCUMENT_NEWLINE_TYPE,
+ GEDIT_DOCUMENT_NEWLINE_TYPE_LF,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB));
+
signals[LOADING] =
g_signal_new ("loading",
G_OBJECT_CLASS_TYPE (object_class),
@@ -202,6 +220,7 @@ static void
gedit_document_loader_init (GeditDocumentLoader *loader)
{
loader->used = FALSE;
+ loader->auto_detected_newline_type = GEDIT_DOCUMENT_NEWLINE_TYPE_DEFAULT;
}
void
@@ -321,6 +340,15 @@ gedit_document_loader_get_encoding (GeditDocumentLoader *loader)
return loader->auto_detected_encoding;
}
+GeditDocumentNewlineType
+gedit_document_loader_get_newline_type (GeditDocumentLoader *loader)
+{
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT_LOADER (loader),
+ GEDIT_DOCUMENT_NEWLINE_TYPE_LF);
+
+ return loader->auto_detected_newline_type;
+}
+
GFileInfo *
gedit_document_loader_get_info (GeditDocumentLoader *loader)
{
diff --git a/gedit/gedit-document-loader.h b/gedit/gedit-document-loader.h
index 84bfcfb..a627fba 100644
--- a/gedit/gedit-document-loader.h
+++ b/gedit/gedit-document-loader.h
@@ -66,6 +66,7 @@ struct _GeditDocumentLoader
gchar *uri;
const GeditEncoding *encoding;
const GeditEncoding *auto_detected_encoding;
+ GeditDocumentNewlineType auto_detected_newline_type;
};
/*
@@ -116,6 +117,8 @@ const gchar *gedit_document_loader_get_uri (GeditDocumentLoader *loader);
const GeditEncoding *gedit_document_loader_get_encoding (GeditDocumentLoader *loader);
+GeditDocumentNewlineType gedit_document_loader_get_newline_type (GeditDocumentLoader *loader);
+
goffset gedit_document_loader_get_bytes_read (GeditDocumentLoader *loader);
/* You can get from the info: content_type, time_modified, standard_size, access_can_write
diff --git a/gedit/gedit-document-saver.c b/gedit/gedit-document-saver.c
index 1e58479..23377a8 100644
--- a/gedit/gedit-document-saver.c
+++ b/gedit/gedit-document-saver.c
@@ -66,6 +66,7 @@ enum {
PROP_DOCUMENT,
PROP_URI,
PROP_ENCODING,
+ PROP_NEWLINE_TYPE,
PROP_FLAGS
};
@@ -91,6 +92,9 @@ gedit_document_saver_set_property (GObject *object,
g_return_if_fail (saver->encoding == NULL);
saver->encoding = g_value_get_boxed (value);
break;
+ case PROP_NEWLINE_TYPE:
+ saver->newline_type = g_value_get_enum (value);
+ break;
case PROP_FLAGS:
saver->flags = g_value_get_flags (value);
break;
@@ -119,6 +123,9 @@ gedit_document_saver_get_property (GObject *object,
case PROP_ENCODING:
g_value_set_boxed (value, saver->encoding);
break;
+ case PROP_NEWLINE_TYPE:
+ g_value_set_enum (value, saver->newline_type);
+ break;
case PROP_FLAGS:
g_value_set_flags (value, saver->flags);
break;
@@ -194,6 +201,18 @@ gedit_document_saver_class_init (GeditDocumentSaverClass *klass)
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
+ PROP_NEWLINE_TYPE,
+ g_param_spec_enum ("newline-type",
+ "Newline type",
+ "The accepted types of line ending",
+ GEDIT_TYPE_DOCUMENT_NEWLINE_TYPE,
+ GEDIT_DOCUMENT_NEWLINE_TYPE_LF,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
PROP_FLAGS,
g_param_spec_flags ("flags",
"Flags",
@@ -223,22 +242,18 @@ gedit_document_saver_init (GeditDocumentSaver *saver)
}
GeditDocumentSaver *
-gedit_document_saver_new (GeditDocument *doc,
- const gchar *uri,
- const GeditEncoding *encoding,
- GeditDocumentSaveFlags flags)
+gedit_document_saver_new (GeditDocument *doc,
+ const gchar *uri,
+ const GeditEncoding *encoding,
+ GeditDocumentNewlineType newline_type,
+ GeditDocumentSaveFlags flags)
{
GeditDocumentSaver *saver;
GType saver_type;
g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), NULL);
-#ifndef G_OS_WIN32
- if (gedit_utils_uri_has_file_scheme (uri))
- saver_type = GEDIT_TYPE_LOCAL_DOCUMENT_SAVER;
- else
-#endif
- saver_type = GEDIT_TYPE_GIO_DOCUMENT_SAVER;
+ saver_type = GEDIT_TYPE_GIO_DOCUMENT_SAVER;
if (encoding == NULL)
encoding = gedit_encoding_get_utf8 ();
@@ -247,6 +262,7 @@ gedit_document_saver_new (GeditDocument *doc,
"document", doc,
"uri", uri,
"encoding", encoding,
+ "newline_type", newline_type,
"flags", flags,
NULL));
diff --git a/gedit/gedit-document-saver.h b/gedit/gedit-document-saver.h
index 1e4d979..52c1cf2 100644
--- a/gedit/gedit-document-saver.h
+++ b/gedit/gedit-document-saver.h
@@ -62,6 +62,7 @@ struct _GeditDocumentSaver
gchar *uri;
const GeditEncoding *encoding;
+ GeditDocumentNewlineType newline_type;
GeditDocumentSaveFlags flags;
@@ -97,10 +98,11 @@ struct _GeditDocumentSaverClass
GType gedit_document_saver_get_type (void) G_GNUC_CONST;
/* If enconding == NULL, the encoding will be autodetected */
-GeditDocumentSaver *gedit_document_saver_new (GeditDocument *doc,
- const gchar *uri,
- const GeditEncoding *encoding,
- GeditDocumentSaveFlags flags);
+GeditDocumentSaver *gedit_document_saver_new (GeditDocument *doc,
+ const gchar *uri,
+ const GeditEncoding *encoding,
+ GeditDocumentNewlineType newline_type,
+ GeditDocumentSaveFlags flags);
gchar *gedit_document_saver_get_document_contents (
GeditDocumentSaver *saver,
diff --git a/gedit/gedit-document.c b/gedit/gedit-document.c
index d7d09be..b35e952 100644
--- a/gedit/gedit-document.c
+++ b/gedit/gedit-document.c
@@ -118,6 +118,8 @@ struct _GeditDocumentPrivate
gchar *search_text;
gint num_of_lines_search_text;
+ GeditDocumentNewlineType newline_type;
+
/* Temp data while loading */
GeditDocumentLoader *loader;
gboolean create; /* Create file if uri points
@@ -153,7 +155,8 @@ enum {
PROP_READ_ONLY,
PROP_ENCODING,
PROP_CAN_SEARCH_AGAIN,
- PROP_ENABLE_SEARCH_HIGHLIGHTING
+ PROP_ENABLE_SEARCH_HIGHLIGHTING,
+ PROP_NEWLINE_TYPE
};
enum {
@@ -342,6 +345,9 @@ gedit_document_get_property (GObject *object,
case PROP_ENABLE_SEARCH_HIGHLIGHTING:
g_value_set_boolean (value, gedit_document_get_enable_search_highlighting (doc));
break;
+ case PROP_NEWLINE_TYPE:
+ g_value_set_enum (value, doc->priv->newline_type);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -361,6 +367,11 @@ gedit_document_set_property (GObject *object,
case PROP_ENABLE_SEARCH_HIGHLIGHTING:
gedit_document_set_enable_search_highlighting (doc,
g_value_get_boolean (value));
+ break;
+ case PROP_NEWLINE_TYPE:
+ gedit_document_set_newline_type (doc,
+ g_value_get_enum (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -485,6 +496,22 @@ gedit_document_class_init (GeditDocumentClass *klass)
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
+ /**
+ * GeditDocument:newline-type:
+ *
+ * The :newline-type property determines what is considered
+ * as a line ending when saving the document
+ */
+ g_object_class_install_property (object_class, PROP_NEWLINE_TYPE,
+ g_param_spec_enum ("newline-type",
+ "Newline type",
+ "The accepted types of line ending",
+ GEDIT_TYPE_DOCUMENT_NEWLINE_TYPE,
+ GEDIT_DOCUMENT_NEWLINE_TYPE_LF,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB));
+
/* This signal is used to update the cursor position is the statusbar,
* it's emitted either when the insert mark is moved explicitely or
* when the buffer changes (insert/delete).
@@ -803,6 +830,8 @@ gedit_document_init (GeditDocument *doc)
doc->priv->encoding = gedit_encoding_get_utf8 ();
+ doc->priv->newline_type = GEDIT_DOCUMENT_NEWLINE_TYPE_DEFAULT;
+
gtk_source_buffer_set_max_undo_levels (GTK_SOURCE_BUFFER (doc),
gedit_prefs_manager_get_undo_actions_limit ());
@@ -1158,9 +1187,13 @@ document_loader_loaded (GeditDocumentLoader *loader,
set_encoding (doc,
gedit_document_loader_get_encoding (loader),
(doc->priv->requested_encoding != NULL));
-
+
+
set_content_type (doc, content_type);
+ gedit_document_set_newline_type (doc,
+ gedit_document_loader_get_newline_type (loader));
+
/* move the cursor at the requested line if any */
if (doc->priv->requested_line_pos > 0)
{
@@ -1412,7 +1445,9 @@ gedit_document_save_real (GeditDocument *doc,
g_return_if_fail (doc->priv->saver == NULL);
/* create a saver, it will be destroyed once saving is complete */
- doc->priv->saver = gedit_document_saver_new (doc, uri, encoding, flags);
+ doc->priv->saver = gedit_document_saver_new (doc, uri, encoding,
+ doc->priv->newline_type,
+ flags);
g_signal_connect (doc->priv->saver,
"saving",
@@ -2406,6 +2441,28 @@ gedit_document_get_enable_search_highlighting (GeditDocument *doc)
}
void
+gedit_document_set_newline_type (GeditDocument *doc,
+ GeditDocumentNewlineType newline_type)
+{
+ g_return_if_fail (GEDIT_IS_DOCUMENT (doc));
+
+ if (doc->priv->newline_type != newline_type)
+ {
+ doc->priv->newline_type = newline_type;
+
+ g_object_notify (G_OBJECT (doc), "newline-type");
+ }
+}
+
+GeditDocumentNewlineType
+gedit_document_get_newline_type (GeditDocument *doc)
+{
+ g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), 0);
+
+ return doc->priv->newline_type;
+}
+
+void
_gedit_document_set_mount_operation_factory (GeditDocument *doc,
GeditMountOperationFactory callback,
gpointer userdata)
diff --git a/gedit/gedit-document.h b/gedit/gedit-document.h
index 0b8fde9..a5d2730 100644
--- a/gedit/gedit-document.h
+++ b/gedit/gedit-document.h
@@ -63,6 +63,19 @@ G_BEGIN_DECLS
typedef enum
{
+ GEDIT_DOCUMENT_NEWLINE_TYPE_LF,
+ GEDIT_DOCUMENT_NEWLINE_TYPE_CR,
+ GEDIT_DOCUMENT_NEWLINE_TYPE_CR_LF
+} GeditDocumentNewlineType;
+
+#ifdef G_OS_WIN32
+#define GEDIT_DOCUMENT_NEWLINE_TYPE_DEFAULT GEDIT_DOCUMENT_NEWLINE_TYPE_CR_LF
+#else
+#define GEDIT_DOCUMENT_NEWLINE_TYPE_DEFAULT GEDIT_DOCUMENT_NEWLINE_TYPE_LF
+#endif
+
+typedef enum
+{
GEDIT_SEARCH_DONT_SET_FLAGS = 1 << 0,
GEDIT_SEARCH_ENTIRE_WORD = 1 << 1,
GEDIT_SEARCH_CASE_SENSITIVE = 1 << 2
@@ -257,6 +270,12 @@ void gedit_document_set_enable_search_highlighting
gboolean gedit_document_get_enable_search_highlighting
(GeditDocument *doc);
+void gedit_document_set_newline_type (GeditDocument *doc,
+ GeditDocumentNewlineType newline_type);
+
+GeditDocumentNewlineType
+ gedit_document_get_newline_type (GeditDocument *doc);
+
gchar *gedit_document_get_metadata (GeditDocument *doc,
const gchar *key);
diff --git a/gedit/gedit-gio-document-loader.c b/gedit/gedit-gio-document-loader.c
index 1a44dbe..fa95673 100644
--- a/gedit/gedit-gio-document-loader.c
+++ b/gedit/gedit-gio-document-loader.c
@@ -270,26 +270,91 @@ append_text_to_document (GeditDocumentLoader *loader,
gtk_text_buffer_insert (GTK_TEXT_BUFFER (doc), &end, text, len);
}
+static GeditDocumentNewlineType
+get_newline_type (GtkTextIter *end)
+{
+ GeditDocumentNewlineType res;
+ GtkTextIter copy;
+ gunichar c;
+
+ copy = *end;
+ c = gtk_text_iter_get_char (©);
+
+ GtkTextIter tt = copy;
+ gtk_text_iter_forward_chars (&tt, 2);
+
+ if (g_unichar_break_type (c) == G_UNICODE_BREAK_CARRIAGE_RETURN)
+ {
+ if (gtk_text_iter_forward_char (©) &&
+ g_unichar_break_type (gtk_text_iter_get_char (©)) == G_UNICODE_BREAK_LINE_FEED)
+ {
+ res = GEDIT_DOCUMENT_NEWLINE_TYPE_CR_LF;
+ }
+ else
+ {
+ res = GEDIT_DOCUMENT_NEWLINE_TYPE_CR;
+ }
+ }
+ else
+ {
+ res = GEDIT_DOCUMENT_NEWLINE_TYPE_LF;
+ }
+
+ return res;
+}
+
static void
-end_append_text_to_document (GeditDocumentLoader *loader)
+detect_newline_type (GeditDocumentLoader *loader)
{
- GtkTextIter start, end;
+ GtkTextIter iter;
+
+ gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (loader->document), &iter);
+
+ if (!gtk_text_iter_backward_line (&iter))
+ {
+ gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (loader->document), &iter);
+ }
+
+ if (gtk_text_iter_ends_line (&iter) || gtk_text_iter_forward_to_line_end (&iter))
+ {
+ loader->auto_detected_newline_type = get_newline_type (&iter);
+ }
+}
+
+static void
+remove_ending_newline (GeditDocumentLoader *loader)
+{
+ GtkTextIter end;
+ GtkTextIter start;
- /* If the last char is a newline, remove it from the buffer (otherwise
- GtkTextView shows it as an empty line). See bug #324942. */
gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (loader->document), &end);
start = end;
- if (gtk_text_iter_backward_char (&start))
- {
- gunichar c;
+ gtk_text_iter_set_line_offset (&start, 0);
- c = gtk_text_iter_get_char (&start);
+ if (gtk_text_iter_ends_line (&start) &&
+ gtk_text_iter_backward_line (&start))
+ {
+ if (!gtk_text_iter_ends_line (&start))
+ {
+ gtk_text_iter_forward_to_line_end (&start);
+ }
- if (g_unichar_break_type (c) == G_UNICODE_BREAK_LINE_FEED)
- gtk_text_buffer_delete (GTK_TEXT_BUFFER (loader->document),
- &start, &end);
+ /* Delete the empty line which is from 'start' to 'end' */
+ gtk_text_buffer_delete (GTK_TEXT_BUFFER (loader->document),
+ &start,
+ &end);
}
+}
+
+static void
+end_append_text_to_document (GeditDocumentLoader *loader)
+{
+ detect_newline_type (loader);
+
+ /* If the last char is a newline, remove it from the buffer (otherwise
+ GtkTextView shows it as an empty line). See bug #324942. */
+ remove_ending_newline (loader);
gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (loader->document), FALSE);
diff --git a/gedit/gedit-gio-document-saver.c b/gedit/gedit-gio-document-saver.c
index fbd1256..5e138f6 100644
--- a/gedit/gedit-gio-document-saver.c
+++ b/gedit/gedit-gio-document-saver.c
@@ -37,19 +37,22 @@
#include <gio/gio.h>
#include <string.h>
-#include "gedit-convert.h"
#include "gedit-gio-document-saver.h"
+#include "gedit-document-input-stream.h"
#include "gedit-debug.h"
+#define WRITE_CHUNK_SIZE 8192
+
typedef struct
{
GeditGioDocumentSaver *saver;
- gchar *buffer;
+ gchar buffer[WRITE_CHUNK_SIZE];
GCancellable *cancellable;
gboolean tried_mount;
+ gsize written;
+ gsize read;
} AsyncData;
-#define WRITE_CHUNK_SIZE 8192
#define REMOTE_QUERY_ATTRIBUTES G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," \
G_FILE_ATTRIBUTE_TIME_MODIFIED
@@ -74,7 +77,8 @@ struct _GeditGioDocumentSaverPrivate
GFile *gfile;
GCancellable *cancellable;
- GFileOutputStream *stream;
+ GOutputStream *stream;
+ GInputStream *input;
GError *error;
};
@@ -82,26 +86,36 @@ struct _GeditGioDocumentSaverPrivate
G_DEFINE_TYPE(GeditGioDocumentSaver, gedit_gio_document_saver, GEDIT_TYPE_DOCUMENT_SAVER)
static void
-gedit_gio_document_saver_finalize (GObject *object)
+gedit_gio_document_saver_dispose (GObject *object)
{
GeditGioDocumentSaverPrivate *priv = GEDIT_GIO_DOCUMENT_SAVER (object)->priv;
- if (priv->cancellable)
+ if (priv->cancellable != NULL)
{
g_cancellable_cancel (priv->cancellable);
g_object_unref (priv->cancellable);
+ priv->cancellable = NULL;
}
- if (priv->gfile)
+ if (priv->gfile != NULL)
+ {
g_object_unref (priv->gfile);
+ priv->gfile = NULL;
+ }
- if (priv->error)
+ if (priv->error != NULL)
+ {
g_error_free (priv->error);
-
- if (priv->stream)
+ priv->error = NULL;
+ }
+
+ if (priv->stream != NULL)
+ {
g_object_unref (priv->stream);
+ priv->stream = NULL;
+ }
- G_OBJECT_CLASS (gedit_gio_document_saver_parent_class)->finalize (object);
+ G_OBJECT_CLASS (gedit_gio_document_saver_parent_class)->dispose (object);
}
static AsyncData *
@@ -111,9 +125,10 @@ async_data_new (GeditGioDocumentSaver *gvsaver)
async = g_slice_new (AsyncData);
async->saver = gvsaver;
- async->buffer = NULL;
async->cancellable = g_object_ref (gvsaver->priv->cancellable);
async->tried_mount = FALSE;
+ async->written = 0;
+ async->read = 0;
return async;
}
@@ -122,7 +137,6 @@ static void
async_data_free (AsyncData *async)
{
g_object_unref (async->cancellable);
- g_free (async->buffer);
g_slice_free (AsyncData, async);
}
@@ -132,7 +146,7 @@ gedit_gio_document_saver_class_init (GeditGioDocumentSaverClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GeditDocumentSaverClass *saver_class = GEDIT_DOCUMENT_SAVER_CLASS (klass);
- object_class->finalize = gedit_gio_document_saver_finalize;
+ object_class->finalize = gedit_gio_document_saver_dispose;
saver_class->save = gedit_gio_document_saver_save;
saver_class->get_file_size = gedit_gio_document_saver_get_file_size;
@@ -171,9 +185,6 @@ async_failed (AsyncData *async,
remote_save_completed_or_failed (async->saver, async);
}
-/* prototype, because they call each other... isn't C lovely */
-static void write_file_chunk (AsyncData *async);
-
static void
remote_reget_info_cb (GFile *source,
GAsyncResult *res,
@@ -321,6 +332,7 @@ remote_get_info_cb (GFileOutputStream *stream,
next_callback = (GAsyncReadyCallback) close_async_ready_cb;
}
+ /* Close the main stream so the file stream is also closed */
g_output_stream_close_async (G_OUTPUT_STREAM (saver->priv->stream),
G_PRIORITY_HIGH,
async->cancellable,
@@ -328,17 +340,28 @@ remote_get_info_cb (GFileOutputStream *stream,
async);
}
+/* prototype, because they call each other... isn't C lovely */
+static void read_file_chunk (AsyncData *async);
+static void write_file_chunk (AsyncData *async);
+
static void
write_complete (AsyncData *async)
{
+ GOutputStream *file_stream;
+
/* document is succesfully saved. we know requery for the mime type and
* the mtime. I'm not sure this is actually necessary, can't we just use
* g_content_type_guess (since we have the file name and the data)
*/
gedit_debug_message (DEBUG_SAVER, "Write complete, query info on stream");
+
+ if (G_IS_FILE_OUTPUT_STREAM (async->saver->priv->stream))
+ file_stream = async->saver->priv->stream;
+ else
+ file_stream = g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (async->saver->priv->stream));
/* query info on the stream */
- g_file_output_stream_query_info_async (async->saver->priv->stream,
+ g_file_output_stream_query_info_async (G_FILE_OUTPUT_STREAM (file_stream),
REMOTE_QUERY_ATTRIBUTES,
G_PRIORITY_HIGH,
async->cancellable,
@@ -348,23 +371,20 @@ write_complete (AsyncData *async)
static void
async_write_cb (GOutputStream *stream,
- GAsyncResult *res,
- AsyncData *async)
+ GAsyncResult *res,
+ AsyncData *async)
{
- GError *error = NULL;
GeditGioDocumentSaver *gvsaver;
gssize bytes_written;
-
- gedit_debug (DEBUG_SAVER);
-
- /* manually check cancelled state */
+ GError *error = NULL;
+
+ /* Check cancelled state manually */
if (g_cancellable_is_cancelled (async->cancellable))
{
async_data_free (async);
return;
}
- gvsaver = async->saver;
bytes_written = g_output_stream_write_finish (stream, res, &error);
gedit_debug_message (DEBUG_SAVER, "Written: %" G_GSSIZE_FORMAT, bytes_written);
@@ -375,17 +395,15 @@ async_write_cb (GOutputStream *stream,
async_failed (async, error);
return;
}
-
- gvsaver->priv->bytes_written += bytes_written;
-
- /* if nothing is written we're done */
- if (gvsaver->priv->bytes_written == gvsaver->priv->size)
+
+ gvsaver = async->saver;
+ async->written += bytes_written;
+
+ /* write again */
+ if (async->written != async->read)
{
- write_complete (async);
- return;
+ write_file_chunk (async);
}
-
- /* otherwise emit progress and write some more */
/* note that this signal blocks the write... check if it isn't
* a performance problem
@@ -394,7 +412,7 @@ async_write_cb (GOutputStream *stream,
FALSE,
NULL);
- write_file_chunk (async);
+ read_file_chunk (async);
}
static void
@@ -404,14 +422,9 @@ write_file_chunk (AsyncData *async)
gvsaver = async->saver;
- gedit_debug_message (DEBUG_SAVER,
- "Writing next chunk: %" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
- gvsaver->priv->bytes_written, gvsaver->priv->size);
-
g_output_stream_write_async (G_OUTPUT_STREAM (gvsaver->priv->stream),
- async->buffer + gvsaver->priv->bytes_written,
- MIN (WRITE_CHUNK_SIZE, gvsaver->priv->size -
- gvsaver->priv->bytes_written),
+ async->buffer + async->written,
+ async->read - async->written,
G_PRIORITY_HIGH,
async->cancellable,
(GAsyncReadyCallback) async_write_cb,
@@ -419,11 +432,70 @@ write_file_chunk (AsyncData *async)
}
static void
+async_read_cb (GInputStream *stream,
+ GAsyncResult *res,
+ AsyncData *async)
+{
+ GeditGioDocumentSaver *gvsaver;
+ GeditDocumentInputStream *dstream;
+ GError *error = NULL;
+
+ if (g_cancellable_is_cancelled (async->cancellable))
+ {
+ async_data_free (async);
+ return;
+ }
+
+ gvsaver = async->saver;
+
+ async->read = g_input_stream_read_finish (stream, res, &error);
+
+ if (error != NULL)
+ {
+ async_failed (async, error);
+ return;
+ }
+
+ /* Check if we finished reading and writing */
+ if (async->read == 0)
+ {
+ write_complete (async);
+ return;
+ }
+
+ /* Get how many chars have been read */
+ dstream = GEDIT_DOCUMENT_INPUT_STREAM (stream);
+ gvsaver->priv->bytes_written += gedit_document_input_stream_tell (dstream);
+
+ write_file_chunk (async);
+}
+
+static void
+read_file_chunk (AsyncData *async)
+{
+ GeditGioDocumentSaver *gvsaver;
+
+ gvsaver = async->saver;
+ async->written = 0;
+
+ g_input_stream_read_async (gvsaver->priv->input,
+ async->buffer,
+ WRITE_CHUNK_SIZE,
+ G_PRIORITY_HIGH,
+ async->cancellable,
+ (GAsyncReadyCallback) async_read_cb,
+ async);
+}
+
+static void
async_replace_ready_callback (GFile *source,
GAsyncResult *res,
AsyncData *async)
{
GeditGioDocumentSaver *gvsaver;
+ GeditDocumentSaver *saver;
+ GCharsetConverter *converter;
+ GFileOutputStream *file_stream;
GError *error = NULL;
/* Check cancelled state manually */
@@ -434,71 +506,49 @@ async_replace_ready_callback (GFile *source,
}
gvsaver = async->saver;
- gvsaver->priv->stream = g_file_replace_finish (source, res, &error);
+ saver = GEDIT_DOCUMENT_SAVER (gvsaver);
+ file_stream = g_file_replace_finish (source, res, &error);
/* handle any error that might occur */
- if (!gvsaver->priv->stream)
+ if (!file_stream)
{
gedit_debug_message (DEBUG_SAVER, "Opening file failed: %s", error->message);
async_failed (async, error);
return;
}
- /* now that we have the stream, start writing async to it */
- write_file_chunk (async);
-}
-
-/* returns a pointer to the reallocated buffer */
-static gchar *
-append_new_line (GeditGioDocumentSaver *gvsaver,
- gchar *buffer,
- gsize *len,
- GError **error)
-{
- GeditDocumentSaver *saver = GEDIT_DOCUMENT_SAVER (gvsaver);
- gsize n_len;
- gchar *n_buffer;
- gchar *res;
-
- res = buffer;
+ /* FIXME: manage converter error? */
+ gedit_debug_message (DEBUG_SAVER, "Encoding charset: %s",
+ gedit_encoding_get_charset (saver->encoding));
- n_buffer = gedit_document_saver_get_end_newline (saver, &n_len);
- if (n_buffer != NULL)
+ if (saver->encoding != gedit_encoding_get_utf8 ())
{
- gchar *new_buffer;
-
- new_buffer = g_try_realloc (buffer, *len + n_len + 1);
-
- if (new_buffer == NULL)
- {
- /* we do not error out, just use the buffer
- without the ending newline */
- g_free (n_buffer);
- g_warning ("Cannot add '\\n' at the end of the file.");
-
- return res;
- }
-
- /* Copy newline */
- memcpy (new_buffer + *len, n_buffer, n_len);
- g_free (n_buffer);
- *len += n_len;
-
- new_buffer[*len] = '\0';
-
- res = new_buffer;
+ converter = g_charset_converter_new (gedit_encoding_get_charset (saver->encoding),
+ "UTF-8",
+ NULL);
+ gvsaver->priv->stream = g_converter_output_stream_new (G_OUTPUT_STREAM (file_stream),
+ G_CONVERTER (converter));
+
+ g_object_unref (file_stream);
+ g_object_unref (converter);
}
+ else
+ {
+ gvsaver->priv->stream = G_OUTPUT_STREAM (file_stream);
+ }
+
+ gvsaver->priv->input = gedit_document_input_stream_new (GTK_TEXT_BUFFER (saver->document),
+ saver->newline_type);
+
+ gvsaver->priv->size = gedit_document_input_stream_get_total_size (GEDIT_DOCUMENT_INPUT_STREAM (gvsaver->priv->input));
- return res;
+ read_file_chunk (async);
}
static void
begin_write (AsyncData *async)
{
GeditGioDocumentSaver *gvsaver;
- gchar *buffer;
- gsize len;
- GError *error = NULL;
gedit_debug_message (DEBUG_SAVER, "Start replacing file contents");
@@ -506,25 +556,11 @@ begin_write (AsyncData *async)
* backup as of yet
*/
gvsaver = async->saver;
- buffer = gedit_document_saver_get_document_contents (GEDIT_DOCUMENT_SAVER (gvsaver), &len, &error);
- if (buffer != NULL && len > 0)
- {
- /* Append new line to buffer */
- buffer = append_new_line (gvsaver, buffer, &len, &error);
- }
-
- if (!buffer)
- {
- async_failed (async, error);
- return;
- }
-
- async->buffer = buffer;
- gvsaver->priv->size = len;
gedit_debug_message (DEBUG_SAVER, "File contents size: %" G_GINT64_FORMAT, gvsaver->priv->size);
gedit_debug_message (DEBUG_SAVER, "Calling replace_async");
+ /* FIXME: when do we want to make a backup? */
g_file_replace_async (gvsaver->priv->gfile,
NULL,
FALSE,
@@ -580,9 +616,9 @@ recover_not_mounted (AsyncData *async)
mount_operation,
async->cancellable,
(GAsyncReadyCallback) mount_ready_callback,
- async);
+ async);
- g_object_unref (mount_operation);
+ g_object_unref (mount_operation);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]