[gnome-builder] libide-editor: port to GTK 4
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] libide-editor: port to GTK 4
- Date: Tue, 12 Jul 2022 06:39:13 +0000 (UTC)
commit 40e8a3b3ad6090e14cab87b70aacc63a27485513
Author: Christian Hergert <chergert redhat com>
Date: Mon Jul 11 22:00:43 2022 -0700
libide-editor: port to GTK 4
- Remove use of IdeSurface (we don't have surfaces anymore)
- Rewrite IdeEditorPage using more code from Text Editor
- Cleanup shortcuts
- Delete lots of janky code (some may come back)
- Remove settings dialog (plugins will provide alternative UI)
- Remove sidebar/utilities/etc
- Add encoding/line-ending support
- Cleanup open/discovery code to use IdePanelPosition
There is still a lot missing from this port. Search has not yet been ported
over from Text Editor for example.
src/libide/editor/gtk/menus.ui | 74 +
src/libide/editor/ide-editor-addin.c | 160 --
src/libide/editor/ide-editor-addin.h | 64 -
...e-editor-plugin-private.h => ide-editor-init.c} | 21 +-
src/libide/editor/ide-editor-page-actions.c | 605 +-----
src/libide/editor/ide-editor-page-addin.c | 8 +-
src/libide/editor/ide-editor-page-addin.h | 15 +-
src/libide/editor/ide-editor-page-private.h | 59 +
src/libide/editor/ide-editor-page-settings.c | 359 ++--
src/libide/editor/ide-editor-page-shortcuts.c | 153 --
src/libide/editor/ide-editor-page.c | 1495 +++++----------
src/libide/editor/ide-editor-page.h | 83 +-
src/libide/editor/ide-editor-page.ui | 126 +-
src/libide/editor/ide-editor-print-operation.c | 210 --
src/libide/editor/ide-editor-print-operation.h | 33 -
src/libide/editor/ide-editor-private.h | 85 +-
.../editor/ide-editor-search-bar-shortcuts.c | 72 -
src/libide/editor/ide-editor-search-bar.c | 661 -------
src/libide/editor/ide-editor-search-bar.h | 44 -
src/libide/editor/ide-editor-search-bar.ui | 283 ---
src/libide/editor/ide-editor-search.c | 2025 --------------------
src/libide/editor/ide-editor-search.h | 146 --
src/libide/editor/ide-editor-settings-dialog.c | 335 ----
src/libide/editor/ide-editor-settings-dialog.h | 34 -
src/libide/editor/ide-editor-settings-dialog.ui | 295 ---
src/libide/editor/ide-editor-sidebar.c | 557 ------
src/libide/editor/ide-editor-sidebar.h | 54 -
src/libide/editor/ide-editor-sidebar.ui | 113 --
src/libide/editor/ide-editor-surface-actions.c | 164 --
src/libide/editor/ide-editor-surface-shortcuts.c | 113 --
src/libide/editor/ide-editor-surface.c | 1093 -----------
src/libide/editor/ide-editor-surface.h | 65 -
src/libide/editor/ide-editor-surface.ui | 36 -
src/libide/editor/ide-editor-utilities.c | 85 -
src/libide/editor/ide-editor-utils.c | 310 +++
src/libide/editor/ide-editor-utils.h | 41 +
src/libide/editor/ide-editor-workspace.c | 234 ++-
src/libide/editor/ide-editor-workspace.h | 8 +-
src/libide/editor/ide-editor-workspace.ui | 117 +-
src/libide/editor/ide-editor.c | 260 +++
.../{ide-editor-utilities.h => ide-editor.h} | 23 +-
src/libide/editor/libide-editor.gresource.xml | 8 +-
src/libide/editor/libide-editor.h | 24 +-
src/libide/editor/meson.build | 29 +-
src/libide/editor/style.css | 12 +
45 files changed, 1817 insertions(+), 8974 deletions(-)
---
diff --git a/src/libide/editor/gtk/menus.ui b/src/libide/editor/gtk/menus.ui
new file mode 100644
index 000000000..714b35ec7
--- /dev/null
+++ b/src/libide/editor/gtk/menus.ui
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <menu id="ide-editor-workspace-menu">
+ <section id="ide-editor-workspace-menu-theme-section">
+ <item>
+ <attribute name="custom">theme_selector</attribute>
+ </item>
+ </section>
+ <section id="ide-editor-workspace-menu-projects-section"/>
+ <section id="ide-editor-workspace-menu-placeholder1"/>
+ <section id="ide-editor-workspace-menu-placeholder2"/>
+ <section id="ide-editor-workspace-menu-open-section">
+ <attribute name="id">ide-editor-workspace-menu-open-section</attribute>
+ <item>
+ <attribute name="id">ide-editor-workspace-menu-open</attribute>
+ <attribute name="label" translatable="yes">Open Fileā¦</attribute>
+ <attribute name="action">workbench.open</attribute>
+ <attribute name="accel"><primary>o</attribute>
+ </item>
+ </section>
+ <section id="ide-editor-workspace-menu-app-section">
+ <attribute name="id">ide-editor-workspace-menu-app-section</attribute>
+ <item>
+ <attribute name="id">ide-editor-workspace-menu-preferences</attribute>
+ <attribute name="label" translatable="yes">Preferences</attribute>
+ <attribute name="action">app.preferences</attribute>
+ <attribute name="accel"><primary>comma</attribute>
+ </item>
+ <item>
+ <attribute name="id">ide-editor-workspace-menu-shortcuts</attribute>
+ <attribute name="label" translatable="yes">Keyboard Shortcuts</attribute>
+ <attribute name="action">app.shortcuts</attribute>
+ <attribute name="accel"><primary>question</attribute>
+ </item>
+ <item>
+ <attribute name="id">ide-editor-workspace-menu-help</attribute>
+ <attribute name="label" translatable="yes">Help</attribute>
+ <attribute name="action">app.help</attribute>
+ <attribute name="accel">F1</attribute>
+ </item>
+ <item>
+ <attribute name="id">ide-editor-workspace-menu-about</attribute>
+ <attribute name="label" translatable="yes">About Builder</attribute>
+ <attribute name="action">app.about</attribute>
+ </item>
+ </section>
+ <section id="ide-editor-workspace-menu-quit-section">
+ <attribute name="id">ide-editor-workspace-menu-quit-section</attribute>
+ <item>
+ <attribute name="id">ide-editor-workspace-menu-quit</attribute>
+ <attribute name="label" translatable="yes">_Quit</attribute>
+ <attribute name="action">app.quit</attribute>
+ </item>
+ </section>
+ </menu>
+ <menu id="ide-editor-page-menu">
+ <section id="ide-editor-page-document-section">
+ <attribute name="label" translatable="yes">Document</attribute>
+ </section>
+ <section id="ide-editor-page-preview-section">
+ <attribute name="after">ide-editor-page-document-section</attribute>
+ </section>
+ <section id="ide-editor-page-reveal-section"/>
+ <section id="ide-editor-page-save-section">
+ <attribute name="after">ide-editor-page-reveal-section</attribute>
+ <item>
+ <attribute name="label" translatable="yes">Save</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Save As</attribute>
+ </item>
+ </section>
+ </menu>
+</interface>
diff --git a/src/libide/editor/ide-editor-plugin-private.h b/src/libide/editor/ide-editor-init.c
similarity index 66%
rename from src/libide/editor/ide-editor-plugin-private.h
rename to src/libide/editor/ide-editor-init.c
index c86344740..53006395a 100644
--- a/src/libide/editor/ide-editor-plugin-private.h
+++ b/src/libide/editor/ide-editor-init.c
@@ -1,6 +1,6 @@
-/* ide-editor-plugin-private.h
+/* ide-editor-init.c
*
- * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2022 Christian Hergert <chergert redhat com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,10 +18,17 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
-#pragma once
+#define G_LOG_DOMAIN "ide-editor-init"
-#include <libide-core.h>
-#include <libpeas/peas.h>
+#include "config.h"
-IDE_AVAILABLE_IN_3_32
-void _ide_editor_register_types (PeasObjectModule *module);
+#include "ide-editor-page.h"
+#include "ide-editor-private.h"
+#include "ide-editor-workspace.h"
+
+void
+_ide_editor_init (void)
+{
+ g_type_ensure (IDE_TYPE_EDITOR_PAGE);
+ g_type_ensure (IDE_TYPE_EDITOR_WORKSPACE);
+}
diff --git a/src/libide/editor/ide-editor-page-actions.c b/src/libide/editor/ide-editor-page-actions.c
index 124e5daff..da4e04bf2 100644
--- a/src/libide/editor/ide-editor-page-actions.c
+++ b/src/libide/editor/ide-editor-page-actions.c
@@ -1,6 +1,6 @@
/* ide-editor-page-actions.c
*
- * Copyright 2017-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2022 Christian Hergert <chergert redhat com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,195 +23,8 @@
#include "config.h"
#include <glib/gi18n.h>
-#include <libide-code.h>
-#include <libide-gui.h>
-#include "ide-editor-surface.h"
-#include "ide-editor-private.h"
-#include "ide-editor-print-operation.h"
-#include "ide-editor-settings-dialog.h"
-
-typedef struct
-{
- IdeEditorPage *self;
- guint line;
- guint line_offset;
-} ReloadState;
-
-static void
-reload_state_free (ReloadState *state)
-{
- g_clear_object (&state->self);
- g_slice_free (ReloadState, state);
-}
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (ReloadState, reload_state_free)
-
-static void
-ide_editor_page_actions_reload_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- IdeBufferManager *bufmgr = (IdeBufferManager *)object;
- g_autoptr(ReloadState) state = user_data;
- g_autoptr(IdeBuffer) buffer = NULL;
- g_autoptr(GError) error = NULL;
-
- g_assert (IDE_IS_BUFFER_MANAGER (bufmgr));
- g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (state != NULL);
- g_assert (IDE_IS_EDITOR_PAGE (state->self));
-
- if (state->self->progress_bar != NULL)
- dzl_gtk_widget_hide_with_fade (GTK_WIDGET (state->self->progress_bar));
-
- if (!(buffer = ide_buffer_manager_load_file_finish (bufmgr, result, &error)))
- {
- g_warning ("%s", error->message);
- ide_page_report_error (IDE_PAGE (state->self),
- /* translators: %s is the error message */
- _("Failed to load file: %s"), error->message);
- ide_page_set_failed (IDE_PAGE (state->self), TRUE);
- }
- else
- {
- IdeSourceView *view;
- GtkTextIter iter;
-
- view = ide_editor_page_get_view (state->self);
- gtk_text_buffer_get_iter_at_line_offset (GTK_TEXT_BUFFER (buffer),
- &iter,
- state->line,
- state->line_offset);
- gtk_text_buffer_select_range (GTK_TEXT_BUFFER (buffer), &iter, &iter);
- ide_source_view_scroll_to_iter (view,
- &iter,
- .25,
- IDE_SOURCE_SCROLL_BOTH,
- 1.0,
- 0.5,
- FALSE);
-
- }
-
- gtk_revealer_set_reveal_child (state->self->modified_revealer, FALSE);
-}
-
-static void
-ide_editor_page_actions_reload (GSimpleAction *action,
- GVariant *param,
- gpointer user_data)
-{
- IdeEditorPage *self = user_data;
- g_autoptr(IdeNotification) notif = NULL;
- g_autoptr(IdeContext) context = NULL;
- IdeBufferManager *bufmgr;
- ReloadState *state;
- GtkTextIter iter;
- IdeBuffer *buffer;
- GFile *file;
-
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- buffer = ide_editor_page_get_buffer (self);
- context = ide_buffer_ref_context (buffer);
- bufmgr = ide_buffer_manager_from_context (context);
- file = ide_buffer_get_file (buffer);
-
- gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (self->progress_bar), 0.0);
- gtk_widget_show (GTK_WIDGET (self->progress_bar));
-
- notif = ide_notification_new ();
-
- ide_buffer_get_selection_bounds (buffer, &iter, NULL);
-
- state = g_slice_new0 (ReloadState);
- state->self = g_object_ref (self);
- state->line = gtk_text_iter_get_line (&iter);
- state->line_offset = gtk_text_iter_get_line_offset (&iter);
-
- ide_buffer_manager_load_file_async (bufmgr,
- file,
- IDE_BUFFER_OPEN_FLAGS_FORCE_RELOAD,
- notif,
- NULL,
- ide_editor_page_actions_reload_cb,
- g_steal_pointer (&state));
-
- g_object_bind_property (notif, "progress",
- self->progress_bar, "fraction",
- G_BINDING_SYNC_CREATE);
-}
-
-static void
-handle_print_result (IdeEditorPage *self,
- GtkPrintOperation *operation,
- GtkPrintOperationResult result)
-{
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (GTK_IS_PRINT_OPERATION (operation));
-
- if (result == GTK_PRINT_OPERATION_RESULT_ERROR)
- {
- g_autoptr(GError) error = NULL;
-
- gtk_print_operation_get_error (operation, &error);
-
- g_warning ("%s", error->message);
- ide_page_report_error (IDE_PAGE (self),
- /* translators: %s is the error message */
- _("Print failed: %s"), error->message);
- }
-}
-
-static void
-print_done (GtkPrintOperation *operation,
- GtkPrintOperationResult result,
- gpointer user_data)
-{
- IdeEditorPage *self = user_data;
-
- g_assert (GTK_IS_PRINT_OPERATION (operation));
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- handle_print_result (self, operation, result);
-
- g_object_unref (operation);
- g_object_unref (self);
-}
-
-static void
-ide_editor_page_actions_print (GSimpleAction *action,
- GVariant *param,
- gpointer user_data)
-{
- g_autoptr(IdeEditorPrintOperation) operation = NULL;
- IdeEditorPage *self = user_data;
- IdeSourceView *source_view;
- GtkWidget *toplevel;
- GtkPrintOperationResult result;
-
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- toplevel = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_WINDOW);
-
- source_view = ide_editor_page_get_view (self);
- operation = ide_editor_print_operation_new (source_view);
-
- /* keep a ref until "done" is emitted */
- g_object_ref (operation);
- g_signal_connect_after (g_object_ref (operation),
- "done",
- G_CALLBACK (print_done),
- g_object_ref (self));
-
- result = gtk_print_operation_run (GTK_PRINT_OPERATION (operation),
- GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
- GTK_WINDOW (toplevel),
- NULL);
-
- handle_print_result (self, GTK_PRINT_OPERATION (operation), result);
-}
+#include "ide-editor-page-private.h"
static void
ide_editor_page_actions_save_cb (GObject *object,
@@ -222,421 +35,51 @@ ide_editor_page_actions_save_cb (GObject *object,
g_autoptr(IdeEditorPage) self = user_data;
g_autoptr(GError) error = NULL;
+ IDE_ENTRY;
+
g_assert (IDE_IS_BUFFER (buffer));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_EDITOR_PAGE (self));
if (!ide_buffer_save_file_finish (buffer, result, &error))
- {
- g_warning ("%s", error->message);
- ide_page_report_error (IDE_PAGE (self),
- /* translators: %s is the error message */
- _("Failed to save file: %s"), error->message);
- ide_page_set_failed (IDE_PAGE (self), TRUE);
- }
+ ide_page_report_error (IDE_PAGE (self),
+ /* translators: %s is replaced with a technical error message */
+ _("Failed to save file: %s"),
+ error->message);
+
+ ide_page_set_progress (IDE_PAGE (self), NULL);
- if (self->progress_bar != NULL)
- dzl_gtk_widget_hide_with_fade (GTK_WIDGET (self->progress_bar));
+ IDE_EXIT;
}
static void
-ide_editor_page_actions_save (GSimpleAction *action,
- GVariant *variant,
- gpointer user_data)
+ide_editor_page_actions_save (GtkWidget *widget,
+ const char *action_name,
+ GVariant *param)
{
- IdeEditorPage *self = user_data;
+ IdeEditorPage *self = (IdeEditorPage *)widget;
g_autoptr(IdeNotification) notif = NULL;
- g_autoptr(IdeContext) context = NULL;
- g_autoptr(GFile) local_file = NULL;
- g_autoptr(GFile) workdir = NULL;
- IdeBuffer *buffer;
- GFile *file;
-
- g_assert (G_IS_SIMPLE_ACTION (action));
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- buffer = ide_editor_page_get_buffer (self);
- g_return_if_fail (IDE_IS_BUFFER (buffer));
-
- context = ide_buffer_ref_context (buffer);
- g_return_if_fail (IDE_IS_CONTEXT (context));
-
- file = ide_buffer_get_file (buffer);
- g_return_if_fail (G_IS_FILE (file));
-
- workdir = ide_context_ref_workdir (context);
- g_assert (G_IS_FILE (workdir));
-
- if (ide_buffer_get_is_temporary (buffer))
- {
- GtkFileChooserNative *dialog;
- GtkWidget *toplevel;
- gint ret;
-
- toplevel = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_WINDOW);
-
- dialog = gtk_file_chooser_native_new (_("Save File"),
- GTK_WINDOW (toplevel),
- GTK_FILE_CHOOSER_ACTION_SAVE,
- _("Save"), _("Cancel"));
-
- g_object_set (dialog,
- "do-overwrite-confirmation", TRUE,
- "local-only", FALSE,
- "modal", TRUE,
- "select-multiple", FALSE,
- "show-hidden", FALSE,
- NULL);
- gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (dialog), workdir, NULL);
+ IDE_ENTRY;
- ret = gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog));
-
- if (ret == GTK_RESPONSE_ACCEPT)
- file = local_file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
-
- gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (dialog));
-
- if (local_file == NULL)
- return;
- }
+ g_assert (IDE_IS_EDITOR_PAGE (self));
- ide_buffer_save_file_async (buffer,
- file,
+ ide_buffer_save_file_async (self->buffer,
+ NULL,
NULL,
¬if,
ide_editor_page_actions_save_cb,
g_object_ref (self));
- g_object_bind_property (notif, "progress", self->progress_bar, "fraction",
- G_BINDING_SYNC_CREATE);
-
- gtk_widget_show (GTK_WIDGET (self->progress_bar));
-}
-
-
-static void
-ide_editor_page_actions_save_as_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- IdeBuffer *buffer = (IdeBuffer *)object;
- g_autoptr(IdeEditorPage) self = user_data;
- g_autoptr(GError) error = NULL;
-
- g_assert (IDE_IS_BUFFER (buffer));
- g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- if (!ide_buffer_save_file_finish (buffer, result, &error))
- {
- /* In this case, the editor page hasn't failed since this is for an
- * alternate file (which maybe we just don't have access to on the
- * network or something).
- *
- * But we do still need to notify the user of the error.
- */
- g_warning ("%s", error->message);
- ide_page_report_error (IDE_PAGE (self),
- /* translators: %s is the underlying error message */
- _("Failed to save file: %s"),
- error->message);
- }
-
- dzl_gtk_widget_hide_with_fade (GTK_WIDGET (self->progress_bar));
-}
-
-static void
-ide_editor_page_actions_save_as (GSimpleAction *action,
- GVariant *param,
- gpointer user_data)
-{
- IdeEditorPage *self = user_data;
- GtkFileChooserNative *dialog;
- IdeBuffer *buffer;
- GtkWidget *toplevel;
- GFile *file;
- gint ret;
-
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- buffer = ide_editor_page_get_buffer (self);
- file = ide_buffer_get_file (buffer);
-
- /* Just redirect to the save flow if we have a temporary
- * file currently. That way we can avoid splitting the
- * flow to handle both cases here.
- */
- if (ide_buffer_get_is_temporary (buffer))
- {
- ide_editor_page_actions_save (action, NULL, user_data);
- return;
- }
-
- toplevel = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_WINDOW);
- dialog = gtk_file_chooser_native_new (_("Save a Copy"),
- GTK_WINDOW (toplevel),
- GTK_FILE_CHOOSER_ACTION_SAVE,
- _("Save"),
- _("Cancel"));
-
- gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
- gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE);
- gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER (dialog), FALSE);
-
- if (file != NULL)
- gtk_file_chooser_set_file (GTK_FILE_CHOOSER (dialog), file, NULL);
-
- ret = gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog));
-
- if (ret == GTK_RESPONSE_ACCEPT)
- {
- g_autoptr(GFile) save_as = NULL;
- g_autoptr(IdeNotification) notif = NULL;
-
- save_as = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
-
- ide_buffer_save_file_async (buffer,
- save_as,
- NULL,
- ¬if,
- ide_editor_page_actions_save_as_cb,
- g_object_ref (self));
-
- g_object_bind_property (notif, "progress", self->progress_bar, "fraction",
- G_BINDING_SYNC_CREATE);
-
- gtk_widget_show (GTK_WIDGET (self->progress_bar));
- }
-
- gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (dialog));
-}
-
-static void
-ide_editor_page_actions_find (GSimpleAction *action,
- GVariant *variant,
- gpointer user_data)
-{
- IdeEditorPage *self = user_data;
- GtkTextIter begin;
- GtkTextIter end;
-
- g_assert (G_IS_SIMPLE_ACTION (action));
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- if (gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (self->buffer), &begin, &end))
- {
- g_autofree gchar *word = gtk_text_iter_get_slice (&begin, &end);
- ide_editor_search_set_search_text (self->search, word);
- }
-
- ide_editor_search_bar_set_replace_mode (self->search_bar, FALSE);
- gtk_revealer_set_reveal_child (self->search_revealer, TRUE);
- gtk_widget_grab_focus (GTK_WIDGET (self->search_bar));
-}
-
-static void
-ide_editor_page_actions_find_replace (GSimpleAction *action,
- GVariant *variant,
- gpointer user_data)
-{
- IdeEditorPage *self = user_data;
- GtkTextIter begin;
- GtkTextIter end;
-
- g_assert (G_IS_SIMPLE_ACTION (action));
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- if (gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (self->buffer), &begin, &end))
- {
- g_autofree gchar *word = gtk_text_iter_get_slice (&begin, &end);
- ide_editor_search_set_search_text (self->search, word);
- }
-
- ide_editor_search_bar_set_replace_mode (self->search_bar, TRUE);
- gtk_revealer_set_reveal_child (self->search_revealer, TRUE);
- gtk_widget_grab_focus (GTK_WIDGET (self->search_bar));
-}
-
-static void
-ide_editor_page_actions_hide_search (GSimpleAction *action,
- GVariant *variant,
- gpointer user_data)
-{
- IdeEditorPage *self = user_data;
-
- g_assert (G_IS_SIMPLE_ACTION (action));
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- gtk_revealer_set_reveal_child (self->search_revealer, FALSE);
- gtk_widget_grab_focus (GTK_WIDGET (self->source_view));
-}
-
-static void
-ide_editor_page_actions_notify_file_settings (IdeEditorPage *self,
- GParamSpec *pspec,
- IdeSourceView *source_view)
-{
- IdeFileSettings *file_settings;
- GActionGroup *group;
-
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (IDE_IS_SOURCE_VIEW (source_view));
-
- group = gtk_widget_get_action_group (GTK_WIDGET (self), "file-settings");
- g_assert (DZL_IS_PROPERTIES_GROUP (group));
-
- file_settings = ide_source_view_get_file_settings (source_view);
- g_assert (!file_settings || IDE_IS_FILE_SETTINGS (file_settings));
-
- g_object_set (group, "object", file_settings, NULL);
-}
-
-static void
-ide_editor_page_actions_move_next_error (GSimpleAction *action,
- GVariant *variant,
- gpointer user_data)
-{
- ide_editor_page_move_next_error (user_data);
-}
-
-static void
-ide_editor_page_actions_move_previous_error (GSimpleAction *action,
- GVariant *variant,
- gpointer user_data)
-{
- ide_editor_page_move_previous_error (user_data);
-}
-
-static void
-ide_editor_page_actions_activate_next_search_result (GSimpleAction *action,
- GVariant *variant,
- gpointer user_data)
-{
- IdeEditorPage *self = user_data;
- GtkTextIter begin;
- GtkTextIter end;
-
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- ide_editor_page_move_next_search_result (self);
-
- gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (self->buffer), &begin, &end);
- gtk_widget_grab_focus (GTK_WIDGET (self->source_view));
- gtk_text_buffer_select_range (GTK_TEXT_BUFFER (self->buffer), &begin, &end);
- ide_source_view_scroll_to_insert (self->source_view);
-}
-
-static void
-ide_editor_page_actions_move_next_search_result (GSimpleAction *action,
- GVariant *variant,
- gpointer user_data)
-{
- ide_editor_page_move_next_search_result (user_data);
-}
-
-static void
-ide_editor_page_actions_move_previous_search_result (GSimpleAction *action,
- GVariant *variant,
- gpointer user_data)
-{
- ide_editor_page_move_previous_search_result (user_data);
-}
-
-static void
-ide_editor_page_actions_properties (GSimpleAction *action,
- GVariant *variant,
- gpointer user_data)
-{
- IdeEditorPage *self = user_data;
- IdeEditorSettingsDialog *dialog;
-
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- dialog = ide_editor_settings_dialog_new (self);
- g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
- ide_gtk_window_present (GTK_WINDOW (dialog));
-}
-
-static void
-ide_editor_page_actions_toggle_map (GSimpleAction *action,
- GVariant *variant,
- gpointer user_data)
-{
- IdeEditorPage *self = user_data;
-
- g_assert (G_IS_SIMPLE_ACTION (action));
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- ide_editor_page_set_show_map (self, !ide_editor_page_get_show_map (self));
-}
-
-static const GActionEntry editor_view_entries[] = {
- { "activate-next-search-result", ide_editor_page_actions_activate_next_search_result },
- { "find", ide_editor_page_actions_find },
- { "find-replace", ide_editor_page_actions_find_replace },
- { "hide-search", ide_editor_page_actions_hide_search },
- { "move-next-error", ide_editor_page_actions_move_next_error },
- { "move-next-search-result", ide_editor_page_actions_move_next_search_result },
- { "move-previous-error", ide_editor_page_actions_move_previous_error },
- { "move-previous-search-result", ide_editor_page_actions_move_previous_search_result },
- { "properties", ide_editor_page_actions_properties },
- { "print", ide_editor_page_actions_print },
- { "reload", ide_editor_page_actions_reload },
- { "save", ide_editor_page_actions_save },
- { "save-as", ide_editor_page_actions_save_as },
- { "toggle-map", ide_editor_page_actions_toggle_map },
-};
-
-void
-_ide_editor_page_init_actions (IdeEditorPage *self)
-{
- g_autoptr(GSimpleActionGroup) group = NULL;
- g_autoptr(DzlPropertiesGroup) sv_props = NULL;
- g_autoptr(DzlPropertiesGroup) file_props = NULL;
- IdeSourceView *source_view;
-
- g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
-
- source_view = ide_editor_page_get_view (self);
-
- /* Setup our user-facing actions */
- group = g_simple_action_group_new ();
- g_action_map_add_action_entries (G_ACTION_MAP (group),
- editor_view_entries,
- G_N_ELEMENTS (editor_view_entries),
- self);
- gtk_widget_insert_action_group (GTK_WIDGET (self), "editor-page", G_ACTION_GROUP (group));
-
- /* We want to access some settings properties as stateful GAction so they
- * manipulated using regular Gtk widgets from the properties panel.
- */
- sv_props = dzl_properties_group_new (G_OBJECT (source_view));
- dzl_properties_group_add_all_properties (sv_props);
- dzl_properties_group_add_property_full (sv_props,
- "use-spaces",
- "insert-spaces-instead-of-tabs",
- DZL_PROPERTIES_FLAGS_STATEFUL_BOOLEANS);
- gtk_widget_insert_action_group (GTK_WIDGET (self), "source-view", G_ACTION_GROUP (sv_props));
+ ide_page_set_progress (IDE_PAGE (self), notif);
- /*
- * We want to bind our file-settings, used to tweak values in the
- * source-view, to a GActionGroup that can be manipulated by the properties
- * editor. Make sure we get notified of changes and sink the current state.
- */
- file_props = dzl_properties_group_new_for_type (IDE_TYPE_FILE_SETTINGS);
- dzl_properties_group_add_all_properties (file_props);
- g_signal_connect_swapped (source_view,
- "notify::file-settings",
- G_CALLBACK (ide_editor_page_actions_notify_file_settings),
- self);
- gtk_widget_insert_action_group (GTK_WIDGET (self), "file-settings", G_ACTION_GROUP (file_props));
- ide_editor_page_actions_notify_file_settings (self, NULL, source_view);
+ IDE_EXIT;
}
void
-_ide_editor_page_update_actions (IdeEditorPage *self)
+_ide_editor_page_class_actions_init (IdeEditorPageClass *klass)
{
- g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ gtk_widget_class_install_action (widget_class, "page.save", NULL, ide_editor_page_actions_save);
}
diff --git a/src/libide/editor/ide-editor-page-addin.c b/src/libide/editor/ide-editor-page-addin.c
index 5bb1d8476..d90974935 100644
--- a/src/libide/editor/ide-editor-page-addin.c
+++ b/src/libide/editor/ide-editor-page-addin.c
@@ -1,6 +1,6 @@
/* ide-editor-page-addin.c
*
- * Copyright 2015-2019 Christian Hergert <christian hergert me>
+ * Copyright 2015-2022 Christian Hergert <christian hergert me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,8 +22,10 @@
#include "config.h"
-#include "ide-editor-private.h"
+#include <libide-plugins.h>
+
#include "ide-editor-page-addin.h"
+#include "ide-editor-page-private.h"
G_DEFINE_INTERFACE (IdeEditorPageAddin, ide_editor_page_addin, G_TYPE_OBJECT)
@@ -88,8 +90,6 @@ ide_editor_page_addin_frame_set (IdeEditorPageAddin *self,
* #IdeEditorPageAddinInterface, then %NULL is returned.
*
* Returns: (transfer none) (nullable): An #IdeEditorPageAddin or %NULL
- *
- * Since: 3.32
*/
IdeEditorPageAddin *
ide_editor_page_addin_find_by_module_name (IdeEditorPage *page,
diff --git a/src/libide/editor/ide-editor-page-addin.h b/src/libide/editor/ide-editor-page-addin.h
index 4b929b7aa..e0fd9ebfe 100644
--- a/src/libide/editor/ide-editor-page-addin.h
+++ b/src/libide/editor/ide-editor-page-addin.h
@@ -1,6 +1,6 @@
/* ide-editor-page-addin.h
*
- * Copyright 2015-2019 Christian Hergert <christian hergert me>
+ * Copyright 2015-2022 Christian Hergert <christian hergert me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,6 @@
# error "Only <libide-editor.h> can be included directly."
#endif
-
#include <libide-core.h>
#include <libide-gui.h>
@@ -34,7 +33,7 @@ G_BEGIN_DECLS
#define IDE_TYPE_EDITOR_PAGE_ADDIN (ide_editor_page_addin_get_type ())
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
G_DECLARE_INTERFACE (IdeEditorPageAddin, ide_editor_page_addin, IDE, EDITOR_PAGE_ADDIN, GObject)
struct _IdeEditorPageAddinInterface
@@ -51,19 +50,19 @@ struct _IdeEditorPageAddinInterface
IdeFrame *frame);
};
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
void ide_editor_page_addin_load (IdeEditorPageAddin *self,
IdeEditorPage *page);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
void ide_editor_page_addin_unload (IdeEditorPageAddin *self,
IdeEditorPage *page);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
void ide_editor_page_addin_frame_set (IdeEditorPageAddin *self,
IdeFrame *frame);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
void ide_editor_page_addin_language_changed (IdeEditorPageAddin *self,
const gchar *language_id);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
IdeEditorPageAddin *ide_editor_page_addin_find_by_module_name (IdeEditorPage *page,
const gchar *module_name);
diff --git a/src/libide/editor/ide-editor-page-private.h b/src/libide/editor/ide-editor-page-private.h
new file mode 100644
index 000000000..b9aca73b8
--- /dev/null
+++ b/src/libide/editor/ide-editor-page-private.h
@@ -0,0 +1,59 @@
+/* ide-editor-page-private.h
+ *
+ * Copyright 2017-2022 Christian Hergert <chergert redhat com>
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-plugins.h>
+
+#include "ide-editor-page.h"
+
+G_BEGIN_DECLS
+
+struct _IdeEditorPage
+{
+ IdePage parent_instance;
+
+ /* Owned references */
+ IdeExtensionSetAdapter *addins;
+ IdeBuffer *buffer;
+ IdeGutter *gutter;
+
+ /* Settings Management */
+ IdeBindingGroup *buffer_file_settings;
+ IdeBindingGroup *view_file_settings;
+
+ /* Template widgets */
+ IdeSourceView *view;
+ GtkScrolledWindow *scroller;
+ GtkSourceMap *map;
+ GtkRevealer *map_revealer;
+
+ guint completion_blocked : 1;
+};
+
+void _ide_editor_page_class_actions_init (IdeEditorPageClass *klass);
+void _ide_editor_page_settings_init (IdeEditorPage *self);
+void _ide_editor_page_settings_reload (IdeEditorPage *self);
+void _ide_editor_page_settings_connect_gutter (IdeEditorPage *self,
+ IdeGutter *gutter);
+void _ide_editor_page_settings_disconnect_gutter (IdeEditorPage *self,
+ IdeGutter *gutter);
+
+G_END_DECLS
diff --git a/src/libide/editor/ide-editor-page-settings.c b/src/libide/editor/ide-editor-page-settings.c
index 0b4e72524..116c07482 100644
--- a/src/libide/editor/ide-editor-page-settings.c
+++ b/src/libide/editor/ide-editor-page-settings.c
@@ -1,6 +1,6 @@
/* ide-editor-page-settings.c
*
- * Copyright 2017-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2022 Christian Hergert <chergert redhat com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,220 +22,261 @@
#include "config.h"
-#include "ide-editor-private.h"
+#include "ide-editor-page-private.h"
-#include <gtksourceview/gtksource.h>
+static GSettings *editor_settings;
static gboolean
-get_smart_home_end (GValue *value,
- GVariant *variant,
- gpointer user_data)
+indent_style_to_insert_spaces (GBinding *binding,
+ const GValue *from,
+ GValue *to,
+ gpointer user_data)
{
- if (g_variant_get_boolean (variant))
- g_value_set_enum (value, GTK_SOURCE_SMART_HOME_END_BEFORE);
+ g_assert (G_IS_BINDING (binding));
+ g_assert (G_VALUE_HOLDS_ENUM (from));
+ g_assert (G_VALUE_HOLDS_BOOLEAN (to));
+ g_assert (user_data == NULL);
+
+ if (g_value_get_enum (from) == IDE_INDENT_STYLE_TABS)
+ g_value_set_boolean (to, FALSE);
else
- g_value_set_enum (value, GTK_SOURCE_SMART_HOME_END_DISABLED);
+ g_value_set_boolean (to, TRUE);
+
return TRUE;
}
-static gboolean
-get_wrap_mode (GValue *value,
- GVariant *variant,
- gpointer user_data)
+void
+_ide_editor_page_settings_reload (IdeEditorPage *self)
{
- const gchar *wrap_mode = g_variant_get_string (variant, NULL);
+ IdeFileSettings *file_settings;
- if (!g_strcmp0 (wrap_mode, "always"))
- g_value_set_enum (value, GTK_WRAP_WORD_CHAR);
- else if (!g_strcmp0 (wrap_mode, "whitespace"))
- g_value_set_enum (value, GTK_WRAP_WORD);
+ IDE_ENTRY;
+
+ g_return_if_fail (IDE_IS_MAIN_THREAD ());
+ g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
+ g_return_if_fail (IDE_IS_BUFFER (self->buffer));
+ g_return_if_fail (IDE_IS_SOURCE_VIEW (self->view));
+ g_return_if_fail (IDE_IS_BINDING_GROUP (self->buffer_file_settings));
+
+ file_settings = ide_buffer_get_file_settings (self->buffer);
+
+ ide_binding_group_set_source (self->buffer_file_settings, file_settings);
+ ide_binding_group_set_source (self->view_file_settings, file_settings);
+
+ IDE_EXIT;
+}
+
+static gboolean
+show_map_to_vscrollbar_policy (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ if (g_variant_get_boolean (variant))
+ g_value_set_enum (value, GTK_POLICY_EXTERNAL);
else
- g_value_set_enum (value, GTK_WRAP_NONE);
+ g_value_set_enum (value, GTK_POLICY_AUTOMATIC);
+
return TRUE;
}
-static void
-on_keybindings_changed (IdeEditorPage *self,
- const gchar *key,
- GSettings *settings)
+static gboolean
+grid_lines_to_background_pattern (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
{
- IdeSourceView *source_view;
+ if (g_variant_get_boolean (variant))
+ g_value_set_enum (value, GTK_SOURCE_BACKGROUND_PATTERN_TYPE_GRID);
+ else
+ g_value_set_enum (value, GTK_SOURCE_BACKGROUND_PATTERN_TYPE_NONE);
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (g_strcmp0 (key, "keybindings") == 0);
- g_assert (G_IS_SETTINGS (settings));
+ return TRUE;
+}
+
+static gboolean
+font_name_to_font_desc (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ const char *str;
- source_view = ide_editor_page_get_view (self);
+ if ((str = g_variant_get_string (variant, NULL)))
+ g_value_take_boxed (value, pango_font_description_from_string (str));
+ else
+ g_value_set_boxed (value, NULL);
- g_signal_emit_by_name (source_view,
- "set-mode",
- NULL,
- IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT);
+ return TRUE;
}
static void
-on_draw_spaces_changed (IdeEditorPage *self,
- const gchar *key,
- GSettings *settings)
+notify_interactive_completion_cb (IdeEditorPage *self,
+ const char *key,
+ GSettings *settings)
{
- GtkSourceView *source_view;
- GtkSourceSpaceDrawer *drawer;
- guint flags;
- GtkSourceSpaceLocationFlags location_flags = GTK_SOURCE_SPACE_LOCATION_NONE;
- GtkSourceSpaceTypeFlags type_flags = GTK_SOURCE_SPACE_TYPE_NONE;
+ GtkSourceCompletion *completion;
g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (g_strcmp0 (key, "draw-spaces") == 0);
g_assert (G_IS_SETTINGS (settings));
- source_view = GTK_SOURCE_VIEW (ide_editor_page_get_view (self));
- drawer = gtk_source_view_get_space_drawer (source_view);
- flags = g_settings_get_flags (settings, "draw-spaces");
+ completion = gtk_source_view_get_completion (GTK_SOURCE_VIEW (self->view));
- if (flags == 0)
+ if (g_settings_get_boolean (settings, "interactive-completion"))
{
- gtk_source_space_drawer_set_enable_matrix (drawer, FALSE);
- return;
+ if (self->completion_blocked)
+ {
+ self->completion_blocked = FALSE;
+ gtk_source_completion_unblock_interactive (completion);
+ }
}
-
- /* Reset the matrix before setting it */
- gtk_source_space_drawer_set_types_for_locations (drawer, GTK_SOURCE_SPACE_LOCATION_ALL,
GTK_SOURCE_SPACE_TYPE_NONE);
-
- if (flags & 1)
- type_flags |= GTK_SOURCE_SPACE_TYPE_SPACE;
-
- if (flags & 2)
- type_flags |= GTK_SOURCE_SPACE_TYPE_TAB;
-
- if (flags & 4)
+ else
{
- gtk_source_space_drawer_set_types_for_locations (drawer, GTK_SOURCE_SPACE_LOCATION_ALL,
GTK_SOURCE_SPACE_TYPE_NEWLINE);
- type_flags |= GTK_SOURCE_SPACE_TYPE_NEWLINE;
+ if (!self->completion_blocked)
+ {
+ self->completion_blocked = TRUE;
+ gtk_source_completion_block_interactive (completion);
+ }
}
-
- if (flags & 8)
- type_flags |= GTK_SOURCE_SPACE_TYPE_NBSP;
-
- if (flags & 16)
- location_flags |= GTK_SOURCE_SPACE_LOCATION_LEADING;
-
- if (flags & 32)
- location_flags |= GTK_SOURCE_SPACE_LOCATION_INSIDE_TEXT;
-
- if (flags & 64)
- location_flags |= GTK_SOURCE_SPACE_LOCATION_TRAILING;
-
- if (type_flags > 0 && location_flags == 0)
- location_flags |= GTK_SOURCE_SPACE_LOCATION_ALL;
-
- gtk_source_space_drawer_set_enable_matrix (drawer, TRUE);
- gtk_source_space_drawer_set_types_for_locations (drawer, location_flags, type_flags);
}
void
-_ide_editor_page_init_settings (IdeEditorPage *self)
+_ide_editor_page_settings_init (IdeEditorPage *self)
{
- IdeSourceView *source_view;
- IdeBuffer *buffer;
-
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (self->editor_settings == NULL);
- g_assert (self->insight_settings == NULL);
-
- source_view = ide_editor_page_get_view (self);
- buffer = ide_editor_page_get_buffer (self);
-
- self->editor_settings = g_settings_new ("org.gnome.builder.editor");
-
- g_settings_bind (self->editor_settings, "highlight-current-line",
- source_view, "highlight-current-line",
+ GtkSourceCompletion *completion;
+
+ IDE_ENTRY;
+
+ g_return_if_fail (IDE_IS_MAIN_THREAD ());
+ g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
+ g_return_if_fail (IDE_IS_SOURCE_VIEW (self->view));
+ g_return_if_fail (IDE_IS_BUFFER (self->buffer));
+ g_return_if_fail (self->buffer_file_settings == NULL);
+ g_return_if_fail (self->view_file_settings == NULL);
+
+ if (editor_settings == NULL)
+ editor_settings = g_settings_new ("org.gnome.builder.editor");
+
+ g_object_bind_property (IDE_APPLICATION_DEFAULT, "style-scheme",
+ self->buffer, "style-scheme-name",
+ G_BINDING_SYNC_CREATE);
+
+ self->buffer_file_settings = ide_binding_group_new ();
+ ide_binding_group_bind (self->buffer_file_settings,
+ "insert-trailing-newline", self->buffer, "implicit-trailing-newline",
+ G_BINDING_SYNC_CREATE);
+
+ self->view_file_settings = ide_binding_group_new ();
+ ide_binding_group_bind (self->view_file_settings,
+ "auto-indent", self->view, "auto-indent",
+ G_BINDING_SYNC_CREATE);
+ ide_binding_group_bind_full (self->view_file_settings,
+ "indent-style", self->view, "insert-spaces-instead-of-tabs",
+ G_BINDING_SYNC_CREATE,
+ indent_style_to_insert_spaces, NULL, NULL, NULL);
+ ide_binding_group_bind (self->view_file_settings,
+ "indent-width", self->view, "indent-width",
+ G_BINDING_SYNC_CREATE);
+ ide_binding_group_bind (self->view_file_settings,
+ "right-margin-position", self->view, "right-margin-position",
+ G_BINDING_SYNC_CREATE);
+ ide_binding_group_bind (self->view_file_settings,
+ "show-right-margin", self->view, "show-right-margin",
+ G_BINDING_SYNC_CREATE);
+ ide_binding_group_bind (self->view_file_settings,
+ "tab-width", self->view, "tab-width",
+ G_BINDING_SYNC_CREATE);
+
+ g_settings_bind (editor_settings, "show-map",
+ self->map_revealer, "reveal-child",
G_SETTINGS_BIND_GET);
-
- g_settings_bind (self->editor_settings, "highlight-matching-brackets",
- buffer, "highlight-matching-brackets",
+ g_settings_bind (editor_settings, "highlight-current-line",
+ self->view, "highlight-current-line",
G_SETTINGS_BIND_GET);
-
- g_settings_bind (self->editor_settings, "show-line-changes",
- source_view, "show-line-changes",
- G_SETTINGS_BIND_GET);
-
- g_settings_bind (self->editor_settings, "show-line-diagnostics",
- source_view, "show-line-diagnostics",
- G_SETTINGS_BIND_GET);
-
- g_settings_bind (self->editor_settings, "show-line-numbers",
- source_view, "show-line-numbers",
- G_SETTINGS_BIND_GET);
-
- g_settings_bind (self->editor_settings, "show-relative-line-numbers",
- source_view, "show-relative-line-numbers",
+ g_settings_bind_with_mapping (editor_settings, "show-map",
+ self->scroller, "vscrollbar-policy",
+ G_SETTINGS_BIND_GET,
+ show_map_to_vscrollbar_policy,
+ NULL, NULL, NULL);
+ g_settings_bind_with_mapping (editor_settings, "show-grid-lines",
+ self->view, "background-pattern",
+ G_SETTINGS_BIND_GET,
+ grid_lines_to_background_pattern,
+ NULL, NULL, NULL);
+ g_settings_bind (editor_settings, "enable-snippets",
+ self->view, "enable-snippets",
G_SETTINGS_BIND_GET);
-
- g_settings_bind (self->editor_settings, "smart-backspace",
- source_view, "smart-backspace",
+ g_settings_bind (editor_settings, "line-height",
+ self->view, "line-height",
G_SETTINGS_BIND_GET);
- g_settings_bind_with_mapping (self->editor_settings, "smart-home-end",
- source_view, "smart-home-end",
+ g_settings_bind_with_mapping (editor_settings, "font-name",
+ self->view, "font-desc",
G_SETTINGS_BIND_GET,
- get_smart_home_end, NULL, NULL, NULL);
+ font_name_to_font_desc,
+ NULL, NULL, NULL);
- g_settings_bind (self->editor_settings, "style-scheme-name",
- buffer, "style-scheme-name",
+ completion = gtk_source_view_get_completion (GTK_SOURCE_VIEW (self->view));
+ g_settings_bind (editor_settings, "select-first-completion",
+ completion, "select-on-show",
G_SETTINGS_BIND_GET);
- g_settings_bind (self->editor_settings, "font-name",
- source_view, "font-name",
- G_SETTINGS_BIND_GET);
+#if 0
+ ide_binding_group_bind (self->view_file_settings,
+ "insert-matching-brace", self->view, "insert-matching-brace",
+ G_BINDING_SYNC_CREATE);
+ ide_binding_group_bind (self->view_file_settings,
+ "overwrite-braces", self->view, "overwrite-braces",
+ G_BINDING_SYNC_CREATE);
+#endif
+
+ g_signal_connect_object (editor_settings,
+ "changed::interactive-completion",
+ G_CALLBACK (notify_interactive_completion_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ notify_interactive_completion_cb (self, NULL, editor_settings);
- g_settings_bind (self->editor_settings, "overscroll",
- source_view, "overscroll",
- G_SETTINGS_BIND_GET);
+ _ide_editor_page_settings_reload (self);
- g_settings_bind (self->editor_settings, "scroll-offset",
- source_view, "scroll-offset",
- G_SETTINGS_BIND_GET);
+ IDE_EXIT;
+}
- g_settings_bind (self->editor_settings, "show-grid-lines",
- source_view, "show-grid-lines",
- G_SETTINGS_BIND_GET);
+void
+_ide_editor_page_settings_connect_gutter (IdeEditorPage *self,
+ IdeGutter *gutter)
+{
+ IDE_ENTRY;
- g_settings_bind_with_mapping (self->editor_settings, "wrap-text",
- source_view, "wrap-mode",
- G_SETTINGS_BIND_GET,
- get_wrap_mode, NULL, NULL, NULL);
+ g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
+ g_return_if_fail (IDE_IS_GUTTER (gutter));
- g_settings_bind (self->editor_settings, "completion-n-rows",
- source_view, "completion-n-rows",
+ g_settings_bind (editor_settings, "show-line-numbers",
+ gutter, "show-line-numbers",
G_SETTINGS_BIND_GET);
-
- g_settings_bind (self->editor_settings, "interactive-completion",
- source_view, "interactive-completion",
+ g_settings_bind (editor_settings, "show-line-changes",
+ gutter, "show-line-changes",
G_SETTINGS_BIND_GET);
-
- g_settings_bind (self->editor_settings, "show-map",
- self, "show-map",
+ g_settings_bind (editor_settings, "show-relative-line-numbers",
+ gutter, "show-relative-line-numbers",
G_SETTINGS_BIND_GET);
-
- g_settings_bind (self->editor_settings, "auto-hide-map",
- self, "auto-hide-map",
+ g_settings_bind (editor_settings, "show-line-diagnostics",
+ gutter, "show-line-diagnostics",
G_SETTINGS_BIND_GET);
- g_signal_connect_object (self->editor_settings,
- "changed::keybindings",
- G_CALLBACK (on_keybindings_changed),
- self,
- G_CONNECT_SWAPPED);
+ IDE_EXIT;
+}
- on_keybindings_changed (self, "keybindings", self->editor_settings);
+void
+_ide_editor_page_settings_disconnect_gutter (IdeEditorPage *self,
+ IdeGutter *gutter)
+{
+ IDE_ENTRY;
- g_signal_connect_object (self->editor_settings,
- "changed::draw-spaces",
- G_CALLBACK (on_draw_spaces_changed),
- self,
- G_CONNECT_SWAPPED);
+ g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
+ g_return_if_fail (IDE_IS_GUTTER (gutter));
- on_draw_spaces_changed (self, "draw-spaces", self->editor_settings);
+ g_settings_unbind (gutter, "show-line-changes");
+ g_settings_unbind (gutter, "show-line-numbers");
+ g_settings_unbind (gutter, "show-relative-line-numbers");
+ g_settings_unbind (gutter, "show-line-diagnostics");
- self->insight_settings = g_settings_new ("org.gnome.builder.code-insight");
+ IDE_EXIT;
}
diff --git a/src/libide/editor/ide-editor-page.c b/src/libide/editor/ide-editor-page.c
index 38b315097..1483956e8 100644
--- a/src/libide/editor/ide-editor-page.c
+++ b/src/libide/editor/ide-editor-page.c
@@ -1,6 +1,6 @@
/* ide-editor-page.c
*
- * Copyright 2017-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2017-2022 Christian Hergert <chergert redhat com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,366 +22,175 @@
#include "config.h"
-#include <dazzle.h>
-#include <libpeas/peas.h>
-#include <gtksourceview/gtksource.h>
-#include <pango/pangofc-fontmap.h>
+#include <glib/gi18n.h>
-#include "ide-editor-page.h"
-#include "ide-editor-page-addin.h"
-#include "ide-editor-private.h"
-#include "ide-line-change-gutter-renderer.h"
+#include <libide-code.h>
+#include <libide-threading.h>
-#define AUTO_HIDE_TIMEOUT_SECONDS 5
+#include "ide-editor-page-addin.h"
+#include "ide-editor-page-private.h"
enum {
PROP_0,
- PROP_AUTO_HIDE_MAP,
PROP_BUFFER,
- PROP_BUFFER_FILE,
- PROP_SEARCH,
- PROP_SHOW_MAP,
+ PROP_GUTTER,
PROP_VIEW,
N_PROPS
};
-static void ide_editor_page_update_reveal_timer (IdeEditorPage *self);
-
-G_DEFINE_FINAL_TYPE (IdeEditorPage, ide_editor_page, IDE_TYPE_PAGE)
-
-DZL_DEFINE_COUNTER (instances, "Editor", "N Views", "Number of editor views");
+G_DEFINE_TYPE (IdeEditorPage, ide_editor_page, IDE_TYPE_PAGE)
static GParamSpec *properties [N_PROPS];
-static FcConfig *localFontConfig;
-
-static void
-ide_editor_page_load_fonts (IdeEditorPage *self)
-{
- PangoFontMap *font_map;
- PangoFontDescription *font_desc;
-
- if (g_once_init_enter (&localFontConfig))
- {
- const gchar *font_path = PACKAGE_DATADIR "/gnome-builder/fonts/BuilderBlocks.ttf";
- FcConfig *config = FcInitLoadConfigAndFonts ();
-
- if (g_getenv ("GB_IN_TREE_FONTS") != NULL)
- font_path = "data/fonts/BuilderBlocks.ttf";
-
- if (!g_file_test (font_path, G_FILE_TEST_IS_REGULAR))
- g_warning ("Failed to locate \"%s\"", font_path);
-
- FcConfigAppFontAddFile (config, (const FcChar8 *)font_path);
-
- g_once_init_leave (&localFontConfig, config);
- }
-
- font_map = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT);
- pango_fc_font_map_set_config (PANGO_FC_FONT_MAP (font_map), localFontConfig);
- gtk_widget_set_font_map (GTK_WIDGET (self->map), font_map);
- font_desc = pango_font_description_from_string ("BuilderBlocks");
- pango_font_description_set_absolute_size (font_desc, (96.0/72.0) * 2 * PANGO_SCALE);
-
- g_assert (localFontConfig != NULL);
- g_assert (font_map != NULL);
- g_assert (font_desc != NULL);
-
- g_object_set (self->map, "font-desc", font_desc, NULL);
-
- pango_font_description_free (font_desc);
- g_object_unref (font_map);
-}
static void
-ide_editor_page_update_icon (IdeEditorPage *self)
+ide_editor_page_query_file_info_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- g_autofree gchar *name = NULL;
- g_autofree gchar *content_type = NULL;
- g_autofree gchar *sniff = NULL;
+ GFile *file = (GFile *)object;
+ g_autoptr(IdeEditorPage) self = user_data;
+ g_autoptr(GFileInfo) info = NULL;
g_autoptr(GIcon) icon = NULL;
- GtkTextIter begin, end;
- GFile *file;
+ const char *content_type;
+ const char *name;
+ g_assert (G_IS_FILE (file));
+ g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (IDE_IS_BUFFER (self->buffer));
-
- /* Get first 1024 bytes to help determine content type */
- gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (self->buffer), &begin, &end);
- if (gtk_text_iter_get_offset (&end) > 1024)
- gtk_text_iter_set_offset (&end, 1024);
- sniff = gtk_text_iter_get_slice (&begin, &end);
- /* Now get basename for content type */
- file = ide_buffer_get_file (self->buffer);
- name = g_file_get_basename (file);
-
- /* Guess content type */
- content_type = g_content_type_guess (name, (const guchar *)sniff, strlen (sniff), NULL);
+ if (!(info = g_file_query_info_finish (file, result, NULL)))
+ return;
- /* Update icon to match guess */
+ content_type = g_file_info_get_content_type (info);
+ name = g_file_info_get_name (info);
icon = ide_g_content_type_get_symbolic_icon (content_type, name);
- ide_page_set_icon (IDE_PAGE (self), icon);
-}
-
-static void
-ide_editor_page_buffer_notify_failed (IdeEditorPage *self,
- GParamSpec *pspec,
- IdeBuffer *buffer)
-{
- gboolean failed;
-
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (IDE_IS_BUFFER (buffer));
-
- failed = ide_buffer_get_failed (buffer);
-
- ide_page_set_failed (IDE_PAGE (self), failed);
-}
-
-static void
-ide_editor_page_stop_search (IdeEditorPage *self,
- IdeEditorSearchBar *search_bar)
-{
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (IDE_IS_EDITOR_SEARCH_BAR (search_bar));
- gtk_revealer_set_reveal_child (self->search_revealer, FALSE);
- gtk_widget_grab_focus (GTK_WIDGET (self->source_view));
+ panel_widget_set_icon (PANEL_WIDGET (self), icon);
}
static void
-ide_editor_page_notify_child_revealed (IdeEditorPage *self,
- GParamSpec *pspec,
- GtkRevealer *revealer)
-{
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (GTK_IS_REVEALER (revealer));
-
- if (gtk_revealer_get_child_revealed (revealer))
- {
- GtkWidget *toplevel = gtk_widget_get_ancestor (GTK_WIDGET (revealer), GTK_TYPE_WINDOW);
- GtkWidget *focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
-
- /* Only focus the search bar if it doesn't already have focus,
- * as it can reselect the search text.
- */
- if (focus == NULL || !gtk_widget_is_ancestor (focus, GTK_WIDGET (revealer)))
- gtk_widget_grab_focus (GTK_WIDGET (self->search_bar));
- }
-}
-
-static gboolean
-ide_editor_page_focus_in_event (IdeEditorPage *self,
- GdkEventFocus *focus,
- IdeSourceView *source_view)
+ide_editor_page_notify_file_cb (IdeEditorPage *self,
+ GParamSpec *pspec,
+ IdeBuffer *buffer)
{
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (IDE_IS_SOURCE_VIEW (source_view));
-
- ide_page_mark_used (IDE_PAGE (self));
-
- return GDK_EVENT_PROPAGATE;
-}
+ GFile *file;
-static void
-ide_editor_page_buffer_loaded (IdeEditorPage *self,
- IdeBuffer *buffer)
-{
g_assert (IDE_IS_EDITOR_PAGE (self));
g_assert (IDE_IS_BUFFER (buffer));
- ide_editor_page_update_icon (self);
+ file = ide_buffer_get_file (buffer);
- /* Scroll to the insertion location once the buffer
- * has loaded. This is useful if it is not onscreen.
- */
- ide_source_view_scroll_to_insert (self->source_view);
+ g_file_query_info_async (file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME","
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ ide_editor_page_query_file_info_cb,
+ g_object_ref (self));
}
static void
-ide_editor_page_buffer_modified_changed (IdeEditorPage *self,
- IdeBuffer *buffer)
+ide_editor_page_modified_changed_cb (IdeEditorPage *self,
+ IdeBuffer *buffer)
{
- gboolean modified = FALSE;
+ IDE_ENTRY;
g_assert (IDE_IS_EDITOR_PAGE (self));
g_assert (IDE_IS_BUFFER (buffer));
- if (!ide_buffer_get_loading (buffer))
- modified = gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (buffer));
-
- ide_page_set_modified (IDE_PAGE (self), modified);
-}
-
-static void
-ide_editor_page_buffer_notify_language_cb (IdeExtensionSetAdapter *set,
- PeasPluginInfo *plugin_info,
- PeasExtension *exten,
- gpointer user_data)
-{
- const gchar *language_id = user_data;
-
- g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
- g_assert (plugin_info != NULL);
- g_assert (IDE_IS_EDITOR_PAGE_ADDIN (exten));
+ panel_widget_set_modified (PANEL_WIDGET (self),
+ gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (buffer)));
- ide_editor_page_addin_language_changed (IDE_EDITOR_PAGE_ADDIN (exten), language_id);
+ IDE_EXIT;
}
static void
-ide_editor_page_buffer_notify_language (IdeEditorPage *self,
- GParamSpec *pspec,
- IdeBuffer *buffer)
+ide_editor_page_style_scheme_changed_cb (IdeEditorPage *self,
+ GParamSpec *pspec,
+ IdeBuffer *buffer)
{
- const gchar *lang_id = NULL;
-
g_assert (IDE_IS_EDITOR_PAGE (self));
g_assert (IDE_IS_BUFFER (buffer));
- if (self->addins == NULL)
- return;
-
- lang_id = ide_buffer_get_language_id (buffer);
-
- /* Update extensions that change based on language */
- ide_extension_set_adapter_set_value (self->addins, lang_id);
- ide_extension_set_adapter_foreach (self->addins,
- ide_editor_page_buffer_notify_language_cb,
- (gpointer)lang_id);
-
- ide_editor_page_update_icon (self);
+ if (self->gutter != NULL)
+ ide_gutter_style_changed (self->gutter);
}
static void
-ide_editor_page_buffer_notify_style_scheme (IdeEditorPage *self,
- GParamSpec *pspec,
- IdeBuffer *buffer)
+ide_editor_page_set_buffer (IdeEditorPage *self,
+ IdeBuffer *buffer)
{
- g_autofree gchar *background = NULL;
- g_autofree gchar *foreground = NULL;
- GtkSourceStyleScheme *scheme;
- GtkSourceStyle *style;
- gboolean background_set = FALSE;
- gboolean foreground_set = FALSE;
- GdkRGBA rgba;
-
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (IDE_IS_BUFFER (buffer));
-
- if (NULL == (scheme = gtk_source_buffer_get_style_scheme (GTK_SOURCE_BUFFER (buffer))) ||
- NULL == (style = gtk_source_style_scheme_get_style (scheme, "text")))
- goto unset_primary_color;
-
- g_object_get (style,
- "background-set", &background_set,
- "background", &background,
- "foreground-set", &foreground_set,
- "foreground", &foreground,
- NULL);
-
- if (!background_set || background == NULL || !gdk_rgba_parse (&rgba, background))
- goto unset_primary_color;
-
- if (background_set && background != NULL && gdk_rgba_parse (&rgba, background))
- ide_page_set_primary_color_bg (IDE_PAGE (self), &rgba);
- else
- goto unset_primary_color;
-
- if (foreground_set && foreground != NULL && gdk_rgba_parse (&rgba, foreground))
- ide_page_set_primary_color_fg (IDE_PAGE (self), &rgba);
- else
- ide_page_set_primary_color_fg (IDE_PAGE (self), NULL);
-
- return;
-
-unset_primary_color:
- ide_page_set_primary_color_bg (IDE_PAGE (self), NULL);
- ide_page_set_primary_color_fg (IDE_PAGE (self), NULL);
-}
+ IDE_ENTRY;
-static void
-ide_editor_page__buffer_notify_changed_on_volume (IdeEditorPage *self,
- GParamSpec *pspec,
- IdeBuffer *buffer)
-{
g_assert (IDE_IS_EDITOR_PAGE (self));
g_assert (IDE_IS_BUFFER (buffer));
- gtk_revealer_set_reveal_child (self->modified_revealer,
- ide_buffer_get_changed_on_volume (buffer));
-}
-
-static void
-ide_editor_page_hide_reload_bar (IdeEditorPage *self,
- GtkWidget *button)
-{
- g_assert (IDE_IS_EDITOR_PAGE (self));
+ if (g_set_object (&self->buffer, buffer))
+ {
+ ide_buffer_hold (buffer);
+
+ gtk_text_view_set_buffer (GTK_TEXT_VIEW (self->view), GTK_TEXT_BUFFER (buffer));
+
+ g_signal_connect_object (buffer,
+ "modified-changed",
+ G_CALLBACK (ide_editor_page_modified_changed_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ g_signal_connect_object (buffer,
+ "notify::file",
+ G_CALLBACK (ide_editor_page_notify_file_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ g_signal_connect_object (buffer,
+ "notify::file-settings",
+ G_CALLBACK (_ide_editor_page_settings_reload),
+ self,
+ G_CONNECT_SWAPPED);
+
+ g_signal_connect_object (buffer,
+ "notify::style-scheme",
+ G_CALLBACK (ide_editor_page_style_scheme_changed_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ g_object_bind_property (buffer, "title",
+ self, "title",
+ G_BINDING_SYNC_CREATE);
+
+ ide_editor_page_notify_file_cb (self, NULL, buffer);
+ ide_editor_page_modified_changed_cb (self, buffer);
+ _ide_editor_page_settings_init (self);
+ }
- gtk_revealer_set_reveal_child (self->modified_revealer, FALSE);
+ IDE_EXIT;
}
static gboolean
-ide_editor_page_source_view_event (IdeEditorPage *self,
- GdkEvent *event,
- IdeSourceView *source_view)
+ide_editor_page_grab_focus (GtkWidget *widget)
{
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (event != NULL);
- g_assert (IDE_IS_SOURCE_VIEW (source_view) || GTK_SOURCE_IS_MAP (source_view));
-
- if (self->auto_hide_map)
- {
- ide_editor_page_update_reveal_timer (self);
- gtk_revealer_set_reveal_child (self->map_revealer, TRUE);
- }
-
- return GDK_EVENT_PROPAGATE;
+ return gtk_widget_grab_focus (GTK_WIDGET (IDE_EDITOR_PAGE (widget)->view));
}
static void
-ide_editor_page_bind_signals (IdeEditorPage *self,
- IdeBuffer *buffer,
- DzlSignalGroup *buffer_signals)
+ide_editor_page_focus_enter_cb (IdeEditorPage *self,
+ GtkEventControllerFocus *controller)
{
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (IDE_IS_BUFFER (buffer));
- g_assert (DZL_IS_SIGNAL_GROUP (buffer_signals));
+ g_autofree char *title = NULL;
- ide_editor_page_buffer_modified_changed (self, buffer);
- ide_editor_page_buffer_notify_language (self, NULL, buffer);
- ide_editor_page_buffer_notify_style_scheme (self, NULL, buffer);
- ide_editor_page_buffer_notify_failed (self, NULL, buffer);
-}
+ IDE_ENTRY;
-static void
-ide_editor_page_set_buffer (IdeEditorPage *self,
- IdeBuffer *buffer)
-{
g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (!buffer || IDE_IS_BUFFER (buffer));
-
- if (g_set_object (&self->buffer, buffer))
- {
- dzl_signal_group_set_target (self->buffer_signals, buffer);
- dzl_binding_group_set_source (self->buffer_bindings, buffer);
- gtk_text_view_set_buffer (GTK_TEXT_VIEW (self->source_view),
- GTK_TEXT_BUFFER (buffer));
- gtk_drag_dest_unset (GTK_WIDGET (self->source_view));
- ide_editor_page_update_icon (self);
- }
-}
+ g_assert (GTK_IS_EVENT_CONTROLLER_FOCUS (controller));
-static IdePage *
-ide_editor_page_create_split (IdePage *view)
-{
- IdeEditorPage *self = (IdeEditorPage *)view;
+ title = ide_buffer_dup_title (self->buffer);
+ g_debug ("Keyboard focus entered page \"%s\"", title);
- g_assert (IDE_IS_EDITOR_PAGE (self));
+ ide_page_mark_used (IDE_PAGE (self));
- return g_object_new (IDE_TYPE_EDITOR_PAGE,
- "buffer", self->buffer,
- "visible", TRUE,
- NULL);
+ IDE_EXIT;
}
static void
@@ -416,18 +225,6 @@ ide_editor_page_addin_added (IdeExtensionSetAdapter *set,
g_assert (IDE_IS_EDITOR_PAGE (self));
ide_editor_page_addin_load (addin, self);
-
- /*
- * Notify of the current frame, but refetch the frame pointer just
- * to be sure we aren't re-using an old pointer in case we're racing
- * with a finalizer.
- */
- if (self->last_frame_ptr != NULL)
- {
- GtkWidget *frame = gtk_widget_get_ancestor (GTK_WIDGET (self), IDE_TYPE_FRAME);
- if (frame != NULL)
- ide_editor_page_addin_frame_set (addin, IDE_FRAME (frame));
- }
}
static void
@@ -448,39 +245,26 @@ ide_editor_page_addin_removed (IdeExtensionSetAdapter *set,
}
static void
-ide_editor_page_hierarchy_changed (GtkWidget *widget,
- GtkWidget *old_toplevel)
+ide_editor_page_root (GtkWidget *widget)
{
IdeEditorPage *self = (IdeEditorPage *)widget;
- IdeFrame *frame;
IdeContext *context;
+ GtkWidget *frame;
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (!old_toplevel || GTK_IS_WIDGET (old_toplevel));
+ IDE_ENTRY;
- /*
- * We don't need to chain up today, but if IdePage starts
- * using the hierarchy_changed signal to handle anything, we want
- * to make sure we aren't surprised.
- */
- if (GTK_WIDGET_CLASS (ide_editor_page_parent_class)->hierarchy_changed)
- GTK_WIDGET_CLASS (ide_editor_page_parent_class)->hierarchy_changed (widget, old_toplevel);
+ GTK_WIDGET_CLASS (ide_editor_page_parent_class)->root (widget);
- context = ide_widget_get_context (GTK_WIDGET (self));
- frame = (IdeFrame *)gtk_widget_get_ancestor (widget, IDE_TYPE_FRAME);
+ context = ide_widget_get_context (widget);
+ frame = gtk_widget_get_ancestor (widget, IDE_TYPE_FRAME);
- /*
- * We don't want to create addins until the widget has been placed into
- * the widget tree. That way the addins can get access to the context
- * or other useful details.
- */
- if (context != NULL && self->addins == NULL)
+ if (self->addins == NULL && context != NULL)
{
self->addins = ide_extension_set_adapter_new (IDE_OBJECT (context),
peas_engine_get_default (),
IDE_TYPE_EDITOR_PAGE_ADDIN,
"Editor-Page-Languages",
- ide_editor_page_get_language_id (self));
+ ide_buffer_get_language_id (self->buffer));
g_signal_connect (self->addins,
"extension-added",
@@ -497,361 +281,65 @@ ide_editor_page_hierarchy_changed (GtkWidget *widget,
self);
}
- /*
- * If we have been moved into a new frame, notify the addins of the
- * hierarchy change.
- */
- if (frame != NULL && frame != self->last_frame_ptr && self->addins != NULL)
- {
- self->last_frame_ptr = frame;
- ide_extension_set_adapter_foreach (self->addins,
- ide_editor_page_notify_frame_set,
- frame);
- }
-}
-
-static void
-ide_editor_page_update_map (IdeEditorPage *self)
-{
- GtkWidget *parent;
-
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- parent = gtk_widget_get_parent (GTK_WIDGET (self->map));
-
- g_object_ref (self->map);
-
- gtk_container_remove (GTK_CONTAINER (parent), GTK_WIDGET (self->map));
-
- if (self->auto_hide_map)
- gtk_container_add (GTK_CONTAINER (self->map_revealer), GTK_WIDGET (self->map));
- else
- gtk_container_add (GTK_CONTAINER (self->scroller_box), GTK_WIDGET (self->map));
-
- gtk_widget_set_visible (GTK_WIDGET (self->map_revealer), self->show_map && self->auto_hide_map);
- gtk_widget_set_visible (GTK_WIDGET (self->map), self->show_map);
- gtk_revealer_set_reveal_child (self->map_revealer, self->show_map);
-
- ide_editor_page_update_reveal_timer (self);
-
- g_object_unref (self->map);
-}
-
-static void
-ide_editor_page_buffer_notify_file (IdeEditorPage *self,
- GParamSpec *pspec,
- gpointer user_data)
-{
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
-
-}
-
-static void
-search_revealer_notify_reveal_child (IdeEditorPage *self,
- GParamSpec *pspec,
- GtkRevealer *revealer)
-{
- IdeCompletion *completion;
-
- g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
- g_return_if_fail (pspec != NULL);
- g_return_if_fail (GTK_IS_REVEALER (revealer));
-
- completion = ide_source_view_get_completion (IDE_SOURCE_VIEW (self->source_view));
-
- if (!gtk_revealer_get_reveal_child (revealer))
- {
- ide_editor_search_end_interactive (self->search);
-
- /* Restore completion that we blocked below. */
- ide_completion_unblock_interactive (completion);
- }
- else
- {
- ide_editor_search_begin_interactive (self->search);
-
- /*
- * Block the completion while the search bar is set. It only
- * slows things down like replace functionality. We'll
- * restore it above when we clear state.
- */
- ide_completion_block_interactive (completion);
- }
-}
-
-static void
-ide_editor_page_focus_location (IdeEditorPage *self,
- IdeLocation *location,
- IdeSourceView *source_view)
-{
- GtkWidget *editor;
-
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (location != NULL);
- g_assert (IDE_IS_SOURCE_VIEW (source_view));
+ if (self->addins != NULL && frame != NULL)
+ ide_extension_set_adapter_foreach (self->addins,
+ ide_editor_page_notify_frame_set,
+ frame);
- editor = gtk_widget_get_ancestor (GTK_WIDGET (self), IDE_TYPE_EDITOR_SURFACE);
- ide_editor_surface_focus_location (IDE_EDITOR_SURFACE (editor), location);
+ IDE_EXIT;
}
-static void
-ide_editor_page_clear_search (IdeEditorPage *self,
- IdeSourceView *view)
+static IdePage *
+ide_editor_page_create_split (IdePage *page)
{
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (IDE_IS_EDITOR_SEARCH (self->search));
- g_assert (IDE_IS_SOURCE_VIEW (view));
-
- ide_editor_search_set_search_text (self->search, NULL);
- ide_editor_search_set_visible (self->search, FALSE);
- gtk_revealer_set_reveal_child (self->search_revealer, FALSE);
-}
+ IdeEditorPage *self = (IdeEditorPage *)page;
+ GtkWidget *ret;
-static void
-ide_editor_page_move_search (IdeEditorPage *self,
- GtkDirectionType dir,
- gboolean extend_selection,
- gboolean select_match,
- gboolean exclusive,
- gboolean apply_count,
- gboolean at_word_boundaries,
- IdeSourceView *view)
-{
- IdeEditorSearchSelect sel = 0;
+ IDE_ENTRY;
g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (IDE_IS_EDITOR_SEARCH (self->search));
- g_assert (IDE_IS_SOURCE_VIEW (view));
-
- if (extend_selection && select_match)
- sel = IDE_EDITOR_SEARCH_SELECT_WITH_RESULT;
- else if (extend_selection)
- sel = IDE_EDITOR_SEARCH_SELECT_TO_RESULT;
-
- ide_editor_search_set_extend_selection (self->search, sel);
- ide_editor_search_set_visible (self->search, TRUE);
-
- if (apply_count)
- {
- ide_editor_search_set_repeat (self->search, ide_source_view_get_count (view));
- g_signal_emit_by_name (view, "clear-count");
- }
-
- ide_editor_search_set_at_word_boundaries (self->search, at_word_boundaries);
-
- switch (dir)
- {
- case GTK_DIR_DOWN:
- case GTK_DIR_RIGHT:
- ide_editor_search_set_reverse (self->search, FALSE);
- ide_editor_search_move (self->search, IDE_EDITOR_SEARCH_NEXT);
- break;
-
- case GTK_DIR_TAB_FORWARD:
- if (extend_selection)
- ide_editor_search_move (self->search, IDE_EDITOR_SEARCH_FORWARD);
- else
- ide_editor_search_move (self->search, IDE_EDITOR_SEARCH_NEXT);
- break;
- case GTK_DIR_UP:
- case GTK_DIR_LEFT:
- ide_editor_search_set_reverse (self->search, TRUE);
- ide_editor_search_move (self->search, IDE_EDITOR_SEARCH_NEXT);
- break;
-
- case GTK_DIR_TAB_BACKWARD:
- if (extend_selection)
- ide_editor_search_move (self->search, IDE_EDITOR_SEARCH_BACKWARD);
- else
- ide_editor_search_move (self->search, IDE_EDITOR_SEARCH_PREVIOUS);
- break;
+ ret = ide_editor_page_new (self->buffer);
- default:
- break;
- }
+ IDE_RETURN (IDE_PAGE (ret));
}
-static void
-ide_editor_page_set_search_text (IdeEditorPage *self,
- const gchar *search_text,
- gboolean from_selection,
- IdeSourceView *view)
+static GFile *
+ide_editor_page_get_file_or_directory (IdePage *page)
{
- g_autofree gchar *freeme = NULL;
- GtkTextIter begin;
- GtkTextIter end;
+ GFile *ret;
- g_assert (IDE_IS_EDITOR_PAGE (self));
- g_assert (IDE_IS_EDITOR_SEARCH (self->search));
- g_assert (search_text != NULL || from_selection);
- g_assert (IDE_IS_SOURCE_VIEW (view));
+ IDE_ENTRY;
- /* Use interactive mode if we're copying from the clipboard, because that
- * is usually going to be followed by focusing the search box and we want
- * to make sure the occurrance count is updated.
- */
+ g_assert (IDE_IS_EDITOR_PAGE (page));
- if (from_selection)
- ide_editor_search_begin_interactive (self->search);
-
- if (from_selection)
- {
- if (gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (self->buffer), &begin, &end))
- search_text = freeme = gtk_text_iter_get_slice (&begin, &end);
- }
+ ret = ide_buffer_get_file (IDE_EDITOR_PAGE (page)->buffer);
- ide_editor_search_set_search_text (self->search, search_text);
- ide_editor_search_set_regex_enabled (self->search, FALSE);
+ if (ret != NULL)
+ g_object_ref (ret);
- if (from_selection)
- ide_editor_search_end_interactive (self->search);
+ IDE_RETURN (ret);
}
static void
-ide_editor_page_constructed (GObject *object)
+ide_editor_page_dispose (GObject *object)
{
IdeEditorPage *self = (IdeEditorPage *)object;
- GtkSourceGutterRenderer *renderer;
- GtkSourceGutter *gutter;
-
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- G_OBJECT_CLASS (ide_editor_page_parent_class)->constructed (object);
-
- gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (self->map), GTK_TEXT_WINDOW_LEFT);
- renderer = g_object_new (IDE_TYPE_LINE_CHANGE_GUTTER_RENDERER,
- "size", 1,
- "visible", TRUE,
- NULL);
- gtk_source_gutter_insert (gutter, renderer, 0);
-
- _ide_editor_page_init_actions (self);
- _ide_editor_page_init_shortcuts (self);
- _ide_editor_page_init_settings (self);
-
- g_signal_connect_swapped (self->source_view,
- "focus-in-event",
- G_CALLBACK (ide_editor_page_focus_in_event),
- self);
-
- g_signal_connect_swapped (self->source_view,
- "motion-notify-event",
- G_CALLBACK (ide_editor_page_source_view_event),
- self);
-
- g_signal_connect_swapped (self->source_view,
- "scroll-event",
- G_CALLBACK (ide_editor_page_source_view_event),
- self);
-
- g_signal_connect_swapped (self->source_view,
- "focus-location",
- G_CALLBACK (ide_editor_page_focus_location),
- self);
-
- g_signal_connect_swapped (self->source_view,
- "set-search-text",
- G_CALLBACK (ide_editor_page_set_search_text),
- self);
-
- g_signal_connect_swapped (self->source_view,
- "clear-search",
- G_CALLBACK (ide_editor_page_clear_search),
- self);
-
- g_signal_connect_swapped (self->source_view,
- "move-search",
- G_CALLBACK (ide_editor_page_move_search),
- self);
-
- g_signal_connect_swapped (self->map,
- "motion-notify-event",
- G_CALLBACK (ide_editor_page_source_view_event),
- self);
-
-
-
- /*
- * We want to track when the search revealer is visible. We will discard
- * the search context when the revealer is not visible so that we don't
- * continue performing expensive buffer operations.
- */
- g_signal_connect_swapped (self->search_revealer,
- "notify::reveal-child",
- G_CALLBACK (search_revealer_notify_reveal_child),
- self);
-
- self->search = ide_editor_search_new (GTK_SOURCE_VIEW (self->source_view));
- ide_editor_search_bar_set_search (self->search_bar, self->search);
- gtk_widget_insert_action_group (GTK_WIDGET (self), "editor-search",
- G_ACTION_GROUP (self->search));
-
- ide_editor_page_load_fonts (self);
- ide_editor_page_update_map (self);
-}
-
-static void
-ide_editor_page_destroy (GtkWidget *widget)
-{
- IdeEditorPage *self = (IdeEditorPage *)widget;
- g_assert (IDE_IS_EDITOR_PAGE (self));
-
- /*
- * WORKAROUND: We need to reset the drag dest to avoid warnings by Gtk
- * reseting the target list for the source view.
- */
- if (self->source_view != NULL)
- gtk_drag_dest_set (GTK_WIDGET (self->source_view),
- GTK_DEST_DEFAULT_ALL,
- NULL, 0, GDK_ACTION_COPY);
-
- dzl_clear_source (&self->toggle_map_source);
+ ide_editor_page_set_gutter (self, NULL);
ide_clear_and_destroy_object (&self->addins);
- gtk_widget_insert_action_group (widget, "editor-search", NULL);
- gtk_widget_insert_action_group (widget, "editor-page", NULL);
-
- g_cancellable_cancel (self->destroy_cancellable);
- g_clear_object (&self->destroy_cancellable);
-
- g_clear_object (&self->search);
- g_clear_object (&self->editor_settings);
- g_clear_object (&self->insight_settings);
-
- g_clear_object (&self->buffer);
+ g_clear_object (&self->buffer_file_settings);
+ g_clear_object (&self->view_file_settings);
- if (self->buffer_bindings != NULL)
- {
- dzl_binding_group_set_source (self->buffer_bindings, NULL);
- g_clear_object (&self->buffer_bindings);
- }
-
- if (self->buffer_signals != NULL)
+ if (self->buffer != NULL)
{
- dzl_signal_group_set_target (self->buffer_signals, NULL);
- g_clear_object (&self->buffer_signals);
+ ide_buffer_release (self->buffer);
+ g_clear_object (&self->buffer);
}
- GTK_WIDGET_CLASS (ide_editor_page_parent_class)->destroy (widget);
-}
-
-static GFile *
-ide_editor_page_get_file_or_directory (IdePage *page)
-{
- GFile *ret = ide_editor_page_get_file (IDE_EDITOR_PAGE (page));
- return ret ? g_object_ref (ret) : NULL;
-}
-
-static void
-ide_editor_page_finalize (GObject *object)
-{
- G_OBJECT_CLASS (ide_editor_page_parent_class)->finalize (object);
-
- DZL_COUNTER_DEC (instances);
+ G_OBJECT_CLASS (ide_editor_page_parent_class)->dispose (object);
}
static void
@@ -864,29 +352,18 @@ ide_editor_page_get_property (GObject *object,
switch (prop_id)
{
- case PROP_AUTO_HIDE_MAP:
- g_value_set_boolean (value, ide_editor_page_get_auto_hide_map (self));
- break;
-
case PROP_BUFFER:
g_value_set_object (value, ide_editor_page_get_buffer (self));
break;
- case PROP_BUFFER_FILE:
- g_value_set_object (value, ide_buffer_get_file (self->buffer));
+ case PROP_GUTTER:
+ g_value_set_object (value, ide_editor_page_get_gutter (self));
break;
+
case PROP_VIEW:
g_value_set_object (value, ide_editor_page_get_view (self));
break;
- case PROP_SEARCH:
- g_value_set_object (value, ide_editor_page_get_search (self));
- break;
-
- case PROP_SHOW_MAP:
- g_value_set_boolean (value, ide_editor_page_get_show_map (self));
- break;
-
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -902,16 +379,12 @@ ide_editor_page_set_property (GObject *object,
switch (prop_id)
{
- case PROP_AUTO_HIDE_MAP:
- ide_editor_page_set_auto_hide_map (self, g_value_get_boolean (value));
- break;
-
case PROP_BUFFER:
ide_editor_page_set_buffer (self, g_value_get_object (value));
break;
- case PROP_SHOW_MAP:
- ide_editor_page_set_show_map (self, g_value_get_boolean (value));
+ case PROP_GUTTER:
+ ide_editor_page_set_gutter (self, g_value_get_object (value));
break;
default:
@@ -926,519 +399,463 @@ ide_editor_page_class_init (IdeEditorPageClass *klass)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
IdePageClass *page_class = IDE_PAGE_CLASS (klass);
- object_class->finalize = ide_editor_page_finalize;
- object_class->constructed = ide_editor_page_constructed;
+ object_class->dispose = ide_editor_page_dispose;
object_class->get_property = ide_editor_page_get_property;
object_class->set_property = ide_editor_page_set_property;
- widget_class->destroy = ide_editor_page_destroy;
- widget_class->hierarchy_changed = ide_editor_page_hierarchy_changed;
+ widget_class->grab_focus = ide_editor_page_grab_focus;
+ widget_class->root = ide_editor_page_root;
- page_class->create_split = ide_editor_page_create_split;
page_class->get_file_or_directory = ide_editor_page_get_file_or_directory;
+ page_class->create_split = ide_editor_page_create_split;
+ /**
+ * IdeEditorPage:buffer:
+ *
+ * The #IdeBuffer that is displayed within the #IdeSourceView.
+ */
properties [PROP_BUFFER] =
g_param_spec_object ("buffer",
"Buffer",
- "The buffer for the view",
+ "The buffer to be displayed within the page",
IDE_TYPE_BUFFER,
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
- /* It's really just there to get notify:: support for the buffer's file property
- * but through the page, for the session addin.
+ /**
+ * IdeEditorPage:gutter:
+ *
+ * The "gutter" property contains an #IdeGutter or %NULL, which is a
+ * specialized renderer for the sourceview which can bring together a number
+ * of types of content which needs to be displayed, in a single renderer.
+ */
+ properties [PROP_GUTTER] =
+ g_param_spec_object ("gutter",
+ "Gutter",
+ "The primary gutter renderer in the left gutter window",
+ IDE_TYPE_GUTTER,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * IdeEditorPage:view:
+ *
+ * The #IdeSourceView contained within the page.
*/
- properties [PROP_BUFFER_FILE] =
- g_param_spec_object ("buffer-file",
- "Buffer file",
- "The buffer file for the view's buffer",
- G_TYPE_FILE,
- (G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
-
- properties [PROP_SEARCH] =
- g_param_spec_object ("search",
- "Search",
- "An search helper for the document",
- IDE_TYPE_EDITOR_SEARCH,
- (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_SHOW_MAP] =
- g_param_spec_boolean ("show-map",
- "Show Map",
- "If the overview map should be shown",
- FALSE,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_AUTO_HIDE_MAP] =
- g_param_spec_boolean ("auto-hide-map",
- "Auto Hide Map",
- "If the overview map should be auto-hidden",
- FALSE,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
properties [PROP_VIEW] =
g_param_spec_object ("view",
"View",
- "The view for editing the buffer",
+ "The view displaying the buffer",
IDE_TYPE_SOURCE_VIEW,
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
- gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/libide-editor/ui/ide-editor-page.ui");
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/libide-editor/ide-editor-page.ui");
gtk_widget_class_bind_template_child (widget_class, IdeEditorPage, map);
gtk_widget_class_bind_template_child (widget_class, IdeEditorPage, map_revealer);
- gtk_widget_class_bind_template_child (widget_class, IdeEditorPage, overlay);
- gtk_widget_class_bind_template_child (widget_class, IdeEditorPage, progress_bar);
gtk_widget_class_bind_template_child (widget_class, IdeEditorPage, scroller);
- gtk_widget_class_bind_template_child (widget_class, IdeEditorPage, scroller_box);
- gtk_widget_class_bind_template_child (widget_class, IdeEditorPage, search_bar);
- gtk_widget_class_bind_template_child (widget_class, IdeEditorPage, search_revealer);
- gtk_widget_class_bind_template_child (widget_class, IdeEditorPage, modified_revealer);
- gtk_widget_class_bind_template_child (widget_class, IdeEditorPage, modified_cancel_button);
- gtk_widget_class_bind_template_child (widget_class, IdeEditorPage, source_view);
- gtk_widget_class_bind_template_callback (widget_class, ide_editor_page_notify_child_revealed);
- gtk_widget_class_bind_template_callback (widget_class, ide_editor_page_stop_search);
-
- g_type_ensure (IDE_TYPE_SOURCE_VIEW);
- g_type_ensure (IDE_TYPE_EDITOR_SEARCH_BAR);
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorPage, view);
+ gtk_widget_class_bind_template_callback (widget_class, ide_editor_page_focus_enter_cb);
+
+ gtk_widget_class_add_binding_action (widget_class, GDK_KEY_s, GDK_CONTROL_MASK, "page.save", NULL);
+
+ _ide_editor_page_class_actions_init (klass);
}
static void
ide_editor_page_init (IdeEditorPage *self)
{
- DZL_COUNTER_INC (instances);
+ GtkSourceGutterRenderer *renderer;
+ GtkSourceGutter *gutter;
+ GMenu *menu;
gtk_widget_init_template (GTK_WIDGET (self));
ide_page_set_can_split (IDE_PAGE (self), TRUE);
- ide_page_set_menu_id (IDE_PAGE (self), "ide-editor-page-document-menu");
-
- self->destroy_cancellable = g_cancellable_new ();
-
- /* Setup signals to monitor on the buffer. */
- self->buffer_signals = dzl_signal_group_new (IDE_TYPE_BUFFER);
-
- dzl_signal_group_connect_swapped (self->buffer_signals,
- "loaded",
- G_CALLBACK (ide_editor_page_buffer_loaded),
- self);
-
- dzl_signal_group_connect_swapped (self->buffer_signals,
- "modified-changed",
- G_CALLBACK (ide_editor_page_buffer_modified_changed),
- self);
-
- dzl_signal_group_connect_swapped (self->buffer_signals,
- "notify::file",
- G_CALLBACK (ide_editor_page_buffer_notify_file),
- self);
-
- dzl_signal_group_connect_swapped (self->buffer_signals,
- "notify::failed",
- G_CALLBACK (ide_editor_page_buffer_notify_failed),
- self);
-
- dzl_signal_group_connect_swapped (self->buffer_signals,
- "notify::language",
- G_CALLBACK (ide_editor_page_buffer_notify_language),
- self);
-
- dzl_signal_group_connect_swapped (self->buffer_signals,
- "notify::style-scheme",
- G_CALLBACK (ide_editor_page_buffer_notify_style_scheme),
- self);
- dzl_signal_group_connect_swapped (self->buffer_signals,
- "notify::changed-on-volume",
- G_CALLBACK (ide_editor_page__buffer_notify_changed_on_volume),
- self);
-
- g_signal_connect_swapped (self->buffer_signals,
- "bind",
- G_CALLBACK (ide_editor_page_bind_signals),
- self);
-
- g_signal_connect_object (self->modified_cancel_button,
- "clicked",
- G_CALLBACK (ide_editor_page_hide_reload_bar),
- self,
- G_CONNECT_SWAPPED);
-
- /* Setup bindings for the buffer. */
- self->buffer_bindings = dzl_binding_group_new ();
- dzl_binding_group_bind (self->buffer_bindings, "title", self, "title", 0);
-
- /* Load our custom font for the overview map. */
- gtk_source_map_set_view (self->map, GTK_SOURCE_VIEW (self->source_view));
+ ide_page_set_menu_id (IDE_PAGE (self), "ide-editor-page-menu");
+
+ /* Add menus to source view */
+ menu = ide_application_get_menu_by_id (IDE_APPLICATION_DEFAULT, "ide-source-view-popup-menu");
+ ide_source_view_append_menu (self->view, G_MENU_MODEL (menu));
+
+ /* Add gutter changes to the overview map */
+ gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (self->map),
+ GTK_TEXT_WINDOW_LEFT);
+ renderer = g_object_new (IDE_TYPE_LINE_CHANGE_GUTTER_RENDERER,
+ "width-request", 1,
+ NULL);
+ gtk_source_gutter_insert (gutter, renderer, 100);
}
-/**
- * ide_editor_page_get_buffer:
- * @self: a #IdeEditorPage
- *
- * Gets the underlying buffer for the view.
- *
- * Returns: (transfer none): An #IdeBuffer
- *
- * Since: 3.32
- */
-IdeBuffer *
-ide_editor_page_get_buffer (IdeEditorPage *self)
+GtkWidget *
+ide_editor_page_new (IdeBuffer *buffer)
{
- g_return_val_if_fail (IDE_IS_EDITOR_PAGE (self), NULL);
+ g_return_val_if_fail (IDE_IS_BUFFER (buffer), NULL);
- return self->buffer;
+ return g_object_new (IDE_TYPE_EDITOR_PAGE,
+ "buffer", buffer,
+ NULL);
}
/**
* ide_editor_page_get_view:
* @self: a #IdeEditorPage
*
- * Gets the #IdeSourceView that is part of the #IdeEditorPage.
- *
- * Returns: (transfer none): An #IdeSourceView
+ * Gets the #IdeSourceView for the page.
*
- * Since: 3.32
+ * Returns: (transfer none): an #IdeSourceView
*/
IdeSourceView *
ide_editor_page_get_view (IdeEditorPage *self)
{
g_return_val_if_fail (IDE_IS_EDITOR_PAGE (self), NULL);
- return self->source_view;
+ return self->view;
}
/**
- * ide_editor_page_get_language_id:
+ * ide_editor_page_get_buffer:
* @self: a #IdeEditorPage
*
- * This is a helper to get the language-id of the underlying buffer.
- *
- * Returns: (nullable): the language-id as a string, or %NULL
+ * Gets the #IdeBuffer for the page.
*
- * Since: 3.32
+ * Returns: (transfer none): an #IdeBuffer
*/
-const gchar *
-ide_editor_page_get_language_id (IdeEditorPage *self)
+IdeBuffer *
+ide_editor_page_get_buffer (IdeEditorPage *self)
{
g_return_val_if_fail (IDE_IS_EDITOR_PAGE (self), NULL);
- if (self->buffer != NULL)
- {
- GtkSourceLanguage *language;
-
- language = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (self->buffer));
-
- if (language != NULL)
- return gtk_source_language_get_id (language);
- }
-
- return NULL;
+ return self->buffer;
}
/**
- * ide_editor_page_scroll_to_line:
+ * ide_editor_page_get_file:
* @self: a #IdeEditorPage
- * @line: the line to scroll to
*
- * This is a helper to quickly jump to a given line without all the frills. It
- * will also ensure focus on the editor view, so that refocusing the view
- * afterwards does not cause the view to restore the cursor to the previous
- * location.
+ * Gets the file for the document.
*
- * This will move the insert cursor.
+ * This is a convenience function around ide_buffer_get_file().
*
- * Lines start from 0.
- *
- * Since: 3.32
+ * Returns: (transfer none): a #GFile
*/
-void
-ide_editor_page_scroll_to_line (IdeEditorPage *self,
- guint line)
+GFile *
+ide_editor_page_get_file (IdeEditorPage *self)
{
- ide_editor_page_scroll_to_line_offset (self, line, 0);
+ g_return_val_if_fail (IDE_IS_EDITOR_PAGE (self), NULL);
+
+ return ide_buffer_get_file (self->buffer);
}
-/**
- * ide_editor_page_scroll_to_line_offset:
- * @self: a #IdeEditorPage
- * @line: the line to scroll to
- * @line_offset: the line offset
- *
- * Like ide_editor_page_scroll_to_line() but allows specifying the
- * line offset (column) to place the cursor on.
- *
- * This will move the insert cursor.
- *
- * Lines and offsets start from 0.
- *
- * If @line_offset is zero, the first non-space character of @line will be
- * used instead.
- *
- * Since: 3.32
- */
-void
-ide_editor_page_scroll_to_line_offset (IdeEditorPage *self,
- guint line,
- guint line_offset)
+static void
+ide_editor_page_save_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GtkTextIter iter;
+ IdeBuffer *buffer = (IdeBuffer *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ IdeEditorPage *self;
- g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
- g_return_if_fail (self->buffer != NULL);
- g_return_if_fail (line <= G_MAXINT);
+ IDE_ENTRY;
- gtk_widget_grab_focus (GTK_WIDGET (self->source_view));
+ g_assert (IDE_IS_BUFFER (buffer));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
- gtk_text_buffer_get_iter_at_line_offset (GTK_TEXT_BUFFER (self->buffer), &iter,
- line, line_offset);
+ self = ide_task_get_source_object (task);
- if (line_offset == 0)
- {
- while (!gtk_text_iter_ends_line (&iter) &&
- g_unichar_isspace (gtk_text_iter_get_char (&iter)))
- {
- if (!gtk_text_iter_forward_char (&iter))
- break;
- }
- }
+ g_assert (IDE_IS_EDITOR_PAGE (self));
- gtk_text_buffer_select_range (GTK_TEXT_BUFFER (self->buffer), &iter, &iter);
- ide_source_view_scroll_to_insert (self->source_view);
-}
+ ide_page_set_progress (IDE_PAGE (self), NULL);
-gboolean
-ide_editor_page_get_auto_hide_map (IdeEditorPage *self)
-{
- g_return_val_if_fail (IDE_IS_EDITOR_PAGE (self), FALSE);
+ if (!ide_buffer_save_file_finish (buffer, result, &error))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ide_task_return_boolean (task, TRUE);
- return self->auto_hide_map;
+ IDE_EXIT;
}
-static gboolean
-ide_editor_page_auto_hide_cb (gpointer user_data)
+static void
+ide_editor_page_save_response (GtkFileChooserNative *native,
+ int response,
+ IdeTask *task)
{
- IdeEditorPage *self = user_data;
+ IdeEditorPage *self;
+ IdeBuffer *buffer;
- g_assert (IDE_IS_EDITOR_PAGE (self));
+ IDE_ENTRY;
- self->toggle_map_source = 0;
- gtk_revealer_set_reveal_child (self->map_revealer, FALSE);
+ g_assert (GTK_IS_FILE_CHOOSER_NATIVE (native));
+ g_assert (IDE_IS_TASK (task));
- return G_SOURCE_REMOVE;
-}
+ self = ide_task_get_source_object (task);
+ buffer = ide_task_get_task_data (task);
-static void
-ide_editor_page_update_reveal_timer (IdeEditorPage *self)
-{
g_assert (IDE_IS_EDITOR_PAGE (self));
+ g_assert (IDE_IS_BUFFER (buffer));
- dzl_clear_source (&self->toggle_map_source);
-
- if (self->auto_hide_map && gtk_revealer_get_reveal_child (self->map_revealer))
+ if (response == GTK_RESPONSE_ACCEPT)
{
- self->toggle_map_source =
- gdk_threads_add_timeout_seconds_full (G_PRIORITY_LOW,
- AUTO_HIDE_TIMEOUT_SECONDS,
- ide_editor_page_auto_hide_cb,
- g_object_ref (self),
- g_object_unref);
+ g_autoptr(GFile) file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (native));
+ g_autoptr(IdeNotification) notif = NULL;
+
+ ide_buffer_save_file_async (buffer,
+ file,
+ ide_task_get_cancellable (task),
+ ¬if,
+ ide_editor_page_save_cb,
+ g_object_ref (task));
+
+ ide_page_set_progress (IDE_PAGE (self), notif);
}
+
+ gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (native));
+ g_object_unref (task);
+
+ IDE_EXIT;
}
void
-ide_editor_page_set_auto_hide_map (IdeEditorPage *self,
- gboolean auto_hide_map)
+ide_editor_page_save_async (IdeEditorPage *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
+ g_autoptr(IdeTask) task = NULL;
+ g_autoptr(IdeNotification) notif = NULL;
+
+ IDE_ENTRY;
+
g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+ g_return_if_fail (IDE_IS_BUFFER (self->buffer));
- auto_hide_map = !!auto_hide_map;
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, ide_editor_page_save_async);
+ ide_task_set_task_data (task, ide_buffer_hold (self->buffer), ide_buffer_release);
- if (auto_hide_map != self->auto_hide_map)
+ if (ide_buffer_get_is_temporary (self->buffer))
{
- self->auto_hide_map = auto_hide_map;
- ide_editor_page_update_map (self);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_AUTO_HIDE_MAP]);
+ g_autoptr(GFile) workdir = NULL;
+ GtkFileChooserNative *dialog;
+ IdeWorkspace *workspace;
+ IdeContext *context;
+
+ workspace = ide_widget_get_workspace (GTK_WIDGET (self));
+ context = ide_workspace_get_context (workspace);
+ workdir = ide_context_ref_workdir (context);
+
+ dialog = gtk_file_chooser_native_new (_("Save File"),
+ GTK_WINDOW (workspace),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ _("Save"), _("Cancel"));
+
+ g_object_set (dialog,
+ "do-overwrite-confirmation", TRUE,
+ "modal", TRUE,
+ "select-multiple", FALSE,
+ "show-hidden", FALSE,
+ NULL);
+
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), workdir, NULL);
+
+ g_signal_connect (dialog,
+ "response",
+ G_CALLBACK (ide_editor_page_save_response),
+ g_object_ref (task));
+
+ gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
+
+ IDE_EXIT;
}
+
+ ide_buffer_save_file_async (self->buffer,
+ ide_buffer_get_file (self->buffer),
+ cancellable,
+ ¬if,
+ ide_editor_page_save_cb,
+ g_steal_pointer (&task));
+
+ ide_page_set_progress (IDE_PAGE (self), notif);
+
+ IDE_EXIT;
}
gboolean
-ide_editor_page_get_show_map (IdeEditorPage *self)
+ide_editor_page_save_finish (IdeEditorPage *self,
+ GAsyncResult *result,
+ GError **error)
{
+ gboolean ret;
+
+ IDE_ENTRY;
+
g_return_val_if_fail (IDE_IS_EDITOR_PAGE (self), FALSE);
+ g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
- return self->show_map;
+ ret = ide_task_propagate_boolean (IDE_TASK (result), error);
+
+ IDE_RETURN (ret);
}
-void
-ide_editor_page_set_show_map (IdeEditorPage *self,
- gboolean show_map)
+static void
+ide_editor_page_discard_changes_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
+ IdeBufferManager *bufmgr = (IdeBufferManager *)object;
+ g_autoptr(IdeBuffer) buffer = NULL;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ IdeEditorPage *self;
- show_map = !!show_map;
+ IDE_ENTRY;
- if (show_map != self->show_map)
- {
- self->show_map = show_map;
- g_object_set (self->scroller,
- "vscrollbar-policy", show_map ? GTK_POLICY_EXTERNAL : GTK_POLICY_AUTOMATIC,
- NULL);
- ide_editor_page_update_map (self);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_AUTO_HIDE_MAP]);
- }
-}
+ g_assert (IDE_IS_BUFFER_MANAGER (bufmgr));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
-/**
- * ide_editor_page_set_language:
- * @self: a #IdeEditorPage
- *
- * This is a convenience function to set the language on the underlying
- * #IdeBuffer text buffer.
- *
- * Since: 3.32
- */
-void
-ide_editor_page_set_language (IdeEditorPage *self,
- GtkSourceLanguage *language)
-{
- g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
- g_return_if_fail (!language || GTK_SOURCE_IS_LANGUAGE (language));
+ self = ide_task_get_source_object (task);
- gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (self->buffer), language);
-}
+ g_assert (IDE_IS_EDITOR_PAGE (self));
-/**
- * ide_editor_page_get_language:
- * @self: a #IdeEditorPage
- *
- * Gets the #GtkSourceLanguage that is used by the underlying buffer.
- *
- * Returns: (transfer none) (nullable): a #GtkSourceLanguage or %NULL.
- *
- * Since: 3.32
- */
-GtkSourceLanguage *
-ide_editor_page_get_language (IdeEditorPage *self)
-{
- g_return_val_if_fail (IDE_IS_EDITOR_PAGE (self), NULL);
+ ide_page_set_progress (IDE_PAGE (self), NULL);
+
+ if (!(buffer = ide_buffer_manager_load_file_finish (bufmgr, result, &error)))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ide_task_return_boolean (task, TRUE);
- return gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (self->buffer));
+ g_assert (!buffer || IDE_IS_BUFFER (buffer));
+
+ IDE_EXIT;
}
-/**
- * ide_editor_page_move_next_error:
- * @self: a #IdeEditorPage
- *
- * Moves to the next error, if any.
- *
- * If there is no error, the insertion cursor is not moved.
- *
- * Since: 3.32
- */
void
-ide_editor_page_move_next_error (IdeEditorPage *self)
-{
+ide_editor_page_discard_changes_async (IdeEditorPage *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(IdeTask) task = NULL;
+ g_autoptr(IdeNotification) notif = NULL;
+ IdeBufferManager *bufmgr;
+ IdeContext *context;
+
+ IDE_ENTRY;
+
g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+ g_return_if_fail (IDE_IS_BUFFER (self->buffer));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, ide_editor_page_discard_changes_async);
+ ide_task_set_task_data (task, ide_buffer_hold (self->buffer), ide_buffer_release);
+
+ if (ide_buffer_get_is_temporary (self->buffer))
+ {
+ ide_task_return_boolean (task, TRUE);
+ IDE_EXIT;
+ }
+
+ context = ide_widget_get_context (GTK_WIDGET (self));
+ bufmgr = ide_buffer_manager_from_context (context);
+ notif = ide_notification_new ();
+ ide_page_set_progress (IDE_PAGE (self), notif);
- g_signal_emit_by_name (self->source_view, "move-error", GTK_DIR_DOWN);
+ ide_buffer_manager_load_file_async (bufmgr,
+ ide_buffer_get_file (self->buffer),
+ IDE_BUFFER_OPEN_FLAGS_FORCE_RELOAD,
+ notif,
+ cancellable,
+ ide_editor_page_discard_changes_cb,
+ g_steal_pointer (&task));
+
+ IDE_EXIT;
}
-/**
- * ide_editor_page_move_previous_error:
- * @self: a #IdeEditorPage
- *
- * Moves the insertion cursor to the previous error.
- *
- * If there is no error, the insertion cursor is not moved.
- *
- * Since: 3.32
- */
-void
-ide_editor_page_move_previous_error (IdeEditorPage *self)
+gboolean
+ide_editor_page_discard_changes_finish (IdeEditorPage *self,
+ GAsyncResult *result,
+ GError **error)
{
- g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
+ gboolean ret;
- g_signal_emit_by_name (self->source_view, "move-error", GTK_DIR_UP);
+ IDE_ENTRY;
+
+ g_return_val_if_fail (IDE_IS_EDITOR_PAGE (self), FALSE);
+ g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
+
+ ret = ide_task_propagate_boolean (IDE_TASK (result), error);
+
+ IDE_RETURN (ret);
}
/**
- * ide_editor_page_move_next_search_result:
+ * ide_editor_page_get_gutter:
* @self: a #IdeEditorPage
*
- * Moves the insertion cursor to the next search result.
+ * Gets the #IdeGutter displayed in the editor page.
*
- * If there is no search result, the insertion cursor is not moved.
- *
- * Since: 3.32
+ * Returns: (transfer none) (nullable): an #IdeGutter or %NULL
*/
-void
-ide_editor_page_move_next_search_result (IdeEditorPage *self)
+IdeGutter *
+ide_editor_page_get_gutter (IdeEditorPage *self)
{
- g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
- g_return_if_fail (self->destroy_cancellable != NULL);
- g_return_if_fail (self->buffer != NULL);
+ g_return_val_if_fail (IDE_IS_EDITOR_PAGE (self), NULL);
- ide_editor_search_move (self->search, IDE_EDITOR_SEARCH_NEXT);
+ return self->gutter;
}
-/**
- * ide_editor_page_move_previous_search_result:
- * @self: a #IdeEditorPage
- *
- * Moves the insertion cursor to the previous search result.
- *
- * If there is no search result, the insertion cursor is not moved.
- *
- * Since: 3.32
- */
void
-ide_editor_page_move_previous_search_result (IdeEditorPage *self)
+ide_editor_page_set_gutter (IdeEditorPage *self,
+ IdeGutter *gutter)
{
+ GtkSourceGutter *container;
+
+ IDE_ENTRY;
+
g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
- g_return_if_fail (self->destroy_cancellable != NULL);
- g_return_if_fail (self->buffer != NULL);
+ g_return_if_fail (!gutter || IDE_IS_GUTTER (gutter));
- ide_editor_search_move (self->search, IDE_EDITOR_SEARCH_PREVIOUS);
-}
+ if (gutter == self->gutter)
+ IDE_EXIT;
-/**
- * ide_editor_page_get_search:
- * @self: a #IdeEditorPage
- *
- * Gets the #IdeEditorSearch used to search within the document.
- *
- * Returns: (transfer none): An #IdeEditorSearch
- *
- * Since: 3.32
- */
-IdeEditorSearch *
-ide_editor_page_get_search (IdeEditorPage *self)
-{
- g_return_val_if_fail (IDE_IS_EDITOR_PAGE (self), NULL);
+ container = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (self->view),
+ GTK_TEXT_WINDOW_LEFT);
+
+ if (self->gutter)
+ {
+ gtk_source_gutter_remove (container, GTK_SOURCE_GUTTER_RENDERER (self->gutter));
+ _ide_editor_page_settings_disconnect_gutter (self, self->gutter);
+ g_clear_object (&self->gutter);
+ }
- return self->search;
+ if (gutter)
+ {
+ g_set_object (&self->gutter, gutter);
+ gtk_source_gutter_insert (container, GTK_SOURCE_GUTTER_RENDERER (self->gutter), 0);
+ _ide_editor_page_settings_connect_gutter (self, self->gutter);
+ ide_gutter_style_changed (self->gutter);
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_GUTTER]);
+
+ IDE_EXIT;
}
-/**
- * ide_editor_page_get_file:
- * @self: a #IdeEditorPage
- *
- * Gets the #GFile that represents the current file. This may be a temporary
- * file, but a #GFile will still be used for the temporary file.
- *
- * Returns: (transfer none): a #GFile for the current buffer
- *
- * Since: 3.32
- */
-GFile *
-ide_editor_page_get_file (IdeEditorPage *self)
+void
+ide_editor_page_scroll_to_visual_position (IdeEditorPage *self,
+ guint line,
+ guint column)
{
- IdeBuffer *buffer;
-
- g_return_val_if_fail (IDE_IS_EDITOR_PAGE (self), NULL);
+ GtkTextIter iter;
- if ((buffer = ide_editor_page_get_buffer (self)))
- return ide_buffer_get_file (buffer);
+ g_return_if_fail (IDE_IS_EDITOR_PAGE (self));
- return NULL;
+ ide_source_view_get_iter_at_visual_position (self->view, &iter, line, column);
+ gtk_text_buffer_select_range (GTK_TEXT_BUFFER (self->buffer), &iter, &iter);
+ gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (self->view),
+ gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (self->buffer)));
}
diff --git a/src/libide/editor/ide-editor-page.h b/src/libide/editor/ide-editor-page.h
index e47c9bfd9..b4ebf0c3d 100644
--- a/src/libide/editor/ide-editor-page.h
+++ b/src/libide/editor/ide-editor-page.h
@@ -1,6 +1,6 @@
/* ide-editor-page.h
*
- * Copyright 2017-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2017-2022 Christian Hergert <chergert redhat com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,59 +24,52 @@
# error "Only <libide-editor.h> can be included directly."
#endif
-#include <libide-code.h>
#include <libide-core.h>
+#include <libide-code.h>
#include <libide-gui.h>
#include <libide-sourceview.h>
-#include "ide-editor-search.h"
-
G_BEGIN_DECLS
#define IDE_TYPE_EDITOR_PAGE (ide_editor_page_get_type())
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (IdeEditorPage, ide_editor_page, IDE, EDITOR_PAGE, IdePage)
-IDE_AVAILABLE_IN_3_32
-GFile *ide_editor_page_get_file (IdeEditorPage *self);
-IDE_AVAILABLE_IN_3_32
-IdeBuffer *ide_editor_page_get_buffer (IdeEditorPage *self);
-IDE_AVAILABLE_IN_3_32
-IdeSourceView *ide_editor_page_get_view (IdeEditorPage *self);
-IDE_AVAILABLE_IN_3_32
-IdeEditorSearch *ide_editor_page_get_search (IdeEditorPage *self);
-IDE_AVAILABLE_IN_3_32
-const gchar *ide_editor_page_get_language_id (IdeEditorPage *self);
-IDE_AVAILABLE_IN_3_32
-void ide_editor_page_scroll_to_line (IdeEditorPage *self,
- guint line);
-IDE_AVAILABLE_IN_3_32
-void ide_editor_page_scroll_to_line_offset (IdeEditorPage *self,
- guint line,
- guint line_offset);
-IDE_AVAILABLE_IN_3_32
-gboolean ide_editor_page_get_auto_hide_map (IdeEditorPage *self);
-IDE_AVAILABLE_IN_3_32
-void ide_editor_page_set_auto_hide_map (IdeEditorPage *self,
- gboolean auto_hide_map);
-IDE_AVAILABLE_IN_3_32
-gboolean ide_editor_page_get_show_map (IdeEditorPage *self);
-IDE_AVAILABLE_IN_3_32
-void ide_editor_page_set_show_map (IdeEditorPage *self,
- gboolean show_map);
-IDE_AVAILABLE_IN_3_32
-GtkSourceLanguage *ide_editor_page_get_language (IdeEditorPage *self);
-IDE_AVAILABLE_IN_3_32
-void ide_editor_page_set_language (IdeEditorPage *self,
- GtkSourceLanguage *language);
-IDE_AVAILABLE_IN_3_32
-void ide_editor_page_move_next_error (IdeEditorPage *self);
-IDE_AVAILABLE_IN_3_32
-void ide_editor_page_move_previous_error (IdeEditorPage *self);
-IDE_AVAILABLE_IN_3_32
-void ide_editor_page_move_next_search_result (IdeEditorPage *self);
-IDE_AVAILABLE_IN_3_32
-void ide_editor_page_move_previous_search_result (IdeEditorPage *self);
+IDE_AVAILABLE_IN_ALL
+GtkWidget *ide_editor_page_new (IdeBuffer *buffer);
+IDE_AVAILABLE_IN_ALL
+IdeBuffer *ide_editor_page_get_buffer (IdeEditorPage *self);
+IDE_AVAILABLE_IN_ALL
+IdeSourceView *ide_editor_page_get_view (IdeEditorPage *self);
+IDE_AVAILABLE_IN_ALL
+GFile *ide_editor_page_get_file (IdeEditorPage *self);
+IDE_AVAILABLE_IN_ALL
+IdeGutter *ide_editor_page_get_gutter (IdeEditorPage *self);
+IDE_AVAILABLE_IN_ALL
+void ide_editor_page_set_gutter (IdeEditorPage *self,
+ IdeGutter *gutter);
+IDE_AVAILABLE_IN_ALL
+void ide_editor_page_discard_changes_async (IdeEditorPage *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+IDE_AVAILABLE_IN_ALL
+gboolean ide_editor_page_discard_changes_finish (IdeEditorPage *self,
+ GAsyncResult *result,
+ GError **error);
+IDE_AVAILABLE_IN_ALL
+void ide_editor_page_save_async (IdeEditorPage *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+IDE_AVAILABLE_IN_ALL
+gboolean ide_editor_page_save_finish (IdeEditorPage *self,
+ GAsyncResult *result,
+ GError **error);
+IDE_AVAILABLE_IN_ALL
+void ide_editor_page_scroll_to_visual_position (IdeEditorPage *self,
+ guint line,
+ guint column);
G_END_DECLS
diff --git a/src/libide/editor/ide-editor-page.ui b/src/libide/editor/ide-editor-page.ui
index 7a4227383..96949e5ae 100644
--- a/src/libide/editor/ide-editor-page.ui
+++ b/src/libide/editor/ide-editor-page.ui
@@ -1,122 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="IdeEditorPage" parent="IdePage">
- <child>
- <object class="GtkOverlay" id="overlay">
- <property name="visible">true</property>
- <child type="overlay">
- <object class="GtkRevealer" id="search_revealer">
- <property name="width-request">525</property>
- <property name="halign">end</property>
- <property name="valign">start</property>
- <property name="margin-right">12</property>
- <property name="reveal-child">false</property>
- <property name="visible">true</property>
- <signal name="notify::child-revealed" handler="ide_editor_page_notify_child_revealed"
swapped="true" object="IdeEditorPage"/>
- <child>
- <object class="IdeEditorSearchBar" id="search_bar">
- <property name="visible">true</property>
- <signal name="stop-search" handler="ide_editor_page_stop_search" swapped="true"
object="IdeEditorPage"/>
- </object>
- </child>
- </object>
- <packing>
- <property name="index">1</property>
- </packing>
- </child>
- <child type="overlay">
- <object class="GtkRevealer" id="modified_revealer">
- <property name="halign">fill</property>
- <property name="valign">start</property>
- <property name="visible">true</property>
- <property name="reveal-child">false</property>
+ <property name="can-maximize">true</property>
+ <child type="content">
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="vexpand">true</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scroller">
<child>
- <object class="GtkInfoBar">
- <property name="visible">true</property>
- <child internal-child="action_area">
- <object class="GtkButtonBox">
- <property name="spacing">6</property>
- <property name="layout_style">end</property>
- <child>
- <object class="GtkButton">
- <property name="action-name">editor-page.reload</property>
- <property name="label" translatable="yes">_Reload</property>
- <property name="visible">true</property>
- <property name="receives_default">true</property>
- <property name="use_underline">true</property>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="modified_cancel_button">
- <property name="label" translatable="yes">_Cancel</property>
- <property name="visible">true</property>
- <property name="use_underline">true</property>
- </object>
- </child>
- </object>
- </child>
- <child internal-child="content_area">
- <object class="GtkBox">
- <property name="spacing">16</property>
- <child>
- <object class="GtkLabel" id="modified_label">
- <property name="hexpand">true</property>
- <property name="label" translatable="yes">Builder has discovered that this file has
been modified externally. Would you like to reload the file?</property>
- <property name="visible">true</property>
- <property name="wrap">true</property>
- <property name="xalign">0</property>
- </object>
- </child>
+ <object class="IdeSourceView" id="view">
+ <property name="monospace">true</property>
+ <property name="hexpand">true</property>
+ <property name="vexpand">true</property>
+ <property name="show-line-numbers">false</property>
+ <property name="left-margin">0</property>
+ <child>
+ <object class="GtkEventControllerFocus">
+ <signal name="enter" handler="ide_editor_page_focus_enter_cb" swapped="true"
object="IdeEditorPage"/>
</object>
</child>
</object>
</child>
</object>
</child>
- <child type="overlay">
- <object class="GtkProgressBar" id="progress_bar">
- <property name="hexpand">true</property>
- <property name="valign">start</property>
- <style>
- <class name="osd"/>
- </style>
- </object>
- </child>
- <child type="overlay">
+ <child>
<object class="GtkRevealer" id="map_revealer">
- <property name="halign">end</property>
<property name="transition-type">slide-left</property>
- <property name="vexpand">true</property>
- </object>
- <packing>
- <property name="index">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="scroller_box">
- <property name="orientation">horizontal</property>
- <property name="visible">true</property>
- <child>
- <object class="GtkScrolledWindow" id="scroller">
- <property name="resize-mode">queue</property>
- <property name="expand">true</property>
- <property name="visible">true</property>
- <child>
- <object class="IdeSourceView" id="source_view">
- <property name="auto-indent">true</property>
- <property name="show-line-changes">true</property>
- <property name="show-line-numbers">true</property>
- <property name="visible">true</property>
- </object>
- </child>
- </object>
- </child>
+ <property name="transition-duration">300</property>
+ <property name="reveal-child">true</property>
<child>
<object class="GtkSourceMap" id="map">
- <property name="visible">false</property>
- <style>
- <class name="source-map"/>
- </style>
+ <property name="left-margin">6</property>
+ <property name="view">view</property>
</object>
</child>
</object>
diff --git a/src/libide/editor/ide-editor-private.h b/src/libide/editor/ide-editor-private.h
index d43d548bf..7acad3f48 100644
--- a/src/libide/editor/ide-editor-private.h
+++ b/src/libide/editor/ide-editor-private.h
@@ -1,6 +1,6 @@
/* ide-editor-private.h
*
- * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2017-2022 Christian Hergert <chergert redhat com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,89 +20,10 @@
#pragma once
-#include <libide-gui.h>
-#include <libide-plugins.h>
-#include <libide-sourceview.h>
-#include <libpeas/peas.h>
-
-#include "ide-editor-addin.h"
-#include "ide-editor-page.h"
-#include "ide-editor-search-bar.h"
-#include "ide-editor-search.h"
-#include "ide-editor-sidebar.h"
-#include "ide-editor-surface.h"
-#include "ide-session-private.h"
+#include <glib.h>
G_BEGIN_DECLS
-struct _IdeEditorSurface
-{
- IdeSurface parent_instance;
-
- PeasExtensionSet *addins;
-
- /* Template widgets */
- IdeGrid *grid;
- GtkOverlay *overlay;
- GtkStack *loading_stack;
-
- /* State before entering focus mode */
- guint prefocus_had_left : 1;
- guint prefocus_had_bottom : 1;
-
- guint restore_panel : 1;
-
- IdeSession *session;
-};
-
-struct _IdeEditorPage
-{
- IdePage parent_instance;
-
- IdeExtensionSetAdapter *addins;
-
- GSettings *editor_settings;
- GSettings *insight_settings;
-
- IdeBuffer *buffer;
- DzlBindingGroup *buffer_bindings;
- DzlSignalGroup *buffer_signals;
-
- IdeEditorSearch *search;
-
- GCancellable *destroy_cancellable;
-
- GtkSourceMap *map;
- GtkRevealer *map_revealer;
- GtkOverlay *overlay;
- GtkProgressBar *progress_bar;
- IdeSourceView *source_view;
- GtkScrolledWindow *scroller;
- GtkBox *scroller_box;
- IdeEditorSearchBar *search_bar;
- GtkRevealer *search_revealer;
- GtkRevealer *modified_revealer;
- GtkButton *modified_cancel_button;
-
- /* Raw pointer used to determine when frame changes */
- IdeFrame *last_frame_ptr;
-
- guint toggle_map_source;
-
- guint auto_hide_map : 1;
- guint show_map : 1;
-};
-
-void _ide_editor_page_init_actions (IdeEditorPage *self);
-void _ide_editor_page_init_settings (IdeEditorPage *self);
-void _ide_editor_page_init_shortcuts (IdeEditorPage *self);
-void _ide_editor_page_update_actions (IdeEditorPage *self);
-void _ide_editor_search_bar_init_shortcuts (IdeEditorSearchBar *self);
-void _ide_editor_sidebar_set_open_pages (IdeEditorSidebar *self,
- GListModel *open_pages);
-void _ide_editor_surface_set_loading (IdeEditorSurface *self,
- gboolean loading);
-void _ide_editor_surface_init_actions (IdeEditorSurface *self);
-void _ide_editor_surface_init_shortcuts (IdeEditorSurface *self);
+void _ide_editor_init (void);
G_END_DECLS
diff --git a/src/libide/editor/ide-editor-utils.c b/src/libide/editor/ide-editor-utils.c
new file mode 100644
index 000000000..a7281fba1
--- /dev/null
+++ b/src/libide/editor/ide-editor-utils.c
@@ -0,0 +1,310 @@
+/* ide-editor-utils.c
+ *
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-editor-utils"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include <string.h>
+#include <math.h>
+
+#include <glib/gi18n.h>
+#include <gtksourceview/gtksource.h>
+
+#include "ide-editor-utils.h"
+
+static const struct {
+ GtkSourceNewlineType type;
+ const char *id;
+ const char *label;
+} line_endings[] = {
+ { GTK_SOURCE_NEWLINE_TYPE_LF, "unix", N_("Unix/Linux (LF)") },
+ { GTK_SOURCE_NEWLINE_TYPE_CR, "mac", N_("Mac OS Classic (CR)") },
+ { GTK_SOURCE_NEWLINE_TYPE_CR_LF, "windows", N_("Windows (CR+LF)") },
+};
+
+static int
+sort_by_name (gconstpointer a,
+ gconstpointer b)
+{
+ return g_strcmp0 (gtk_source_encoding_get_name (a),
+ gtk_source_encoding_get_name (b));
+}
+
+/**
+ * ide_editor_encoding_menu_new:
+ * @action_name: the action to activate when selecting menu items
+ *
+ * Creates a new #GMenuModel with items which will activate using
+ * their encoding charset for the action @action_name target.
+ *
+ * Returns: (transfer full): a #GMenuModel
+ */
+GMenuModel *
+ide_editor_encoding_menu_new (const char *action_name)
+{
+ g_autoptr(GMenu) menu = NULL;
+ GHashTable *submenus;
+ GMenu *top_menu;
+ GSList *all;
+
+ g_return_val_if_fail (action_name, NULL);
+
+ top_menu = g_menu_new ();
+
+ submenus = g_hash_table_new (g_str_hash, g_str_equal);
+ all = g_slist_sort (gtk_source_encoding_get_all (), sort_by_name);
+
+ /* Always place UTF8 at the top in it's own section */
+ {
+ g_autoptr(GMenu) section = g_menu_new ();
+ g_autoptr(GMenuItem) item = g_menu_item_new ("UTF-8", NULL);
+
+ g_menu_item_set_action_and_target (item, action_name, "s", "UTF-8");
+ g_menu_item_set_attribute (item, "role", "s", "check");
+ g_menu_append_item (section, item);
+ g_menu_append_section (top_menu, NULL, G_MENU_MODEL (section));
+ }
+
+ menu = g_menu_new ();
+ g_menu_append_section (top_menu, NULL, G_MENU_MODEL (menu));
+
+ for (const GSList *l = all; l; l = l->next)
+ {
+ GtkSourceEncoding *encoding = l->data;
+ const char *name = gtk_source_encoding_get_name (encoding);
+ const char *charset = gtk_source_encoding_get_charset (encoding);
+ g_autofree char *title = g_strdup_printf ("%s (%s)", name, charset);
+ g_autoptr(GMenuItem) item = g_menu_item_new (title, NULL);
+ GMenu *submenu;
+
+ if (name == NULL || charset == NULL)
+ continue;
+
+ if (!(submenu = g_hash_table_lookup (submenus, name)))
+ {
+ submenu = g_menu_new ();
+ g_menu_append_submenu (menu, name, G_MENU_MODEL (submenu));
+ g_hash_table_insert (submenus, (char *)name, submenu);
+ g_object_unref (submenu);
+ }
+
+ g_menu_item_set_action_and_target (item, action_name, "s", gtk_source_encoding_get_charset (encoding));
+ g_menu_item_set_attribute (item, "role", "s", "check");
+ g_menu_append_item (submenu, item);
+ }
+
+ g_hash_table_unref (submenus);
+ g_slist_free (all);
+
+ return G_MENU_MODEL (top_menu);
+}
+
+void
+ide_editor_file_chooser_add_encodings (GtkFileChooser *chooser)
+{
+ GPtrArray *choices;
+ GPtrArray *labels;
+ GSList *all;
+
+ g_return_if_fail (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);
+}
+
+void
+ide_editor_file_chooser_add_line_endings (GtkFileChooser *chooser,
+ GtkSourceNewlineType selected)
+{
+ static GArray *choices;
+ static GArray *labels;
+
+ g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser));
+
+ if (choices == NULL)
+ {
+ choices = g_array_new (TRUE, FALSE, sizeof (char *));
+ labels = g_array_new (TRUE, FALSE, sizeof (char *));
+
+ for (guint i = 0; i < G_N_ELEMENTS (line_endings); i++)
+ {
+ const char *msg = g_dgettext (GETTEXT_PACKAGE, line_endings[i].label);
+
+ g_array_append_val (choices, line_endings[i].id);
+ g_array_append_val (labels, msg);
+ }
+ }
+
+ gtk_file_chooser_add_choice (chooser,
+ "line-ending",
+ _("Line Ending:"),
+ (const char **)(gpointer)choices->data,
+ (const char **)(gpointer)labels->data);
+ gtk_file_chooser_set_choice (chooser, "line-endings", "unix");
+
+ for (guint i = 0; i < G_N_ELEMENTS (line_endings); i++)
+ {
+ if (line_endings[i].type == selected)
+ {
+ gtk_file_chooser_set_choice (chooser, "line-endings", line_endings[i].id);
+ break;
+ }
+ }
+}
+
+const GtkSourceEncoding *
+ide_editor_file_chooser_get_encoding (GtkFileChooser *chooser)
+{
+ const char *encoding;
+
+ g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
+
+ if ((encoding = gtk_file_chooser_get_choice (chooser, "encoding")))
+ {
+ if (strcmp (encoding, "auto") != 0)
+ return gtk_source_encoding_get_from_charset (encoding);
+ }
+
+ return NULL;
+}
+
+GtkSourceNewlineType
+ide_editor_file_chooser_get_line_ending (GtkFileChooser *chooser)
+{
+ const char *ending;
+
+ g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), 0);
+
+ if ((ending = gtk_file_chooser_get_choice (chooser, "line-ending")))
+ {
+ for (guint i = 0; i < G_N_ELEMENTS (line_endings); i++)
+ {
+ if (g_strcmp0 (ending, line_endings[i].id) == 0)
+ return line_endings[i].type;
+ }
+ }
+
+ return GTK_SOURCE_NEWLINE_TYPE_LF;
+}
+
+/**
+ * ide_editor_syntax_menu_new:
+ * @action_name: the action to activate when selecting menu items
+ *
+ * Creates a new #GMenuModel with items which will activate using
+ * their syntax id for the action @action_name target.
+ *
+ * Returns: (transfer full): a #GMenuModel
+ */
+GMenuModel *
+ide_editor_syntax_menu_new (const char *action_name)
+{
+ GtkSourceLanguageManager *manager;
+ const char * const *language_ids;
+ g_autofree char **sections = NULL;
+ GHashTable *submenus;
+ g_autoptr(GMenu) top_section = NULL;
+ GMenu *top_menu;
+ guint len = 0;
+
+ g_return_val_if_fail (action_name, NULL);
+
+ manager = gtk_source_language_manager_get_default ();
+ language_ids = gtk_source_language_manager_get_language_ids (manager);
+ submenus = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
+ top_menu = g_menu_new ();
+ top_section = g_menu_new ();
+
+ g_menu_append_section (top_menu, _("Language"), G_MENU_MODEL (top_section));
+
+ for (guint i = 0; language_ids[i]; i++)
+ {
+ const char *language_id = language_ids[i];
+ GtkSourceLanguage *language = gtk_source_language_manager_get_language (manager, language_id);
+ g_autoptr(GMenuItem) item = NULL;
+ const char *name;
+ const char *section;
+ GMenu *submenu;
+
+ if (gtk_source_language_get_hidden (language))
+ continue;
+
+ name = gtk_source_language_get_name (language);
+ section = gtk_source_language_get_section (language);
+
+ if (!(submenu = g_hash_table_lookup (submenus, section)))
+ {
+ submenu = g_menu_new ();
+ g_hash_table_insert (submenus, (char *)section, submenu);
+ }
+
+ item = g_menu_item_new (name, NULL);
+ g_menu_item_set_action_and_target (item, action_name, "s", language_id);
+ g_menu_append_item (submenu, item);
+ }
+
+ sections = (char **)g_hash_table_get_keys_as_array (submenus, &len);
+ ide_strv_sort ((char **)sections, len);
+
+ for (guint i = 0; sections[i]; i++)
+ {
+ GMenu *submenu = g_hash_table_lookup (submenus, sections[i]);
+ g_menu_append_submenu (top_section, sections[i], G_MENU_MODEL (submenu));
+ }
+
+ g_hash_table_unref (submenus);
+
+ return G_MENU_MODEL (top_menu);
+}
diff --git a/src/libide/editor/ide-editor-utils.h b/src/libide/editor/ide-editor-utils.h
new file mode 100644
index 000000000..f776451e6
--- /dev/null
+++ b/src/libide/editor/ide-editor-utils.h
@@ -0,0 +1,41 @@
+/* ide-editor-utils.h
+ *
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#if !defined (IDE_EDITOR_INSIDE) && !defined (IDE_EDITOR_COMPILATION)
+# error "Only <libide-editor.h> can be included directly."
+#endif
+
+#include <gtksourceview/gtksource.h>
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+void ide_editor_file_chooser_add_encodings (GtkFileChooser *chooser);
+void ide_editor_file_chooser_add_line_endings (GtkFileChooser *chooser,
+ GtkSourceNewlineType selected);
+const GtkSourceEncoding *ide_editor_file_chooser_get_encoding (GtkFileChooser *chooser);
+GtkSourceNewlineType ide_editor_file_chooser_get_line_ending (GtkFileChooser *chooser);
+GMenuModel *ide_editor_encoding_menu_new (const char *action_name);
+GMenuModel *ide_editor_syntax_menu_new (const char *action_name);
+
+G_END_DECLS
diff --git a/src/libide/editor/ide-editor-workspace.c b/src/libide/editor/ide-editor-workspace.c
index 5acb310c8..aaa29c236 100644
--- a/src/libide/editor/ide-editor-workspace.c
+++ b/src/libide/editor/ide-editor-workspace.c
@@ -22,91 +22,253 @@
#include "config.h"
-#include "ide-editor-surface.h"
#include "ide-editor-workspace.h"
+#include "ide-workspace-private.h"
/**
* SECTION:ide-editor-workspace
* @title: IdeEditorWorkspace
- * @short_description: A simplified workspace for dedicated editing
+ * @short_description: The editor IDE window
*
- * The #IdeEditorWorkspace is a secondary workspace that can be used to
- * add additional #IdePage to. It does not contain the full contents of
- * the #IdePrimaryWorkspace. It is suitable for using on an additional
- * monitor as well as a dedicated editor in simplified Builder mode when
- * running directly from the command line.
- *
- * Since: 3.32
+ * The editor workspace is a secondary workspace that may be added to
+ * supplement the IdePrimaryWorkspace for additional editors. It may
+ * also be used in an "editor" mode without a project.
*/
struct _IdeEditorWorkspace
{
- IdeWorkspace parent_instance;
- DzlMenuButton *surface_menu_button;
- DzlShortcutTooltip *search_tooltip;
+ IdeWorkspace parent_instance;
+
+ /* Template widgets */
+ IdeHeaderBar *header_bar;
+ AdwWindowTitle *project_title;
+ GtkMenuButton *add_button;
+ PanelDock *dock;
+ PanelPaned *edge_start;
+ PanelPaned *edge_end;
+ PanelPaned *edge_bottom;
+ IdeGrid *grid;
};
G_DEFINE_FINAL_TYPE (IdeEditorWorkspace, ide_editor_workspace, IDE_TYPE_WORKSPACE)
+static gboolean
+file_to_short_path (GBinding *binding,
+ const GValue *from,
+ GValue *to,
+ gpointer user_data)
+{
+ GFile *file;
+
+ g_assert (G_IS_BINDING (binding));
+ g_assert (G_VALUE_HOLDS (from, G_TYPE_FILE));
+ g_assert (G_VALUE_HOLDS (to, G_TYPE_STRING));
+ g_assert (user_data == NULL);
+
+ if ((file = g_value_get_object (from)))
+ {
+ if (g_file_is_native (file))
+ g_value_take_string (to, ide_path_collapse (g_file_peek_path (file)));
+ else
+ g_value_take_string (to, g_file_get_uri (file));
+ }
+
+ return TRUE;
+}
+
static void
-ide_editor_workspace_surface_set (IdeWorkspace *workspace,
- IdeSurface *surface)
+ide_editor_workspace_context_set (IdeWorkspace *workspace,
+ IdeContext *context)
{
IdeEditorWorkspace *self = (IdeEditorWorkspace *)workspace;
+ IdeProjectInfo *project_info;
+ IdeWorkbench *workbench;
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_EDITOR_WORKSPACE (self));
- g_assert (!surface || IDE_IS_SURFACE (surface));
+ g_assert (IDE_IS_CONTEXT (context));
- if (DZL_IS_DOCK_ITEM (surface))
- {
- g_autofree gchar *icon_name = NULL;
+ IDE_WORKSPACE_CLASS (ide_editor_workspace_parent_class)->context_set (workspace, context);
- icon_name = dzl_dock_item_get_icon_name (DZL_DOCK_ITEM (surface));
- g_object_set (self->surface_menu_button,
- "icon-name", icon_name,
- NULL);
- }
+ workbench = ide_widget_get_workbench (GTK_WIDGET (self));
+ project_info = ide_workbench_get_project_info (workbench);
- IDE_WORKSPACE_CLASS (ide_editor_workspace_parent_class)->surface_set (workspace, surface);
+ if (project_info)
+ g_object_bind_property (project_info, "name",
+ self->project_title, "title",
+ G_BINDING_SYNC_CREATE);
+ g_object_bind_property_full (context, "workdir",
+ self->project_title, "subtitle",
+ G_BINDING_SYNC_CREATE,
+ file_to_short_path, NULL, NULL, NULL);
+}
+
+static void
+ide_editor_workspace_add_page (IdeWorkspace *workspace,
+ IdePage *page,
+ IdePanelPosition *position)
+{
+ IdeEditorWorkspace *self = (IdeEditorWorkspace *)workspace;
+
+ g_assert (IDE_IS_EDITOR_WORKSPACE (self));
+
+ _ide_workspace_add_widget (workspace,
+ PANEL_WIDGET (page),
+ position,
+ self->edge_start,
+ self->edge_end,
+ self->edge_bottom,
+ self->grid);
+}
+
+static void
+ide_editor_workspace_add_pane (IdeWorkspace *workspace,
+ IdePane *pane,
+ IdePanelPosition *position)
+{
+ IdeEditorWorkspace *self = (IdeEditorWorkspace *)workspace;
+
+ g_assert (IDE_IS_EDITOR_WORKSPACE (self));
+
+ _ide_workspace_add_widget (workspace,
+ PANEL_WIDGET (pane),
+ position,
+ self->edge_start,
+ self->edge_end,
+ self->edge_bottom,
+ self->grid);
+}
+
+static void
+ide_editor_workspace_add_grid_column (IdeWorkspace *workspace,
+ guint position)
+{
+ panel_grid_insert_column (PANEL_GRID (IDE_EDITOR_WORKSPACE (workspace)->grid), position);
+}
+
+static IdeFrame *
+ide_editor_workspace_get_most_recent_frame (IdeWorkspace *workspace)
+{
+ IdeEditorWorkspace *self = (IdeEditorWorkspace *)workspace;
+
+ g_assert (IDE_IS_EDITOR_WORKSPACE (self));
+
+ return IDE_FRAME (panel_grid_get_most_recent_frame (PANEL_GRID (self->grid)));
+}
+
+static PanelFrame *
+ide_editor_workspace_get_frame_at_position (IdeWorkspace *workspace,
+ IdePanelPosition *position)
+{
+ IdeEditorWorkspace *self = (IdeEditorWorkspace *)workspace;
+
+ g_assert (IDE_IS_EDITOR_WORKSPACE (self));
+ g_assert (position != NULL);
+
+ return _ide_workspace_find_frame (workspace,
+ position,
+ self->edge_start,
+ self->edge_end,
+ self->edge_bottom,
+ self->grid);
+}
+
+static gboolean
+ide_editor_workspace_can_search (IdeWorkspace *workspace)
+{
+ return TRUE;
+}
+
+static IdeHeaderBar *
+ide_editor_workspace_get_header_bar (IdeWorkspace *workspace)
+{
+ return IDE_EDITOR_WORKSPACE (workspace)->header_bar;
+}
+
+static void
+ide_editor_workspace_foreach_page (IdeWorkspace *workspace,
+ IdePageCallback callback,
+ gpointer user_data)
+{
+ ide_grid_foreach_page (IDE_EDITOR_WORKSPACE (workspace)->grid, callback, user_data);
+}
+
+static void
+ide_editor_workspace_dispose (GObject *object)
+{
+ IdeEditorWorkspace *self = (IdeEditorWorkspace *)object;
+
+ /* Ensure that the grid is removed first so that it will cleanup
+ * addins/pages/etc before we ever get to removing the workspace
+ * addins as part of the parent class.
+ */
+ panel_dock_remove (self->dock, GTK_WIDGET (self->grid));
+ self->grid = NULL;
+
+ G_OBJECT_CLASS (ide_editor_workspace_parent_class)->dispose (object);
}
static void
ide_editor_workspace_class_init (IdeEditorWorkspaceClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
IdeWorkspaceClass *workspace_class = IDE_WORKSPACE_CLASS (klass);
+ object_class->dispose = ide_editor_workspace_dispose;
+
+ workspace_class->add_grid_column = ide_editor_workspace_add_grid_column;
+ workspace_class->add_page = ide_editor_workspace_add_page;
+ workspace_class->add_pane = ide_editor_workspace_add_pane;
+ workspace_class->can_search = ide_editor_workspace_can_search;
+ workspace_class->context_set = ide_editor_workspace_context_set;
+ workspace_class->foreach_page = ide_editor_workspace_foreach_page;
+ workspace_class->get_frame_at_position = ide_editor_workspace_get_frame_at_position;
+ workspace_class->get_header_bar = ide_editor_workspace_get_header_bar;
+ workspace_class->get_most_recent_frame = ide_editor_workspace_get_most_recent_frame;
+
ide_workspace_class_set_kind (workspace_class, "editor");
- workspace_class->surface_set = ide_editor_workspace_surface_set;
+ gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/libide-editor/ide-editor-workspace.ui");
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorWorkspace, add_button);
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorWorkspace, dock);
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorWorkspace, edge_bottom);
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorWorkspace, edge_end);
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorWorkspace, edge_start);
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorWorkspace, grid);
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorWorkspace, header_bar);
+ gtk_widget_class_bind_template_child (widget_class, IdeEditorWorkspace, project_title);
- gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/libide-editor/ui/ide-editor-workspace.ui");
- gtk_widget_class_bind_template_child (widget_class, IdeEditorWorkspace, surface_menu_button);
- gtk_widget_class_bind_template_child (widget_class, IdeEditorWorkspace, search_tooltip);
+ g_type_ensure (IDE_TYPE_GRID);
+ g_type_ensure (IDE_TYPE_NOTIFICATIONS_BUTTON);
+ g_type_ensure (IDE_TYPE_OMNI_BAR);
}
static void
ide_editor_workspace_init (IdeEditorWorkspace *self)
{
+ GMenu *menu;
+
gtk_widget_init_template (GTK_WIDGET (self));
+
+ menu = ide_application_get_menu_by_id (IDE_APPLICATION_DEFAULT, "new-document-menu");
+ gtk_menu_button_set_menu_model (self->add_button, G_MENU_MODEL (menu));
}
/**
* ide_editor_workspace_new:
- * @app: an #IdeApplication
- *
- * Creates a new #IdeEditorWorkspace.
+ * @application: an #IdeApplication such as %IDE_APPLICATION_DEFAULT
*
- * You'll need to add this to a workbench to be functional.
+ * Creates a new #IdeEditorWorkspace
*
* Returns: (transfer full): an #IdeEditorWorkspace
- *
- * Since: 3.32
*/
IdeEditorWorkspace *
-ide_editor_workspace_new (IdeApplication *app)
+ide_editor_workspace_new (IdeApplication *application)
{
+ g_return_val_if_fail (IDE_IS_APPLICATION (application), NULL);
+
return g_object_new (IDE_TYPE_EDITOR_WORKSPACE,
- "application", app,
+ "application", application,
NULL);
}
diff --git a/src/libide/editor/ide-editor-workspace.h b/src/libide/editor/ide-editor-workspace.h
index 48a4472c1..6c5e4c0df 100644
--- a/src/libide/editor/ide-editor-workspace.h
+++ b/src/libide/editor/ide-editor-workspace.h
@@ -24,16 +24,16 @@
# error "Only <libide-editor.h> can be included directly."
#endif
-#include <libide-core.h>
+#include <libide-gui.h>
G_BEGIN_DECLS
#define IDE_TYPE_EDITOR_WORKSPACE (ide_editor_workspace_get_type())
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (IdeEditorWorkspace, ide_editor_workspace, IDE, EDITOR_WORKSPACE, IdeWorkspace)
-IDE_AVAILABLE_IN_3_32
-IdeEditorWorkspace *ide_editor_workspace_new (IdeApplication *app);
+IDE_AVAILABLE_IN_ALL
+IdeEditorWorkspace *ide_editor_workspace_new (IdeApplication *application);
G_END_DECLS
diff --git a/src/libide/editor/ide-editor-workspace.ui b/src/libide/editor/ide-editor-workspace.ui
index baa2436df..4c37571f2 100644
--- a/src/libide/editor/ide-editor-workspace.ui
+++ b/src/libide/editor/ide-editor-workspace.ui
@@ -2,67 +2,80 @@
<interface>
<template class="IdeEditorWorkspace" parent="IdeWorkspace">
<child type="titlebar">
- <object class="IdeHeaderBar">
- <property name="show-close-button">true</property>
- <property name="show-fullscreen-button">false</property>
+ <object class="IdeHeaderBar" id="header_bar">
<property name="menu-id">ide-editor-workspace-menu</property>
- <property name="visible">true</property>
- <child type="primary">
- <object class="IdeSurfacesButton" id="surface_menu_button">
- <property name="focus-on-click">false</property>
- <property name="menu-id">ide-editor-workspace-surfaces-menu</property>
- <property name="show-accels">true</property>
- <property name="show-arrow">true</property>
- <property name="show-icons">true</property>
- <!-- disable transitions since they'll cause jitter with the
- whole surface changing below it. -->
- <property name="transitions-enabled">false</property>
- <property name="has-tooltip">true</property>
- <property name="tooltip-text" translatable="yes">Switch surface</property>
+ <child type="left">
+ <object class="GtkMenuButton" id="add_button">
+ <property name="icon-name">list-add-symbolic</property>
+ <property name="always-show-arrow">true</property>
</object>
</child>
- <child type="secondary">
- <object class="DzlPriorityBox">
- <property name="visible">true</property>
- <child>
- <object class="IdeSearchButton" id="search_button">
- <property name="visible">true</property>
- <child internal-child="entry">
- <object class="DzlSuggestionEntry">
- <property name="max-width-chars">20</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="pack-type">end</property>
- <property name="priority">-200</property>
- </packing>
- </child>
+ <child type="left">
+ <object class="PanelDockSwitcher">
+ <property name="dock">dock</property>
+ <property name="position">start</property>
+ </object>
+ </child>
+ <child type="title">
+ <object class="AdwWindowTitle" id="project_title">
+ <property name="title" translatable="yes">Builder</property>
+ </object>
+ </child>
+ <child type="right">
+ <object class="IdeNotificationsButton" id="notifications_button"/>
+ </child>
+ <child type="right">
+ <object class="GtkButton" id="search_button">
+ <property name="icon-name">edit-find-symbolic</property>
+ </object>
+ </child>
+ <child type="right">
+ <object class="PanelDockSwitcher">
+ <property name="dock">dock</property>
+ <property name="position">end</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="PanelDock" id="dock">
+ <property name="start-width">300</property>
+ <property name="reveal-start">true</property>
+ <property name="vexpand">true</property>
+ <child type="center">
+ <object class="IdeGrid" id="grid">
+ </object>
+ </child>
+ <child type="start">
+ <object class="PanelPaned" id="edge_start">
+ <property name="orientation">vertical</property>
+ </object>
+ </child>
+ <child type="end">
+ <object class="PanelPaned" id="edge_end">
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkRevealer">
- <property name="reveal-child">false</property>
- <property name="transition-type">slide-left</property>
- <property name="visible">true</property>
- <child>
- <object class="IdeNotificationsButton" id="notifications_button">
- <property name="show-theatric">false</property>
- <property name="visible">true</property>
- </object>
- </child>
+ <object class="PanelFrame">
</object>
- <packing>
- <property name="pack-type">end</property>
- <property name="priority">-300</property>
- </packing>
</child>
</object>
</child>
+ <child type="bottom">
+ <object class="PanelPaned" id="edge_bottom">
+ <property name="orientation">horizontal</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child internal-child="statusbar">
+ <object class="PanelStatusbar">
+ <child type="suffix">
+ <object class="PanelDockSwitcher">
+ <property name="dock">dock</property>
+ <property name="position">bottom</property>
+ </object>
+ </child>
</object>
</child>
</template>
- <object class="DzlShortcutTooltip" id="search_tooltip">
- <property name="title" translatable="yes">Search your project</property>
- <property name="command-id">org.gnome.builder.workspace.global-search</property>
- <property name="widget">search_button</property>
- </object>
</interface>
diff --git a/src/libide/editor/ide-editor.c b/src/libide/editor/ide-editor.c
new file mode 100644
index 000000000..64cbf886d
--- /dev/null
+++ b/src/libide/editor/ide-editor.c
@@ -0,0 +1,260 @@
+/* ide-editor.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-editor"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "ide-editor.h"
+#include "ide-editor-page.h"
+
+typedef struct _Focus
+{
+ IdeWorkspace *workspace;
+ IdePanelPosition *position;
+ IdeLocation *location;
+ IdeBuffer *buffer;
+ GFile *file;
+} Focus;
+
+static Focus *
+focus_new (IdeWorkspace *workspace,
+ IdePanelPosition *position,
+ IdeBuffer *buffer,
+ IdeLocation *location)
+{
+ IdeBufferManager *bufmgr;
+ IdeContext *context;
+ Focus *focus;
+ GFile *file = NULL;
+
+ g_assert (IDE_IS_WORKSPACE (workspace));
+ g_assert (position != NULL);
+ g_assert (!buffer || IDE_IS_BUFFER (buffer));
+ g_assert (!location || IDE_IS_LOCATION (location));
+ g_assert (buffer != NULL || location != NULL);
+
+ context = ide_workspace_get_context (workspace);
+ bufmgr = ide_buffer_manager_from_context (context);
+
+ g_assert (IDE_IS_CONTEXT (context));
+ g_assert (IDE_IS_BUFFER_MANAGER (bufmgr));
+
+ if (location != NULL)
+ file = ide_location_get_file (location);
+ else
+ file = ide_buffer_get_file (buffer);
+
+ g_assert (buffer != NULL || file != NULL);
+
+ if (buffer == NULL)
+ buffer = ide_buffer_manager_find_buffer (bufmgr, file);
+
+ focus = g_atomic_rc_box_alloc0 (sizeof *focus);
+ focus->position = ide_panel_position_ref (position);
+ g_set_object (&focus->workspace, workspace);
+ g_set_object (&focus->buffer, buffer);
+ g_set_object (&focus->location, location);
+ g_set_object (&focus->file, file);
+
+ return focus;
+}
+
+static void
+focus_finalize (gpointer data)
+{
+ Focus *focus = data;
+
+ g_clear_object (&focus->workspace);
+ g_clear_object (&focus->location);
+ g_clear_object (&focus->buffer);
+ g_clear_object (&focus->file);
+}
+
+static void
+focus_free (Focus *focus)
+{
+ g_atomic_rc_box_release_full (focus, focus_finalize);
+}
+
+static void
+focus_complete (Focus *focus,
+ const GError *error)
+{
+ IdeEditorPage *page = NULL;
+ PanelFrame *frame;
+
+ IDE_ENTRY;
+
+ g_assert (focus != NULL);
+ g_assert (G_IS_FILE (focus->file));
+ g_assert (!focus->location || IDE_IS_LOCATION (focus->location));
+ g_assert (!focus->buffer || IDE_IS_BUFFER (focus->buffer));
+ g_assert (focus->buffer || error != NULL);
+ g_assert (IDE_IS_WORKSPACE (focus->workspace));
+ g_assert (focus->position != NULL);
+
+ if (error != NULL)
+ {
+ IdeContext *context = ide_workspace_get_context (focus->workspace);
+ ide_context_warning (context,
+ /* translators: %s is replaced with the error message */
+ _("Failed to open file: %s"),
+ error->message);
+ focus_free (focus);
+ IDE_EXIT;
+ }
+
+ frame = ide_workspace_get_frame_at_position (focus->workspace, focus->position);
+
+ if (frame != NULL)
+ {
+ guint n_pages = panel_frame_get_n_pages (PANEL_FRAME (frame));
+
+ for (guint i = 0; i < n_pages; i++)
+ {
+ PanelWidget *child = panel_frame_get_page (PANEL_FRAME (frame), i);
+
+ if (IDE_IS_EDITOR_PAGE (child))
+ {
+ IdeBuffer *buffer = ide_editor_page_get_buffer (IDE_EDITOR_PAGE (child));
+
+ if (buffer == focus->buffer)
+ {
+ page = IDE_EDITOR_PAGE (child);
+ break;
+ }
+ }
+ }
+ }
+
+ g_assert (!page || IDE_IS_EDITOR_PAGE (page));
+
+ if (page == NULL)
+ {
+ page = IDE_EDITOR_PAGE (ide_editor_page_new (focus->buffer));
+ ide_workspace_add_page (focus->workspace, IDE_PAGE (page), focus->position);
+ }
+
+ if (focus->location != NULL)
+ {
+ IdeSourceView *view = ide_editor_page_get_view (page);
+ GtkTextIter iter;
+
+ ide_buffer_get_iter_at_location (focus->buffer, &iter, focus->location);
+ gtk_text_buffer_select_range (GTK_TEXT_BUFFER (focus->buffer), &iter, &iter);
+ ide_source_view_scroll_to_insert (view);
+ }
+
+ if (frame != NULL)
+ panel_frame_set_visible_child (frame, PANEL_WIDGET (page));
+
+ gtk_widget_grab_focus (GTK_WIDGET (page));
+
+ focus_free (focus);
+
+ IDE_EXIT;
+}
+
+static void
+ide_editor_load_file_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeBufferManager *bufmgr = (IdeBufferManager *)object;
+ g_autoptr(IdeBuffer) buffer = NULL;
+ g_autoptr(GError) error = NULL;
+ Focus *focus = user_data;
+
+ g_assert (IDE_IS_BUFFER_MANAGER (bufmgr));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (focus != NULL);
+ g_assert (IDE_IS_WORKSPACE (focus->workspace));
+ g_assert (focus->position != NULL);
+ g_assert (G_IS_FILE (focus->file));
+
+ if ((buffer = ide_buffer_manager_load_file_finish (bufmgr, result, &error)))
+ g_set_object (&focus->buffer, buffer);
+
+ focus_complete (focus, error);
+}
+
+static void
+do_focus (IdeWorkspace *workspace,
+ IdePanelPosition *position,
+ IdeBuffer *buffer,
+ IdeLocation *location)
+{
+ g_autoptr(IdePanelPosition) local_position = NULL;
+ IdeBufferManager *bufmgr;
+ IdeContext *context;
+ Focus *focus;
+
+ g_assert (IDE_IS_WORKSPACE (workspace));
+ g_assert (!buffer || IDE_IS_BUFFER (buffer));
+ g_assert (!location || IDE_IS_LOCATION (location));
+ g_assert (buffer != NULL || location != NULL);
+
+ context = ide_workspace_get_context (workspace);
+ bufmgr = ide_buffer_manager_from_context (context);
+
+ g_assert (IDE_IS_CONTEXT (context));
+ g_assert (IDE_IS_BUFFER_MANAGER (bufmgr));
+
+ if (position == NULL)
+ position = local_position = ide_panel_position_new ();
+
+ focus = focus_new (workspace, position, buffer, location);
+
+ if (focus->buffer == NULL)
+ ide_buffer_manager_load_file_async (bufmgr,
+ focus->file,
+ IDE_BUFFER_OPEN_FLAGS_NONE,
+ NULL,
+ ide_workspace_get_cancellable (workspace),
+ ide_editor_load_file_cb,
+ focus);
+ else
+ focus_complete (focus, NULL);
+}
+
+void
+ide_editor_focus_location (IdeWorkspace *workspace,
+ IdePanelPosition *position,
+ IdeLocation *location)
+{
+ g_return_if_fail (IDE_IS_WORKSPACE (workspace));
+ g_return_if_fail (IDE_IS_LOCATION (location));
+
+ do_focus (workspace, position, NULL, location);
+}
+
+void
+ide_editor_focus_buffer (IdeWorkspace *workspace,
+ IdePanelPosition *position,
+ IdeBuffer *buffer)
+{
+ g_return_if_fail (IDE_IS_WORKSPACE (workspace));
+ g_return_if_fail (IDE_IS_BUFFER (buffer));
+
+ do_focus (workspace, position, buffer, NULL);
+}
diff --git a/src/libide/editor/ide-editor-utilities.h b/src/libide/editor/ide-editor.h
similarity index 61%
rename from src/libide/editor/ide-editor-utilities.h
rename to src/libide/editor/ide-editor.h
index 8893f35ec..a908116de 100644
--- a/src/libide/editor/ide-editor-utilities.h
+++ b/src/libide/editor/ide-editor.h
@@ -1,6 +1,6 @@
-/* ide-editor-utilities.h
+/* ide-editor.h
*
- * Copyright 2017-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2022 Christian Hergert <chergert redhat com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,20 +20,19 @@
#pragma once
-#if !defined (IDE_EDITOR_INSIDE) && !defined (IDE_EDITOR_COMPILATION)
-# error "Only <libide-editor.h> can be included directly."
-#endif
-
#include <libide-core.h>
+#include <libide-code.h>
#include <libide-gui.h>
G_BEGIN_DECLS
-#define IDE_TYPE_EDITOR_UTILITIES (ide_editor_utilities_get_type())
-
-IDE_AVAILABLE_IN_3_32
-G_DECLARE_FINAL_TYPE (IdeEditorUtilities, ide_editor_utilities, IDE, EDITOR_UTILITIES, IdePanel)
-
-/* Use GtkContainer api to add your DzlDockWidget */
+IDE_AVAILABLE_IN_ALL
+void ide_editor_focus_location (IdeWorkspace *workspace,
+ IdePanelPosition *position,
+ IdeLocation *location);
+IDE_AVAILABLE_IN_ALL
+void ide_editor_focus_buffer (IdeWorkspace *workspace,
+ IdePanelPosition *position,
+ IdeBuffer *buffer);
G_END_DECLS
diff --git a/src/libide/editor/libide-editor.gresource.xml b/src/libide/editor/libide-editor.gresource.xml
index 2c390f7e5..8ceb752e9 100644
--- a/src/libide/editor/libide-editor.gresource.xml
+++ b/src/libide/editor/libide-editor.gresource.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
- <gresource prefix="/org/gnome/libide-editor/ui/">
+ <gresource prefix="/org/gnome/libide-editor/">
<file preprocess="xml-stripblanks">ide-editor-page.ui</file>
- <file preprocess="xml-stripblanks">ide-editor-search-bar.ui</file>
- <file preprocess="xml-stripblanks">ide-editor-settings-dialog.ui</file>
- <file preprocess="xml-stripblanks">ide-editor-sidebar.ui</file>
- <file preprocess="xml-stripblanks">ide-editor-surface.ui</file>
<file preprocess="xml-stripblanks">ide-editor-workspace.ui</file>
+ <file preprocess="xml-stripblanks">gtk/menus.ui</file>
+ <file>style.css</file>
</gresource>
</gresources>
diff --git a/src/libide/editor/libide-editor.h b/src/libide/editor/libide-editor.h
index b541f5833..c1d6fe856 100644
--- a/src/libide/editor/libide-editor.h
+++ b/src/libide/editor/libide-editor.h
@@ -1,6 +1,6 @@
/* libide-editor.h
*
- * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2018-2022 Christian Hergert <chergert redhat com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,22 +20,10 @@
#pragma once
-#include <libide-gui.h>
-#include <libide-sourceview.h>
-
-G_BEGIN_DECLS
-
#define IDE_EDITOR_INSIDE
-
-#include "ide-editor-addin.h"
-#include "ide-editor-page.h"
-#include "ide-editor-page-addin.h"
-#include "ide-editor-search.h"
-#include "ide-editor-sidebar.h"
-#include "ide-editor-surface.h"
-#include "ide-editor-utilities.h"
-#include "ide-editor-workspace.h"
-
+# include "ide-editor.h"
+# include "ide-editor-page.h"
+# include "ide-editor-page-addin.h"
+# include "ide-editor-utils.h"
+# include "ide-editor-workspace.h"
#undef IDE_EDITOR_INSIDE
-
-G_END_DECLS
diff --git a/src/libide/editor/meson.build b/src/libide/editor/meson.build
index 808ed784f..c6eb702b8 100644
--- a/src/libide/editor/meson.build
+++ b/src/libide/editor/meson.build
@@ -11,21 +11,16 @@ libide_editor_generated_headers = []
#
libide_editor_public_headers = [
- 'ide-editor-addin.h',
+ 'ide-editor.h',
'ide-editor-page.h',
'ide-editor-page-addin.h',
- 'ide-editor-search.h',
- 'ide-editor-sidebar.h',
- 'ide-editor-surface.h',
- 'ide-editor-utilities.h',
+ 'ide-editor-utils.h',
'ide-editor-workspace.h',
'libide-editor.h',
]
libide_editor_private_headers = [
- 'ide-editor-print-operation.h',
- 'ide-editor-search-bar.h',
- 'ide-editor-settings-dialog.h',
+ 'ide-editor-page-private.h',
]
install_headers(libide_editor_public_headers, subdir: libide_editor_header_subdir)
@@ -35,27 +30,18 @@ install_headers(libide_editor_public_headers, subdir: libide_editor_header_subdi
#
libide_editor_public_sources = [
- 'ide-editor-addin.c',
+ 'ide-editor.c',
'ide-editor-page.c',
'ide-editor-page-addin.c',
- 'ide-editor-search.c',
- 'ide-editor-sidebar.c',
- 'ide-editor-surface.c',
- 'ide-editor-utilities.c',
+ 'ide-editor-utils.c',
'ide-editor-workspace.c',
]
libide_editor_private_sources = [
+ 'ide-editor-init.c',
'ide-editor-page-actions.c',
'ide-editor-page-settings.c',
- 'ide-editor-page-shortcuts.c',
- 'ide-editor-print-operation.c',
- 'ide-editor-search-bar.c',
- 'ide-editor-search-bar-shortcuts.c',
- 'ide-editor-settings-dialog.c',
- 'ide-editor-surface-actions.c',
- 'ide-editor-surface-shortcuts.c',
]
libide_editor_sources += libide_editor_public_sources
@@ -80,11 +66,11 @@ libide_editor_sources += libide_editor_resources
libide_editor_deps = [
libgio_dep,
libgtk_dep,
- libdazzle_dep,
libpeas_dep,
libide_core_dep,
libide_io_dep,
+ libide_plugins_dep,
libide_projects_dep,
libide_search_dep,
libide_sourceview_dep,
@@ -93,7 +79,6 @@ libide_editor_deps = [
]
libide_editor_internal_deps = [
- libpangoft2_dep,
]
#
diff --git a/src/libide/editor/style.css b/src/libide/editor/style.css
new file mode 100644
index 000000000..d958de97d
--- /dev/null
+++ b/src/libide/editor/style.css
@@ -0,0 +1,12 @@
+textview.GtkSourceMap {
+ font-family: BuilderBlocks;
+ font-size: 1.75pt;
+ line-height: 5px;
+ color: alpha(currentColor, 0.75);
+}
+textview.GtkSourceMap:dir(ltr) {
+ border-left: 1px solid @borders;
+}
+textview.GtkSourceMap:dir(rtl) {
+ border-right: 1px solid @borders;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]