[gnome-builder] clang-format: simplify clang-format buffer save addin
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] clang-format: simplify clang-format buffer save addin
- Date: Mon, 8 Nov 2021 21:19:03 +0000 (UTC)
commit 050b2448123a2c69aec17199a4bf506b9d94658c
Author: Christian Hergert <chergert redhat com>
Date: Mon Nov 8 13:17:25 2021 -0800
clang-format: simplify clang-format buffer save addin
.../clang-format/gb-clang-format-buffer-addin.c | 370 ++++++---------------
1 file changed, 107 insertions(+), 263 deletions(-)
---
diff --git a/src/plugins/clang-format/gb-clang-format-buffer-addin.c
b/src/plugins/clang-format/gb-clang-format-buffer-addin.c
index b49f4b0e3..71a500f9a 100644
--- a/src/plugins/clang-format/gb-clang-format-buffer-addin.c
+++ b/src/plugins/clang-format/gb-clang-format-buffer-addin.c
@@ -32,313 +32,156 @@
struct _GbClangFormatBufferAddin
{
GObject parent_instance;
- gchar *working_directory;
- gssize cursor_position;
- IdePage *page;
- gssize header_len;
};
-typedef struct {
- IdeBuffer *buffer;
- IdePage *page;
-} Lookup;
+static GSettings *settings;
static void
-foreach_page_cb (GtkWidget *page,
- gpointer user_data)
+scroll_page_to_insert (GtkWidget *widget,
+ gpointer data)
{
- Lookup *l = user_data;
+ IdePage *page = (IdePage *)widget;
+ IdeBuffer *buffer = data;
- if (l->page == NULL &&
- IDE_IS_EDITOR_PAGE (page) &&
- ide_editor_page_get_buffer (IDE_EDITOR_PAGE (page)) == l->buffer)
- l->page = IDE_PAGE (page);
-}
-
-static IdePage *
-get_page (IdeBuffer *buffer)
-{
- Lookup lookup = {buffer, NULL};
- IdeContext *context = ide_buffer_ref_context (buffer);
- IdeWorkbench *workbench = ide_workbench_from_context (context);
- ide_workbench_foreach_page (workbench, foreach_page_cb, &lookup);
-
- return lookup.page;
-}
-
-gboolean
-format_on_save_enabled (IdeBuffer *buffer)
-{
- g_autoptr (GSettings) settings = g_settings_new ("org.gnome.builder");
-
- return g_settings_get_boolean (settings, "format-on-save");
-}
-
-gboolean
-is_formattable_language (IdeBuffer *buffer)
-{
- const gchar *lang_id;
-
- lang_id = ide_buffer_get_language_id (buffer);
- if (lang_id == NULL)
- {
- g_debug ("Language ID was NULL");
- return FALSE;
- }
-
- if (strcmp (lang_id, "c") == 0 || strcmp (lang_id, "chdr") == 0 ||
- strcmp (lang_id, "cpp") == 0 || strcmp (lang_id, "cpphdr") == 0 ||
- strcmp (lang_id, "objc") == 0)
- return TRUE;
-
- return FALSE;
-}
-
-char *
-project_root_directory (IdeBuffer *buffer)
-{
- IdeContext *context;
- GFile *workdir;
-
- context = ide_buffer_ref_context (buffer);
- if (context == NULL)
- {
- g_warning ("Failed to get IdeContext");
- return NULL;
- }
-
- workdir = ide_context_ref_workdir (context);
- if (workdir == NULL)
- {
- g_warning ("Failed to get working directory");
- return NULL;
- }
-
- return g_file_get_path (workdir);
-}
-
-gboolean
-clang_format_config_exists (GbClangFormatBufferAddin *self,
- IdeBuffer *buffer)
-{
- GFile *config;
-
- config = g_file_new_build_filename (self->working_directory, ".clang-format", NULL);
-
- return g_file_query_exists (config, NULL);
-}
+ g_assert (IDE_IS_PAGE (page));
+ g_assert (IDE_IS_BUFFER (buffer));
-gint
-get_cursor_position (IdeBuffer *buffer)
-{
- GtkTextBuffer *textbuffer;
- gint cursor_position;
+ if (!IDE_IS_EDITOR_PAGE (page))
+ return;
- textbuffer = GTK_TEXT_BUFFER (buffer);
- g_object_get (G_OBJECT (textbuffer), "cursor-position", &cursor_position, NULL);
+ if (buffer != ide_editor_page_get_buffer (IDE_EDITOR_PAGE (page)))
+ return;
- return cursor_position;
+ gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (ide_editor_page_get_view (IDE_EDITOR_PAGE (page))),
+ gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (buffer)));
}
-gssize
-get_header_length (gchar *data)
+static gboolean
+clang_supports_language (GtkSourceLanguage *language)
{
- gssize len = g_utf8_strlen (data, G_MAXSSIZE);
-
- for (gssize i = 0; i < len; ++i)
- if (data[i] == '\n')
- return (i + 1 <= len ? (i + 1) : i);
-
- return 0;
+ static const char *supported[] = { "c", "chdr", "cpp", "cpphdr", "objc", NULL };
+ g_assert (!language || GTK_SOURCE_IS_LANGUAGE (language));
+ return language != NULL &&
+ g_strv_contains (supported, gtk_source_language_get_id (language));
}
-gboolean
-parse_header (GbClangFormatBufferAddin *self,
- gchar *data)
+static int
+get_cursor_position (const char *str,
+ guint length)
{
- JsonParser *parser;
- gboolean ret;
- GError *error;
+ g_autoptr(JsonParser) parser = NULL;
+ JsonObject *object;
JsonNode *root;
- JsonObject *cursor;
- self->header_len = get_header_length (data);
- if (self->header_len <= 0)
- {
- g_warning ("Empty header");
- return FALSE;
- }
+ g_assert (str != NULL);
- error = NULL;
parser = json_parser_new ();
- ret = json_parser_load_from_data (parser, data, self->header_len, &error);
- if (ret == FALSE)
- {
- g_warning ("Unable to parse JSON: %s", error->message);
- g_error_free (error);
- g_object_unref (parser);
- return FALSE;
- }
+ if (!json_parser_load_from_data (parser, str, length, NULL))
+ return -1;
- root = json_parser_get_root (parser);
- cursor = json_node_get_object (root);
- if (cursor == NULL)
- {
- g_warning ("clang-format didn't return cursor position");
- g_object_unref (parser);
- return FALSE;
- }
- self->cursor_position = json_object_get_int_member (cursor, "Cursor");
-
- g_object_unref (parser);
- return TRUE;
-}
+ if (!(root = json_parser_get_root (parser)) ||
+ !JSON_NODE_HOLDS_OBJECT (root) ||
+ !(object = json_node_get_object (root)) ||
+ !json_object_has_member (object, "Cursor"))
+ return -1;
-gchar *
-format_cursor_arg (gssize position)
-{
- return g_strdup_printf ("--cursor=%zu", position);
+ return json_object_get_int_member (object, "Cursor");
}
-IdeSubprocess *
-create_process (GbClangFormatBufferAddin *self)
-{
- g_autoptr (IdeSubprocessLauncher) launcher = NULL;
- IdeSubprocess *subprocess = NULL;
- GPtrArray *args;
- GError *error = NULL;
- gchar *cursor_arg;
-
- cursor_arg = format_cursor_arg (self->cursor_position);
-
- args = g_ptr_array_new ();
- g_ptr_array_add (args, (gchar *)"clang-format");
- g_ptr_array_add (args, cursor_arg);
- g_ptr_array_add (args, NULL);
-
- launcher = ide_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE
- | G_SUBPROCESS_FLAGS_STDOUT_PIPE
- | G_SUBPROCESS_FLAGS_STDERR_PIPE);
- ide_subprocess_launcher_set_cwd (launcher, self->working_directory);
- ide_subprocess_launcher_set_argv (launcher,
- (const gchar *const *)args->pdata);
- subprocess = ide_subprocess_launcher_spawn (launcher, NULL, &error);
-
- g_ptr_array_free (args, TRUE);
- g_free (cursor_arg);
- return subprocess;
-}
-
-gboolean
-process_communicate (IdeSubprocess *process,
- IdeBuffer *buffer,
- gchar **stdout_buf)
+static void
+gb_clang_format_buffer_addin_save_file (IdeBufferAddin *addin,
+ IdeBuffer *buffer,
+ GFile *file)
{
- const gchar *stdin_buf;
- gchar *stderr_buf = NULL;
- GError *error = NULL;
- gboolean ret;
-
+ GbClangFormatBufferAddin *self = (GbClangFormatBufferAddin *)addin;
+ g_autoptr(IdeSubprocessLauncher) launcher = NULL;
+ g_autoptr(IdeSubprocess) subprocess = NULL;
+ g_autoptr(IdeContext) context = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GFile) workdir = NULL;
+ g_autoptr(GFile) dot_clang_format = NULL;
+ g_autofree char *cursor_arg = NULL;
+ g_autofree char *stdout_buf = NULL;
+ GtkSourceLanguage *language;
+ IdeWorkbench *workbench;
+ const char *stdin_buf;
+ const char *formatted;
+ GtkTextIter iter;
+ int cursor_position;
+
+ IDE_ENTRY;
+
+ g_assert (GB_IS_CLANG_FORMAT_BUFFER_ADDIN (self));
+ g_assert (IDE_IS_BUFFER (buffer));
+ g_assert (G_IS_FILE (file));
+
+ if (!g_settings_get_boolean (settings, "format-on-save"))
+ IDE_EXIT;
+
+ if (!(context = ide_buffer_ref_context (buffer)))
+ IDE_EXIT;
+
+ if (!(workdir = ide_context_ref_workdir (context)) || !g_file_is_native (workdir))
+ IDE_EXIT;
+
+ if (!(language = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (buffer))) ||
+ !clang_supports_language (language))
+ IDE_EXIT;
+
+ dot_clang_format = g_file_get_child (workdir, ".clang-format");
+ if (!g_file_query_exists (dot_clang_format, NULL))
+ IDE_EXIT;
+
+ gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer),
+ &iter,
+ gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (buffer)));
+ cursor_arg = g_strdup_printf ("--cursor=%u", gtk_text_iter_get_offset (&iter));
stdin_buf = g_bytes_get_data (ide_buffer_dup_content (buffer), NULL);
- ret = ide_subprocess_communicate_utf8 (process, stdin_buf, NULL, stdout_buf,
- &stderr_buf, &error);
- if (ret == FALSE)
+ launcher = ide_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE |
+ G_SUBPROCESS_FLAGS_STDOUT_PIPE |
+ G_SUBPROCESS_FLAGS_STDERR_SILENCE);
+ ide_subprocess_launcher_set_cwd (launcher, g_file_peek_path (workdir));
+ ide_subprocess_launcher_push_argv (launcher, "clang-format");
+ ide_subprocess_launcher_push_argv (launcher, cursor_arg);
+
+ if (!(subprocess = ide_subprocess_launcher_spawn (launcher, NULL, &error)))
{
- g_warning ("clang-format failed: %s", error->message);
- g_free (error);
- return FALSE;
+ g_debug ("Failed to spawn clang-format: %s", error->message);
+ IDE_EXIT;
}
- return TRUE;
-}
-
-void
-run_clang_format (GbClangFormatBufferAddin *self,
- IdeBuffer *buffer)
-{
- IdeSubprocess *process;
- gchar *stdout_buf = NULL;
- gchar *data_start;
- gsize data_len;
- GtkTextIter cursor;
-
- process = create_process (self);
- if (process_communicate (process, buffer, &stdout_buf) == FALSE)
- return;
-
- if (parse_header (self, stdout_buf) == FALSE)
- return;
-
- data_start = stdout_buf + self->header_len;
- data_len = strlen (data_start);
- if (data_len <= 0)
+ if (!ide_subprocess_communicate_utf8 (subprocess, stdin_buf, NULL, &stdout_buf, NULL, &error))
{
- g_warning ("No output");
- return;
+ g_debug ("Failed to communicate with subprocess: %s", error->message);
+ IDE_EXIT;
}
- if (data_start[data_len - 1] == '\n')
- data_len--;
-
- gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (buffer));
-
- gtk_text_buffer_set_text (GTK_TEXT_BUFFER (buffer), data_start, data_len);
-
- gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &cursor);
- gtk_text_iter_set_offset (&cursor, self->cursor_position);
- gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (buffer), &cursor);
-
- gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (buffer));
-
- if (self->page != NULL)
+ if (!(formatted = strchr (stdout_buf, '\n')))
{
- IdeSourceView *source_view = ide_editor_page_get_view (IDE_EDITOR_PAGE (self->page));
- gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (source_view), &cursor, 0.25, FALSE, 0.5, 0.5);
+ g_debug ("Missing or corrupted data from clang-format");
+ IDE_EXIT;
}
- else
- g_warning ("Failed to get page");
-}
-
-static void
-gb_clang_format_buffer_addin_save_file (IdeBufferAddin *addin,
- IdeBuffer *buffer,
- GFile *file)
-{
- GbClangFormatBufferAddin *self;
- if (format_on_save_enabled (buffer) == FALSE)
- return;
+ if ((cursor_position = get_cursor_position (stdout_buf, formatted - stdout_buf)) < 0)
+ IDE_EXIT;
- if (is_formattable_language (buffer) == FALSE)
- return;
-
- self = (GbClangFormatBufferAddin *)addin;
- self->working_directory = project_root_directory (buffer);
- if (self->working_directory == NULL)
- {
- g_warning ("Failed to get working directory");
- return;
- }
+ gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (buffer));
+ gtk_text_buffer_set_text (GTK_TEXT_BUFFER (buffer), formatted + 1, -1);
+ gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &iter, cursor_position);
+ gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer), &iter, &iter);
+ gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (buffer));
- if (clang_format_config_exists (self, buffer) == FALSE)
- {
- g_debug ("No .clang-format");
- return;
- }
- self->cursor_position = get_cursor_position (buffer);
- self->page = get_page (buffer);
+ workbench = ide_workbench_from_context (context);
+ ide_workbench_foreach_page (workbench, scroll_page_to_insert, buffer);
- run_clang_format (self, buffer);
+ IDE_EXIT;
}
static void
buffer_addin_iface_init (IdeBufferAddinInterface *iface)
{
- iface->load = NULL;
- iface->unload = NULL;
iface->save_file = gb_clang_format_buffer_addin_save_file;
- iface->file_loaded = NULL;
}
G_DEFINE_FINAL_TYPE_WITH_CODE (GbClangFormatBufferAddin, gb_clang_format_buffer_addin, G_TYPE_OBJECT,
@@ -347,6 +190,7 @@ G_DEFINE_FINAL_TYPE_WITH_CODE (GbClangFormatBufferAddin, gb_clang_format_buffer_
static void
gb_clang_format_buffer_addin_class_init (GbClangFormatBufferAddinClass *klass)
{
+ settings = g_settings_new ("org.gnome.builder");
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]