Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retain whether a file ended with a trailing newline optionally displaying it #687

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions data/org.mate.pluma.gschema.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@
<summary>Autosave Interval</summary>
<description>Number of minutes after which pluma will automatically save modified files. This will only take effect if the "Autosave" option is turned on.</description>
</key>
<key name="hide-trailing-newline" type="b">
<default>true</default>
<summary>Hide Tailing Newline</summary>
<description>Whether pluma should hide the final newline in opened files if one was present when loading the file. Enabling this will also cause newly created files to be saved with a trailing newline by default.</description>
</key>
<key name="show-save-confirmation" type="b">
<default>true</default>
<summary>Show save confirmation</summary>
Expand Down
10 changes: 10 additions & 0 deletions pluma/dialogs/pluma-preferences-dialog.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ struct _PlumaPreferencesDialogPrivate
GtkWidget *auto_save_checkbutton;
GtkWidget *auto_save_spinbutton;

/* File Format */
GtkWidget *hide_trailing_newline_checkbutton;

/* Line numbers */
GtkWidget *display_line_numbers_checkbutton;

Expand Down Expand Up @@ -353,6 +356,11 @@ setup_editor_page (PlumaPreferencesDialog *dlg)
dlg->priv->auto_save_spinbutton,
"value",
G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET | G_SETTINGS_BIND_NO_SENSITIVITY);
g_settings_bind (dlg->priv->editor_settings,
PLUMA_SETTINGS_HIDE_TRAILING_NEWLINE,
dlg->priv->hide_trailing_newline_checkbutton,
"active",
G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
g_settings_bind (dlg->priv->editor_settings,
PLUMA_SETTINGS_DRAWER_NEWLINE,
dlg->priv->draw_newlines_checkbutton,
Expand Down Expand Up @@ -1276,6 +1284,8 @@ pluma_preferences_dialog_init (PlumaPreferencesDialog *dlg)
"auto_save_checkbutton", &dlg->priv->auto_save_checkbutton,
"auto_save_spinbutton", &dlg->priv->auto_save_spinbutton,

"hide_trailing_newline_checkbutton", &dlg->priv->hide_trailing_newline_checkbutton,

"default_font_checkbutton", &dlg->priv->default_font_checkbutton,
"font_button", &dlg->priv->font_button,
"font_hbox", &dlg->priv->font_hbox,
Expand Down
500 changes: 304 additions & 196 deletions pluma/dialogs/pluma-preferences-dialog.ui

Large diffs are not rendered by default.

61 changes: 42 additions & 19 deletions pluma/pluma-document-input-stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct _PlumaDocumentInputStreamPrivate
gint bytes_partial;

PlumaDocumentNewlineType newline_type;
gboolean add_trailing_newline;

guint newline_added : 1;
guint is_initialized : 1;
Expand All @@ -54,7 +55,8 @@ enum
{
PROP_0,
PROP_BUFFER,
PROP_NEWLINE_TYPE
PROP_NEWLINE_TYPE,
PROP_ADD_TRAILING_NEWLINE,
};

static gssize pluma_document_input_stream_read (GInputStream *stream,
Expand Down Expand Up @@ -84,6 +86,10 @@ pluma_document_input_stream_set_property (GObject *object,
stream->priv->newline_type = g_value_get_enum (value);
break;

case PROP_ADD_TRAILING_NEWLINE:
stream->priv->add_trailing_newline = g_value_get_boolean (value);
break;

default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
Expand All @@ -108,6 +114,10 @@ pluma_document_input_stream_get_property (GObject *object,
g_value_set_enum (value, stream->priv->newline_type);
break;

case PROP_ADD_TRAILING_NEWLINE:
g_value_set_boolean (value, stream->priv->add_trailing_newline);
break;

default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
Expand Down Expand Up @@ -152,6 +162,16 @@ pluma_document_input_stream_class_init (PlumaDocumentInputStreamClass *klass)
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB |
G_PARAM_CONSTRUCT_ONLY));

g_object_class_install_property (gobject_class,
PROP_ADD_TRAILING_NEWLINE,
g_param_spec_boolean ("add-trailing-newline",
"Add Trailing Newline",
"Automatically add a trailing newline to the file contents?",
TRUE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT));
}

static void
Expand Down Expand Up @@ -428,30 +448,33 @@ pluma_document_input_stream_read (GInputStream *stream,
space_left -= n;
} while (space_left > 0 && n != 0 && dstream->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 (dstream->priv->buffer,
&iter,
dstream->priv->pos);

if (gtk_text_iter_is_end (&iter) &&
!gtk_text_iter_is_start (&iter))
if (dstream->priv->add_trailing_newline)
{
gssize newline_size;

newline_size = get_new_line_size (dstream);
/* 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 (dstream->priv->buffer,
&iter,
dstream->priv->pos);

if (space_left >= newline_size &&
!dstream->priv->newline_added)
if (gtk_text_iter_is_end (&iter) &&
!gtk_text_iter_is_start (&iter))
{
const gchar *newline;
gssize newline_size;

newline_size = get_new_line_size (dstream);

newline = get_new_line (dstream);
if (space_left >= newline_size &&
!dstream->priv->newline_added)
{
const gchar *newline;

newline = get_new_line (dstream);

memcpy ((void *) ((gsize) buffer + read), newline, newline_size);
memcpy ((void *) ((gsize) buffer + read), newline, newline_size);

read += newline_size;
dstream->priv->newline_added = TRUE;
read += newline_size;
dstream->priv->newline_added = TRUE;
}
}
}

Expand Down
54 changes: 44 additions & 10 deletions pluma/pluma-document-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ enum
PROP_DOCUMENT,
PROP_URI,
PROP_ENCODING,
PROP_NEWLINE_TYPE
PROP_NEWLINE_TYPE,
PROP_TRIM_TRAILING_NEWLINE,
PROP_TRIMMED_TRAILING_NEWLINE,
};

#define READ_CHUNK_SIZE 8192
Expand Down Expand Up @@ -105,6 +107,7 @@ struct _PlumaDocumentLoaderPrivate
PlumaDocumentNewlineType auto_detected_newline_type;
GFile *gfile;
goffset bytes_read;
gboolean trim_trailing_newline;

/* Handle for remote files */
GCancellable *cancellable;
Expand Down Expand Up @@ -144,6 +147,9 @@ pluma_document_loader_set_property (GObject *object,
case PROP_NEWLINE_TYPE:
loader->priv->auto_detected_newline_type = g_value_get_enum (value);
break;
case PROP_TRIM_TRAILING_NEWLINE:
loader->priv->trim_trailing_newline = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
Expand Down Expand Up @@ -172,6 +178,23 @@ pluma_document_loader_get_property (GObject *object,
case PROP_NEWLINE_TYPE:
g_value_set_enum (value, loader->priv->auto_detected_newline_type);
break;
case PROP_TRIM_TRAILING_NEWLINE:
g_value_set_boolean (value, loader->priv->trim_trailing_newline);
break;
case PROP_TRIMMED_TRAILING_NEWLINE:
if (loader->priv->output != NULL)
{
gboolean trimmed_trailing_newline;
g_object_get (loader->priv->output,
"trimmed-trailing-newline", &trimmed_trailing_newline,
NULL);
g_value_set_boolean (value, trimmed_trailing_newline);
}
else
{
g_value_set_boolean (value, FALSE);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
Expand Down Expand Up @@ -277,15 +300,23 @@ pluma_document_loader_class_init (PlumaDocumentLoaderClass *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",
PLUMA_TYPE_DOCUMENT_NEWLINE_TYPE,
PLUMA_DOCUMENT_NEWLINE_TYPE_LF,
G_PARAM_READWRITE |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB));
PROP_TRIM_TRAILING_NEWLINE,
g_param_spec_boolean ("trim-trailing-newline",
"Trim Trailing Newline",
"Remove the final received newline from the document buffer?",
TRUE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT));

g_object_class_install_property (object_class,
PROP_TRIMMED_TRAILING_NEWLINE,
g_param_spec_boolean ("trimmed-trailing-newline",
"Trailing Newline Trimmed",
"Was the final received newline removed from the document buffer?",
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));

signals[LOADING] =
g_signal_new ("loading",
Expand Down Expand Up @@ -650,6 +681,9 @@ finish_query_info (AsyncData *async)

/* Output stream */
loader->priv->output = pluma_document_output_stream_new (loader->priv->document);
g_object_set (G_OBJECT (loader->priv->output),
"trim-trailing-newline", loader->priv->trim_trailing_newline,
NULL);

/* start reading */
read_file_chunk (async);
Expand Down
47 changes: 45 additions & 2 deletions pluma/pluma-document-output-stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,19 @@ struct _PlumaDocumentOutputStreamPrivate
gchar *buffer;
gsize buflen;

gboolean trim_trailing_newline;
gboolean trimmed_trailing_newline;

guint is_initialized : 1;
guint is_closed : 1;
};

enum
{
PROP_0,
PROP_DOCUMENT
PROP_DOCUMENT,
PROP_TRIM_TRAILING_NEWLINE,
PROP_TRIMMED_TRAILING_NEWLINE,
};

G_DEFINE_TYPE_WITH_PRIVATE (PlumaDocumentOutputStream, pluma_document_output_stream, G_TYPE_OUTPUT_STREAM)
Expand Down Expand Up @@ -85,6 +90,10 @@ pluma_document_output_stream_set_property (GObject *object,
stream->priv->doc = PLUMA_DOCUMENT (g_value_get_object (value));
break;

case PROP_TRIM_TRAILING_NEWLINE:
stream->priv->trim_trailing_newline = g_value_get_boolean (value);
break;

default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
Expand All @@ -105,6 +114,14 @@ pluma_document_output_stream_get_property (GObject *object,
g_value_set_object (value, stream->priv->doc);
break;

case PROP_TRIM_TRAILING_NEWLINE:
g_value_set_boolean (value, stream->priv->trim_trailing_newline);
break;

case PROP_TRIMMED_TRAILING_NEWLINE:
g_value_set_boolean (value, stream->priv->trimmed_trailing_newline);
break;

default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
Expand Down Expand Up @@ -166,6 +183,25 @@ pluma_document_output_stream_class_init (PlumaDocumentOutputStreamClass *klass)
PLUMA_TYPE_DOCUMENT,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));

g_object_class_install_property (object_class,
PROP_TRIM_TRAILING_NEWLINE,
g_param_spec_boolean ("trim-trailing-newline",
"Trim Trailing Newline",
"Remove the final received newline from the document buffer?",
TRUE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT));

g_object_class_install_property (object_class,
PROP_TRIMMED_TRAILING_NEWLINE,
g_param_spec_boolean ("trimmed-trailing-newline",
"Trailing Newline Trimmed",
"Was the final received newline removed from the document buffer?",
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
}

static void
Expand All @@ -176,6 +212,8 @@ pluma_document_output_stream_init (PlumaDocumentOutputStream *stream)
stream->priv->buffer = NULL;
stream->priv->buflen = 0;

stream->priv->trimmed_trailing_newline = FALSE;

stream->priv->is_initialized = FALSE;
stream->priv->is_closed = FALSE;
}
Expand Down Expand Up @@ -264,13 +302,18 @@ remove_ending_newline (PlumaDocumentOutputStream *stream)
gtk_text_buffer_delete (GTK_TEXT_BUFFER (stream->priv->doc),
&start,
&end);

stream->priv->trimmed_trailing_newline = TRUE;
}
}

static void
end_append_text_to_document (PlumaDocumentOutputStream *stream)
{
remove_ending_newline (stream);
if (stream->priv->trim_trailing_newline)
{
remove_ending_newline (stream);
}

gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (stream->priv->doc),
FALSE);
Expand Down
Loading