Commit 2ecf0279 authored by Lucie Dvorakova's avatar Lucie Dvorakova Committed by Christian Hergert

Retab: convert indetation between tabs and spaces

When pasting code with diffrent indentation style then the one in the
Indentation settings, the indentation style of the inserted code stays the
same.

A new plugin retab has been added. The retab is accessible through the
Selection in the popup menu and converts the indentation style base on the
Indentation setting of the file.

https://bugzilla.gnome.org/show_bug.cgi?id=766266
parent 8b3c156f
......@@ -323,6 +323,7 @@ m4_include([plugins/project-tree/configure.ac])
m4_include([plugins/python-gi-imports-completion/configure.ac])
m4_include([plugins/python-pack/configure.ac])
m4_include([plugins/quick-highlight/configure.ac])
m4_include([plugins/retab/configure.ac])
m4_include([plugins/rust-langserv/configure.ac])
m4_include([plugins/rustup/configure.ac])
m4_include([plugins/support/configure.ac])
......@@ -609,6 +610,7 @@ echo " Python GObject Introspection ......... : ${enable_python_gi_imports_comp
echo " Python Jedi Autocompletion ........... : ${enable_jedi_plugin}"
echo " Python Language Pack ................. : ${enable_python_pack_plugin}"
echo " Quick Highlight ...................... : ${enable_quick_highlight_plugin}"
echo " Retab................................. : ${enable_retab_plugin}"
echo " Rust Language Server ................. : ${enable_rust_langserv_plugin}"
echo " RustUp ............................... : ${enable_rustup_plugin}"
echo " Support .............................. : ${enable_support_plugin}"
......
......@@ -51,6 +51,7 @@ option('with_project_tree', type: 'boolean')
option('with_python_gi_imports_completion', type: 'boolean')
option('with_python_pack', type: 'boolean')
option('with_quick_highlight', type: 'boolean')
option('with_retab', type: 'boolean')
option('with_rust_langserv', type: 'boolean')
option('with_rustup', type: 'boolean')
option('with_support', type: 'boolean')
......
......@@ -34,6 +34,7 @@ SUBDIRS = \
python-gi-imports-completion \
python-pack \
quick-highlight \
retab \
rust-langserv \
rustup \
support \
......
......@@ -45,6 +45,7 @@ subdir('project-tree')
subdir('python-gi-imports-completion')
subdir('python-pack')
subdir('quick-highlight')
subdir('retab')
subdir('rust-langserv')
subdir('rustup')
subdir('support')
......
if ENABLE_RETAB_PLUGIN
DISTCLEANFILES =
BUILT_SOURCES =
CLEANFILES =
EXTRA_DIST = $(plugin_DATA)
plugindir = $(libdir)/gnome-builder/plugins
plugin_LTLIBRARIES = libretab-plugin.la
dist_plugin_DATA = retab.plugin
libretab_plugin_la_SOURCES = \
gbp-retab-plugin.c \
gbp-retab-view-addin.c \
gbp-retab-view-addin.h \
$(NULL)
nodist_libretab_plugin_la_SOURCES = \
gbp-retab-resources.c \
gbp-retab-resources.h
libretab_plugin_la_CFLAGS = $(PLUGIN_CFLAGS)
libretab_plugin_la_LDFLAGS = $(PLUGIN_LDFLAGS)
glib_resources_c = gbp-retab-resources.c
glib_resources_h = gbp-retab-resources.h
glib_resources_xml = gbp-retab.gresource.xml
glib_resources_namespace = gbp_retab
include $(top_srcdir)/build/autotools/Makefile.am.gresources
include $(top_srcdir)/plugins/Makefile.plugin
endif
-include $(top_srcdir)/git.mk
# --enable-retab-plugin=yes/no
AC_ARG_ENABLE([retab-plugin],
[AS_HELP_STRING([--enable-retab-plugin=@<:@yes/no@:>@],
[Build with support for retabing lines.])],
[enable_retab_plugin=$enableval],
[enable_retab_plugin=yes])
# for if ENABLE_RETAB_PLUGIN in Makefile.am
AM_CONDITIONAL(ENABLE_RETAB_PLUGIN, test x$enable_retab_plugin != xno)
# Ensure our makefile is generated by autoconf
AC_CONFIG_FILES([plugins/retab/Makefile])
/* gbp-retab-plugin.c
*
* Copyright (C) 2017 Lucie Charvat <luci.charvat@gmail.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/>.
*/
#include <ide.h>
#include <libpeas/peas.h>
#include "gbp-retab-view-addin.h"
void
peas_register_types (PeasObjectModule *module)
{
peas_object_module_register_extension_type (module,
IDE_TYPE_EDITOR_VIEW_ADDIN,
GBP_TYPE_RETAB_VIEW_ADDIN);
}
/* gbp-retab-view-addin.c
*
* Copyright (C) 2017 Lucie Charvat <luci.charvat@gmail.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/>.
*/
#include <glib.h>
#include <glib/gi18n.h>
#include <gtksourceview/gtksource.h>
#include <ide.h>
#include "sourceview/ide-text-iter.h"
#include "gbp-retab-view-addin.h"
struct _GbpRetabViewAddin
{
GObject parent_instance;
IdeEditorView *editor_view;
};
static void editor_view_addin_iface_init (IdeEditorViewAddinInterface *iface);
G_DEFINE_TYPE_EXTENDED (GbpRetabViewAddin, gbp_retab_view_addin, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (IDE_TYPE_EDITOR_VIEW_ADDIN, editor_view_addin_iface_init))
static gint
get_buffer_range_indent (GtkTextBuffer *buffer,
gint line,
gboolean to_spaces)
{
GtkTextIter iter;
gint indent = 0;
gtk_text_buffer_get_iter_at_line (buffer, &iter, line);
while (!gtk_text_iter_ends_line (&iter) && g_unichar_isspace(gtk_text_iter_get_char (&iter)))
{
gtk_text_iter_forward_char (&iter);
++indent;
}
return indent;
}
/* Removes indent that is mean to be changes and inserts
* tabs and/or spaces insted */
static void
gbp_retab_view_addin_retab (GtkTextBuffer *buffer,
gint line,
gint tab_width,
gint indent,
gboolean to_spaces)
{
g_autoptr(GString) new_indent = g_string_new (NULL);
GtkTextIter iter;
GtkTextIter begin;
GtkTextIter end;
gint tab_num = 0;
gint space_num = 0;
g_assert (GTK_IS_TEXT_BUFFER (buffer));
g_assert (line >= 0 && line < gtk_text_buffer_get_line_count(buffer));
g_assert (tab_width != 0);
g_assert (new_indent != NULL);
gtk_text_buffer_get_iter_at_line (buffer, &iter, line);
while (!gtk_text_iter_ends_line (&iter) && g_unichar_isspace(gtk_text_iter_get_char (&iter)))
{
if (gtk_text_iter_get_char (&iter) == ' ')
++space_num;
else if (gtk_text_iter_get_char (&iter) == '\t')
++tab_num;
gtk_text_iter_forward_char (&iter);
}
if (to_spaces)
{
for (gint tab = 0; tab < tab_num * tab_width; ++tab)
g_string_append_c(new_indent, ' ');
for (gint space = 0; space < space_num; ++space)
g_string_append_c(new_indent, ' ');
}
else
{
for (gint tab = 0; tab < tab_num + (space_num / tab_width); ++tab)
g_string_append_c(new_indent, '\t');
for (gint space = 0; space < space_num % tab_width; ++space)
g_string_append_c(new_indent, ' ');
}
gtk_text_buffer_get_iter_at_line(buffer, &begin, line);
gtk_text_buffer_get_iter_at_line_offset (buffer, &end, line, indent);
gtk_text_buffer_delete (buffer, &begin, &end);
if (new_indent->len)
gtk_text_buffer_insert (buffer, &begin, new_indent->str, new_indent->len);
}
static void
gbp_retab_view_addin_action (GSimpleAction *action,
GVariant *variant,
gpointer user_data)
{
GbpRetabViewAddin *self = GBP_RETAB_VIEW_ADDIN (user_data);
IdeEditorView *editor_view = self->editor_view;
IdeSourceView *source_view;
GtkTextBuffer *buffer;
GtkSourceCompletion *completion;
guint tab_width;
gint start_line;
gint end_line;
gint indent;
GtkTextIter begin;
GtkTextIter end;
gboolean editable;
gboolean to_spaces;
g_assert (G_IS_SIMPLE_ACTION (action));
buffer = GTK_TEXT_BUFFER (ide_editor_view_get_document (editor_view));
source_view = ide_editor_view_get_active_source_view (editor_view);
if (source_view == NULL || !GTK_SOURCE_IS_VIEW (source_view))
return;
editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (source_view));
completion = gtk_source_view_get_completion (GTK_SOURCE_VIEW (source_view));
tab_width = gtk_source_view_get_tab_width(GTK_SOURCE_VIEW (source_view));
to_spaces = gtk_source_view_get_insert_spaces_instead_of_tabs(GTK_SOURCE_VIEW (source_view));
if (!editable)
return;
gtk_text_buffer_get_selection_bounds (buffer, &begin, &end);
gtk_text_iter_order (&begin, &end);
if (!gtk_text_iter_equal (&begin, &end) &&
gtk_text_iter_starts_line (&end))
gtk_text_iter_backward_char (&end);
start_line = gtk_text_iter_get_line (&begin);
end_line = gtk_text_iter_get_line (&end);
gtk_source_completion_block_interactive (completion);
gtk_text_buffer_begin_user_action (buffer);
for (gint line = start_line; line <= end_line; ++line)
{
indent = get_buffer_range_indent (buffer, line, to_spaces);
if (indent > 0)
gbp_retab_view_addin_retab (buffer, line, tab_width, indent, to_spaces);
}
gtk_text_buffer_end_user_action (buffer);
gtk_source_completion_unblock_interactive (completion);
}
static void
gbp_retab_view_addin_load (IdeEditorViewAddin *addin,
IdeEditorView *view)
{
GbpRetabViewAddin *self;
GActionGroup *group;
GSimpleAction *action;
g_assert (GBP_IS_RETAB_VIEW_ADDIN (addin));
g_assert (IDE_IS_EDITOR_VIEW (view));
self = GBP_RETAB_VIEW_ADDIN (addin);
self->editor_view = view;
action = g_simple_action_new ("retab", NULL);
g_signal_connect_object (action, "activate", G_CALLBACK (gbp_retab_view_addin_action), self, 0);
group = gtk_widget_get_action_group (GTK_WIDGET (view), "view");
g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action));
}
static void
gbp_retab_view_addin_unload (IdeEditorViewAddin *addin,
IdeEditorView *view)
{
GActionGroup *group;
g_assert (GBP_IS_RETAB_VIEW_ADDIN (addin));
g_assert (IDE_IS_EDITOR_VIEW (view));
group = gtk_widget_get_action_group (GTK_WIDGET (view), "view");
g_action_map_remove_action (G_ACTION_MAP (group), "retab");
}
static void
gbp_retab_view_addin_class_init (GbpRetabViewAddinClass *klass)
{
}
static void
gbp_retab_view_addin_init (GbpRetabViewAddin *self)
{
}
static void
editor_view_addin_iface_init (IdeEditorViewAddinInterface *iface)
{
iface->load = gbp_retab_view_addin_load;
iface->unload = gbp_retab_view_addin_unload;
}
/* gbp-retab-view-addin.h
*
* Copyright (C) 2017 Lucie Charvat <luci.charvat@gmail.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/>.
*/
#ifndef GBP_RETAB_VIEW_ADDIN_H
#define GBP_RETAB_VIEW_ADDIN_H
G_BEGIN_DECLS
#define GBP_TYPE_RETAB_VIEW_ADDIN (gbp_retab_view_addin_get_type())
G_DECLARE_FINAL_TYPE (GbpRetabViewAddin, gbp_retab_view_addin, GBP, RETAB_VIEW_ADDIN, GObject)
G_END_DECLS
#endif /* GBP_RETAB_VIEW_ADDIN_H */
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/builder/plugins/retab-plugin">
<file>gtk/menus.ui</file>
</gresource>
</gresources>
<?xml version="1.0"?>
<interface>
<menu id="ide-source-view-popup-menu">
<section id="ide-source-view-popup-menu-selection-section">
<submenu id="ide-source-view-popup-menu-selection-submenu">
<section id="ide-source-view-popup-menu-selection-retab-section">
<attribute name="after">ide-source-view-popup-menu-line-section</attribute>
<item>
<attribute name="label" translatable="yes">Retab</attribute>
<attribute name="action">view.retab</attribute>
</item>
</section>
</submenu>
</section>
</menu>
</interface>
if get_option('with_retab')
retab_resources = gnome.compile_resources(
'gbp-retab-resources',
'gbp-retab.gresource.xml',
c_name: 'gbp_retab',
)
retab_sources = [
'gbp-retab-plugin.c',
'gbp-retab-view-addin.c',
'gbp-retab-view-addin.h',
retab_resources[0],
]
shared_module('retab-plugin', retab_sources,
dependencies: plugin_deps,
link_args: plugin_link_args,
link_depends: plugin_link_deps,
install: true,
install_dir: plugindir,
)
install_data('retab.plugin', install_dir: plugindir)
endif
[Plugin]
Module=retab-plugin
Name=Retab
Description=Retab lines with Builder editor.
Authors=Lucie Charvat <luci.charvat@gmail.com>
Copyright=Copyright © 2017 Lucie Charvat
Builtin=true
Hidden=true
Depends=editor
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment