/* ide-indenter.c * * Copyright 2015-2019 Christian Hergert * * 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 . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "ide-indenter" #include "config.h" #include #include "ide-indenter.h" G_DEFINE_INTERFACE (IdeIndenter, ide_indenter, IDE_TYPE_OBJECT) static gchar * ide_indenter_default_format (IdeIndenter *self, GtkTextView *text_view, GtkTextIter *begin, GtkTextIter *end, gint *cursor_offset, GdkEventKey *event) { return NULL; } static gboolean ide_indenter_default_is_trigger (IdeIndenter *self, GdkEventKey *event) { return FALSE; } static void ide_indenter_default_init (IdeIndenterInterface *iface) { iface->format = ide_indenter_default_format; iface->is_trigger = ide_indenter_default_is_trigger; } static gchar * ide_indenter_mimic_source_view (GtkTextView *text_view, GtkTextIter *begin, GtkTextIter *end, gint *cursor_offset, GdkEventKey *event) { GtkTextIter copy_begin; GtkTextIter copy_end; gchar *ret; IDE_ENTRY; g_assert (GTK_IS_TEXT_VIEW (text_view)); g_assert (begin != NULL); g_assert (end != NULL); g_assert (cursor_offset != NULL); g_assert (event != NULL); *cursor_offset = 0; *begin = *end; if (event->keyval != GDK_KEY_Return && event->keyval != GDK_KEY_KP_Enter) IDE_RETURN (NULL); copy_begin = *end; /* We might already be at the beginning of the file */ if (!gtk_text_iter_backward_char (©_begin)) IDE_RETURN (NULL); gtk_text_iter_set_line_offset (©_begin, 0); copy_end = copy_begin; while (g_unichar_isspace (gtk_text_iter_get_char (©_end))) { if (gtk_text_iter_ends_line (©_end) || !gtk_text_iter_forward_char (©_end)) break; } ret = gtk_text_iter_get_slice (©_begin, ©_end); IDE_RETURN (ret); } /** * ide_indenter_format: * @self: (nullable): An #IdeIndenter or %NULL for the fallback * @text_view: a #GtkTextView * @begin: a #GtkTextIter for the beginning region of text to replace. * @end: a #GtkTextIter for the end region of text to replace. * @cursor_offset: (out): The offset in characters from @end to place the * cursor. Negative values are okay. * @event: The #GdkEventKey that triggered the event. * * This function performs an indentation for the key press activated by @event. * The implementation is free to move the @begin and @end iters to swallow * adjacent content. The result, a string, is the contents that will replace * the content inbetween @begin and @end. * * @cursor_offset may be set to jump the cursor starting from @end. Negative * values are allowed. * * If @self is %NULL, the fallback indenter is used, which tries to mimic the * indentation style of #GtkSourceView. * * Returns: (nullable) (transfer full): A string containing the replacement * text, or %NULL. * * Since: 3.32 */ gchar * ide_indenter_format (IdeIndenter *self, GtkTextView *text_view, GtkTextIter *begin, GtkTextIter *end, gint *cursor_offset, GdkEventKey *event) { g_return_val_if_fail (!self || IDE_IS_INDENTER (self), NULL); g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL); g_return_val_if_fail (begin != NULL, NULL); g_return_val_if_fail (end != NULL, NULL); g_return_val_if_fail (cursor_offset != NULL, NULL); g_return_val_if_fail (event != NULL, NULL); if (self == NULL) return ide_indenter_mimic_source_view (text_view, begin, end, cursor_offset, event); else return IDE_INDENTER_GET_IFACE (self)->format (self, text_view, begin, end, cursor_offset, event); } /** * ide_indenter_is_trigger: * @self: (nullable): an #IdeIndenter or %NULL for the fallback * @event: a #GdkEventKey * * Determines if @event should trigger an indentation request. If %TRUE is * returned then ide_indenter_format() will be called. * * If @self is %NULL, the fallback indenter is used, which tries to mimic * the default indentation style of #GtkSourceView. * * Returns: %TRUE if @event should trigger an indentation request. * * Since: 3.32 */ gboolean ide_indenter_is_trigger (IdeIndenter *self, GdkEventKey *event) { g_return_val_if_fail (!self || IDE_IS_INDENTER (self), FALSE); g_return_val_if_fail (event != NULL, FALSE); if (self == NULL) { switch (event->keyval) { case GDK_KEY_KP_Enter: case GDK_KEY_Return: return TRUE; default: return FALSE; } } return IDE_INDENTER_GET_IFACE (self)->is_trigger (self, event); }