[gtksourceview/wip/loader-saver] Add GtkSourceBufferInputStream private class
- From: Sébastien Wilmet <swilmet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/loader-saver] Add GtkSourceBufferInputStream private class
- Date: Fri, 6 Dec 2013 23:22:55 +0000 (UTC)
commit 3ef881aae0e9911e80d22c72ed331b944833f410
Author: Sébastien Wilmet <swilmet gnome org>
Date: Fri Dec 6 22:45:26 2013 +0100
Add GtkSourceBufferInputStream private class
Taken from the gedit source code, GeditDocumentInputStream.
gtksourceview/Makefile.am | 2 +
gtksourceview/gtksourcebuffer.h | 7 +
gtksourceview/gtksourcebufferinputstream.c | 486 ++++++++++++++++++++++++++++
gtksourceview/gtksourcebufferinputstream.h | 71 ++++
po/POTFILES.in | 1 +
5 files changed, 567 insertions(+), 0 deletions(-)
---
diff --git a/gtksourceview/Makefile.am b/gtksourceview/Makefile.am
index 618ce37..a3c6c1a 100644
--- a/gtksourceview/Makefile.am
+++ b/gtksourceview/Makefile.am
@@ -52,6 +52,7 @@ libgtksourceview_headers = \
libgtksourceview_private_headers = \
gtksourcebuffer-private.h \
+ gtksourcebufferinputstream.h \
gtksourcecompletioncontainer.h \
gtksourcecompletionmodel.h \
gtksourcecompletion-private.h \
@@ -73,6 +74,7 @@ libgtksourceview_private_headers = \
gtktextregion.h
libgtksourceview_private_c_files = \
+ gtksourcebufferinputstream.c \
gtksourcecompletioncontainer.c \
gtksourcecompletionmodel.c \
gtksourcecontextengine.c \
diff --git a/gtksourceview/gtksourcebuffer.h b/gtksourceview/gtksourcebuffer.h
index f04facb..17c7a63 100644
--- a/gtksourceview/gtksourcebuffer.h
+++ b/gtksourceview/gtksourcebuffer.h
@@ -73,6 +73,13 @@ typedef enum
GTK_SOURCE_CHANGE_CASE_TITLE
} GtkSourceChangeCaseType;
+typedef enum
+{
+ GTK_SOURCE_NEWLINE_TYPE_LF,
+ GTK_SOURCE_NEWLINE_TYPE_CR,
+ GTK_SOURCE_NEWLINE_TYPE_CR_LF
+} GtkSourceNewlineType;
+
struct _GtkSourceBuffer
{
GtkTextBuffer parent_instance;
diff --git a/gtksourceview/gtksourcebufferinputstream.c b/gtksourceview/gtksourcebufferinputstream.c
new file mode 100644
index 0000000..4996293
--- /dev/null
+++ b/gtksourceview/gtksourcebufferinputstream.c
@@ -0,0 +1,486 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
+/* gtksourcebufferinputstream.c
+ * This file is part of GtkSourceView
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ * Copyright (C) 2013 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * GtkSourceView is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <string.h>
+#include "gtksourcebufferinputstream.h"
+#include "gtksourceview-typebuiltins.h"
+
+/* NOTE: never use async methods on this stream, the stream is just
+ * a wrapper around GtkTextBuffer api so that we can use GIO Stream
+ * methods, but the underlying code operates on a GtkTextBuffer, so
+ * there is no I/O involved and should be accessed only by the main
+ * thread.
+ */
+
+struct _GtkSourceBufferInputStreamPrivate
+{
+ GtkTextBuffer *buffer;
+ GtkTextMark *pos;
+ gint bytes_partial;
+
+ GtkSourceNewlineType newline_type;
+
+ guint newline_added : 1;
+ guint is_initialized : 1;
+ guint ensure_trailing_newline : 1;
+};
+
+enum
+{
+ PROP_0,
+ PROP_BUFFER,
+ PROP_NEWLINE_TYPE,
+ PROP_ENSURE_TRAILING_NEWLINE
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceBufferInputStream, _gtk_source_buffer_input_stream,
G_TYPE_INPUT_STREAM);
+
+static gsize
+get_new_line_size (GtkSourceBufferInputStream *stream)
+{
+ switch (stream->priv->newline_type)
+ {
+ case GTK_SOURCE_NEWLINE_TYPE_CR:
+ case GTK_SOURCE_NEWLINE_TYPE_LF:
+ return 1;
+
+ case GTK_SOURCE_NEWLINE_TYPE_CR_LF:
+ return 2;
+
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+
+ return 1;
+}
+
+static const gchar *
+get_new_line (GtkSourceBufferInputStream *stream)
+{
+ switch (stream->priv->newline_type)
+ {
+ case GTK_SOURCE_NEWLINE_TYPE_LF:
+ return "\n";
+
+ case GTK_SOURCE_NEWLINE_TYPE_CR:
+ return "\r";
+
+ case GTK_SOURCE_NEWLINE_TYPE_CR_LF:
+ return "\r\n";
+
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+
+ return "\n";
+}
+
+static gsize
+read_line (GtkSourceBufferInputStream *stream,
+ gchar *outbuf,
+ gsize space_left)
+{
+ GtkTextIter start, next, end;
+ gchar *buf;
+ gint bytes; /* int since it's what iter_get_offset returns */
+ gsize bytes_to_write, newline_size, read;
+ const gchar *newline;
+ gboolean is_last;
+
+ gtk_text_buffer_get_iter_at_mark (stream->priv->buffer,
+ &start,
+ stream->priv->pos);
+
+ if (gtk_text_iter_is_end (&start))
+ {
+ return 0;
+ }
+
+ end = next = start;
+ newline = get_new_line (stream);
+
+ /* 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 -= 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 */
+ newline_size = get_new_line_size (stream);
+ if (!is_last)
+ {
+ bytes_to_write += newline_size;
+ }
+
+ if (bytes_to_write > space_left)
+ {
+ gchar *ptr;
+ gint char_offset;
+ gint written;
+ gsize to_write;
+
+ /* 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;
+ written = 0;
+ char_offset = 0;
+
+ while (written < to_write)
+ {
+ gint w;
+
+ ptr = g_utf8_next_char (ptr);
+ w = (ptr - buf);
+ if (w > to_write)
+ {
+ break;
+ }
+ else
+ {
+ written = w;
+ ++char_offset;
+ }
+ }
+
+ memcpy (outbuf, buf, written);
+
+ /* Note: offset is one past what we wrote */
+ gtk_text_iter_forward_chars (&start, char_offset);
+ stream->priv->bytes_partial += written;
+ read = written;
+ }
+ 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);
+ }
+
+ start = next;
+ stream->priv->bytes_partial = 0;
+ read = bytes_to_write;
+ }
+
+ gtk_text_buffer_move_mark (stream->priv->buffer,
+ stream->priv->pos,
+ &start);
+
+ g_free (buf);
+ return read;
+}
+
+static gssize
+_gtk_source_buffer_input_stream_read (GInputStream *input_stream,
+ void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GtkSourceBufferInputStream *stream;
+ GtkTextIter iter;
+ gssize space_left, read, n;
+
+ stream = GTK_SOURCE_BUFFER_INPUT_STREAM (input_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 (!stream->priv->is_initialized)
+ {
+ gtk_text_buffer_get_start_iter (stream->priv->buffer, &iter);
+ stream->priv->pos = gtk_text_buffer_create_mark (stream->priv->buffer,
+ NULL,
+ &iter,
+ FALSE);
+
+ stream->priv->is_initialized = TRUE;
+ }
+
+ space_left = count;
+ read = 0;
+
+ do
+ {
+ n = read_line (stream, (gchar *)buffer + read, space_left);
+ read += n;
+ space_left -= n;
+ } while (space_left > 0 && n != 0 && stream->priv->bytes_partial == 0);
+
+ /* Make sure that non-empty files are always terminated with \n (see bug #95676).
+ * Note that we strip the trailing \n when loading the file */
+ gtk_text_buffer_get_iter_at_mark (stream->priv->buffer,
+ &iter,
+ stream->priv->pos);
+
+ if (gtk_text_iter_is_end (&iter) &&
+ !gtk_text_iter_is_start (&iter) &&
+ stream->priv->ensure_trailing_newline)
+ {
+ gssize newline_size;
+
+ newline_size = get_new_line_size (stream);
+
+ if (space_left >= newline_size &&
+ !stream->priv->newline_added)
+ {
+ const gchar *newline;
+
+ newline = get_new_line (stream);
+
+ memcpy ((gchar *)buffer + read, newline, newline_size);
+
+ read += newline_size;
+ stream->priv->newline_added = TRUE;
+ }
+ }
+
+ return read;
+}
+
+static gboolean
+_gtk_source_buffer_input_stream_close (GInputStream *input_stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GtkSourceBufferInputStream *stream = GTK_SOURCE_BUFFER_INPUT_STREAM (input_stream);
+
+ stream->priv->newline_added = FALSE;
+
+ if (stream->priv->is_initialized)
+ {
+ gtk_text_buffer_delete_mark (stream->priv->buffer, stream->priv->pos);
+ }
+
+ return TRUE;
+}
+
+static void
+_gtk_source_buffer_input_stream_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkSourceBufferInputStream *stream = GTK_SOURCE_BUFFER_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;
+
+ case PROP_ENSURE_TRAILING_NEWLINE:
+ stream->priv->ensure_trailing_newline = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gtk_source_buffer_input_stream_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkSourceBufferInputStream *stream = GTK_SOURCE_BUFFER_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;
+
+ case PROP_ENSURE_TRAILING_NEWLINE:
+ g_value_set_boolean (value, stream->priv->ensure_trailing_newline);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gtk_source_buffer_input_stream_class_init (GtkSourceBufferInputStreamClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
+
+ gobject_class->get_property = _gtk_source_buffer_input_stream_get_property;
+ gobject_class->set_property = _gtk_source_buffer_input_stream_set_property;
+
+ stream_class->read_fn = _gtk_source_buffer_input_stream_read;
+ stream_class->close_fn = _gtk_source_buffer_input_stream_close;
+
+ g_object_class_install_property (gobject_class,
+ PROP_BUFFER,
+ g_param_spec_object ("buffer",
+ "Buffer",
+ "The buffer to read",
+ GTK_TYPE_TEXT_BUFFER,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GtkSourceBufferInputStream: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 type of line ending",
+ GTK_SOURCE_TYPE_NEWLINE_TYPE,
+ GTK_SOURCE_NEWLINE_TYPE_LF,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ /**
+ * GtkSourceBufferInputStream:ensure-trailing-newline:
+ *
+ * The :ensure-trailing-newline property specifies whether or not to
+ * ensure (enforce) the buffer ends with a trailing newline.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_ENSURE_TRAILING_NEWLINE,
+ g_param_spec_boolean ("ensure-trailing-newline",
+ "Ensure Trailing Newline",
+ "Ensure the buffer ends with a trailing
newline",
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+_gtk_source_buffer_input_stream_init (GtkSourceBufferInputStream *stream)
+{
+ stream->priv = _gtk_source_buffer_input_stream_get_instance_private (stream);
+}
+
+/**
+ * _gtk_source_buffer_input_stream_new:
+ * @buffer: a #GtkTextBuffer
+ *
+ * Reads the data from @buffer.
+ *
+ * Returns: a new #GInputStream to read @buffer
+ */
+GInputStream *
+_gtk_source_buffer_input_stream_new (GtkTextBuffer *buffer,
+ GtkSourceNewlineType type,
+ gboolean ensure_trailing_newline)
+{
+ g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+
+ return g_object_new (GTK_SOURCE_TYPE_BUFFER_INPUT_STREAM,
+ "buffer", buffer,
+ "newline-type", type,
+ "ensure-trailing-newline", ensure_trailing_newline,
+ NULL);
+}
+
+gsize
+_gtk_source_buffer_input_stream_get_total_size (GtkSourceBufferInputStream *stream)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_BUFFER_INPUT_STREAM (stream), 0);
+
+ return gtk_text_buffer_get_char_count (stream->priv->buffer);
+}
+
+gsize
+_gtk_source_buffer_input_stream_tell (GtkSourceBufferInputStream *stream)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_BUFFER_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
+ {
+ GtkTextIter iter;
+
+ gtk_text_buffer_get_iter_at_mark (stream->priv->buffer,
+ &iter,
+ stream->priv->pos);
+ return gtk_text_iter_get_offset (&iter);
+ }
+}
diff --git a/gtksourceview/gtksourcebufferinputstream.h b/gtksourceview/gtksourcebufferinputstream.h
new file mode 100644
index 0000000..d1449c3
--- /dev/null
+++ b/gtksourceview/gtksourcebufferinputstream.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
+/* gtksourcebufferinputstream.h
+ * This file is part of GtkSourceView
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ * Copyright (C) 2013 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * GtkSourceView is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GTK_SOURCE_BUFFER_INPUT_STREAM_H__
+#define __GTK_SOURCE_BUFFER_INPUT_STREAM_H__
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include "gtksourcebuffer.h"
+
+G_BEGIN_DECLS
+
+#define GTK_SOURCE_TYPE_BUFFER_INPUT_STREAM (_gtk_source_buffer_input_stream_get_type ())
+#define GTK_SOURCE_BUFFER_INPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
GTK_SOURCE_TYPE_BUFFER_INPUT_STREAM, GtkSourceBufferInputStream))
+#define GTK_SOURCE_BUFFER_INPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
GTK_SOURCE_TYPE_BUFFER_INPUT_STREAM, GtkSourceBufferInputStreamClass))
+#define GTK_SOURCE_IS_BUFFER_INPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
GTK_SOURCE_TYPE_BUFFER_INPUT_STREAM))
+#define GTK_SOURCE_IS_BUFFER_INPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
GTK_SOURCE_TYPE_BUFFER_INPUT_STREAM))
+#define GTK_SOURCE_BUFFER_INPUT_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
GTK_SOURCE_TYPE_BUFFER_INPUT_STREAM, GtkSourceBufferInputStreamClass))
+
+typedef struct _GtkSourceBufferInputStream GtkSourceBufferInputStream;
+typedef struct _GtkSourceBufferInputStreamClass GtkSourceBufferInputStreamClass;
+typedef struct _GtkSourceBufferInputStreamPrivate GtkSourceBufferInputStreamPrivate;
+
+struct _GtkSourceBufferInputStream
+{
+ GInputStream parent;
+
+ GtkSourceBufferInputStreamPrivate *priv;
+};
+
+struct _GtkSourceBufferInputStreamClass
+{
+ GInputStreamClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType _gtk_source_buffer_input_stream_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GInputStream *_gtk_source_buffer_input_stream_new (GtkTextBuffer *buffer,
+ GtkSourceNewlineType type,
+ gboolean
ensure_trailing_newline);
+
+G_GNUC_INTERNAL
+gsize _gtk_source_buffer_input_stream_get_total_size (GtkSourceBufferInputStream *stream);
+
+G_GNUC_INTERNAL
+gsize _gtk_source_buffer_input_stream_tell (GtkSourceBufferInputStream *stream);
+
+G_END_DECLS
+
+#endif /* __GTK_SOURCE_BUFFER_INPUT_STREAM_H__ */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 944e802..2ac3319 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -114,6 +114,7 @@ data/styles/oblivion.xml
data/styles/tango.xml
gtksourceview/completion-providers/words/gtksourcecompletionwords.c
gtksourceview/gtksourcebuffer.c
+gtksourceview/gtksourcebufferinputstream.c
gtksourceview/gtksourcecompletion.c
gtksourceview/gtksourcecompletioncontainer.c
gtksourceview/gtksourcecompletioncontext.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]