[gnome-builder/wip/slaf/beautifier: 4/15] beautifier plugin: initial commit



commit f24d957e54427c4abf100accaa5cd61df6249a19
Author: Sebastien Lafargue <slafargue gnome org>
Date:   Sun Nov 13 15:42:06 2016 +0100

    beautifier plugin: initial commit

 configure.ac                                       |    2 +
 plugins/Makefile.am                                |    1 +
 plugins/beautifier/Makefile.am                     |   65 ++++
 plugins/beautifier/beautifier.plugin               |    8 +
 plugins/beautifier/configure.ac                    |   12 +
 plugins/beautifier/data/c-sharp/config.ini         |   10 +
 plugins/beautifier/data/c-sharp/mono.cfg           |   86 +++++
 plugins/beautifier/data/c/config.ini               |   21 ++
 plugins/beautifier/data/c/gnu-indent.cfg           |   82 +++++
 plugins/beautifier/data/c/k&r.cfg                  |   83 +++++
 plugins/beautifier/data/c/linux-kernel.cfg         |  122 +++++++
 plugins/beautifier/data/d/config.ini               |   11 +
 plugins/beautifier/data/d/d.cfg                    |   83 +++++
 plugins/beautifier/data/global.ini                 |    6 +
 plugins/beautifier/data/objc/config.ini            |   11 +
 plugins/beautifier/data/objc/objc.cfg              |  139 ++++++++
 plugins/beautifier/gb-beautifier-config.c          |  372 +++++++++++++++++++
 plugins/beautifier/gb-beautifier-config.h          |   53 +++
 plugins/beautifier/gb-beautifier-helper.c          |  155 ++++++++
 plugins/beautifier/gb-beautifier-helper.h          |   46 +++
 plugins/beautifier/gb-beautifier-plugin.c          |   30 ++
 plugins/beautifier/gb-beautifier-private.h         |   40 ++
 plugins/beautifier/gb-beautifier-process.c         |  268 ++++++++++++++
 plugins/beautifier/gb-beautifier-process.h         |   43 +++
 plugins/beautifier/gb-beautifier-workbench-addin.c |  374 ++++++++++++++++++++
 plugins/beautifier/gb-beautifier-workbench-addin.h |   32 ++
 plugins/beautifier/gb-beautifier.gresource.xml     |    6 +
 plugins/beautifier/gtk/menus.ui                    |   19 +
 28 files changed, 2180 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 1bb4c67..db17571 100644
--- a/configure.ac
+++ b/configure.ac
@@ -281,6 +281,7 @@ dnl Check for supported plugins
 dnl ***********************************************************************
 m4_include([plugins/autotools/configure.ac])
 m4_include([plugins/autotools-templates/configure.ac])
+m4_include([plugins/beautifier/configure.ac])
 m4_include([plugins/build-tools/configure.ac])
 m4_include([plugins/c-pack/configure.ac])
 m4_include([plugins/cargo/configure.ac])
@@ -597,6 +598,7 @@ echo " Plugins"
 echo ""
 echo "  Autotools ............................ : ${enable_autotools_plugin}"
 echo "  Build Tools .......................... : ${enable_build_tools_plugin}"
+echo "  Beautifier  .......................... : ${enable_beautifier_plugin}"
 echo "  C Language Pack ...................... : ${enable_c_pack_plugin}"
 echo "  Cargo ................................ : ${enable_cargo_plugin}"
 echo "  Clang ................................ : ${enable_clang_plugin}"
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 99fa451..00f8e35 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -1,6 +1,7 @@
 SUBDIRS = \
        autotools \
        autotools-templates \
+       beautifier \
        build-tools \
        c-pack \
        cargo \
diff --git a/plugins/beautifier/Makefile.am b/plugins/beautifier/Makefile.am
new file mode 100644
index 0000000..7844127
--- /dev/null
+++ b/plugins/beautifier/Makefile.am
@@ -0,0 +1,65 @@
+if ENABLE_BEAUTIFIER_PLUGIN
+
+CLEANFILES =
+DISTCLEANFILES =
+BUILT_SOURCES =
+EXTRA_DIST = $(plugin_DATA)
+
+beautifier_cflags =                                                                                  \
+       $(PLUGIN_CFLAGS)                                                                             \
+       -DGB_BEAUTIFIER_PLUGIN_DATADIR="\"$(datadir)/gnome-builder/plugins/beautifier_plugin/data\"" \
+       $(NULL)
+
+plugindir = $(libdir)/gnome-builder/plugins
+plugin_LTLIBRARIES = libbeautifier-plugin.la
+dist_plugin_DATA = beautifier.plugin
+
+libbeautifier_plugin_la_SOURCES =          \
+       gb-beautifier-config.c             \
+       gb-beautifier-config.h             \
+       gb-beautifier-helper.c             \
+       gb-beautifier-helper.h             \
+       gb-beautifier-plugin.c             \
+       gb-beautifier-private.h            \
+       gb-beautifier-process.c            \
+       gb-beautifier-process.h            \
+       gb-beautifier-workbench-addin.c    \
+       gb-beautifier-workbench-addin.h    \
+       $(NULL)
+
+nodist_libbeautifier_plugin_la_SOURCES =   \
+       gb-beautifier-resources.c          \
+       gb-beautifier-resources.h          \
+       $(NULL)
+
+resourcedir = $(datadir)/gnome-builder/plugins/beautifier_plugin
+nobase_resource_DATA =             \
+       data/global.ini            \
+       data/c/config.ini          \
+       data/c/gnu-indent.cfg      \
+       data/c/k&r.cfg             \
+       data/c/linux-kernel.cfg    \
+       data/c-sharp/config.ini    \
+       data/c-sharp/mono.cfg      \
+       data/d/config.ini          \
+       data/d/d.cfg               \
+       data/objc/config.ini       \
+       data/objc/objc.cfg         \
+       $(NULL)
+
+EXTRA_DIST += $(nobase_resource_DATA)
+
+libbeautifier_plugin_la_CFLAGS = $(beautifier_cflags)
+libbeautifier_plugin_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+
+glib_resources_c = gb-beautifier-resources.c
+glib_resources_h = gb-beautifier-resources.h
+glib_resources_xml = gb-beautifier.gresource.xml
+glib_resources_namespace = gb_beautifier
+include $(top_srcdir)/build/autotools/Makefile.am.gresources
+
+include $(top_srcdir)/plugins/Makefile.plugin
+
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/plugins/beautifier/beautifier.plugin b/plugins/beautifier/beautifier.plugin
new file mode 100644
index 0000000..28a4ffa
--- /dev/null
+++ b/plugins/beautifier/beautifier.plugin
@@ -0,0 +1,8 @@
+[Plugin]
+Module=beautifier-plugin
+Name=Code Beautifier
+Description=Beautify code according to profiles
+Authors=Sébastien Lafargue <slafargue gnome org>
+Copyright=Copyright © 2016 Sébastien Lafargue
+Depends=editor
+Builtin=true
diff --git a/plugins/beautifier/configure.ac b/plugins/beautifier/configure.ac
new file mode 100644
index 0000000..d6aa259
--- /dev/null
+++ b/plugins/beautifier/configure.ac
@@ -0,0 +1,12 @@
+# --enable-beautifier-plugin=yes/no
+AC_ARG_ENABLE([beautifier-plugin],
+              [AS_HELP_STRING([--enable-beautifier-plugin=@<:@yes/no@:>@],
+                              [Build with support for beautify code.])],
+              [enable_beautifier_plugin=$enableval],
+              [enable_beautifier_plugin=yes])
+
+# for if ENABLE_BEAUTIFIER_PLUGIN in Makefile.am
+AM_CONDITIONAL(ENABLE_BEAUTIFIER_PLUGIN, test x$enable_beautifier_plugin != xno)
+
+# Ensure our makefile is generated by autoconf
+AC_CONFIG_FILES([plugins/beautifier/Makefile])
diff --git a/plugins/beautifier/data/c-sharp/config.ini b/plugins/beautifier/data/c-sharp/config.ini
new file mode 100644
index 0000000..d931e13
--- /dev/null
+++ b/plugins/beautifier/data/c-sharp/config.ini
@@ -0,0 +1,10 @@
+# C-Sharp/mono language config file
+# Possible commands: uncrustify
+[global]
+
+default = mono.cfg
+
+[mono.cfg]
+
+command = uncrustify
+name = C-sharp uncrustify
diff --git a/plugins/beautifier/data/c-sharp/mono.cfg b/plugins/beautifier/data/c-sharp/mono.cfg
new file mode 100644
index 0000000..0029fdb
--- /dev/null
+++ b/plugins/beautifier/data/c-sharp/mono.cfg
@@ -0,0 +1,86 @@
+#
+# Mono library format
+# https://github.com/uncrustify/uncrustify/blob/master/etc/mono.cfg
+
+indent_with_tabs               = 0             # 1=indent to level only, 2=indent with tabs
+input_tab_size                 = 8             # original tab size
+output_tab_size                        = 8             # new tab size
+indent_columns                 = output_tab_size
+indent_label                   = 2             # pos: absolute col, neg: relative column
+# indent_align_string          = False         # align broken strings
+# indent_brace                 = 0
+indent_func_call_param         = true          # use indent tabstop
+
+nl_enum_brace                  = remove        # "enum {" vs "enum \n {"
+nl_union_brace                 = remove        # "union {" vs "union \n {"
+nl_struct_brace                        = remove        # "struct {" vs "struct \n {"
+nl_do_brace                    = remove        # "do {" vs "do \n {"
+nl_if_brace                    = remove        # "if () {" vs "if () \n {"
+nl_for_brace                   = remove        # "for () {" vs "for () \n {"
+nl_else_brace                  = remove        # "else {" vs "else \n {"
+nl_while_brace                 = remove        # "while () {" vs "while () \n {"
+nl_switch_brace                        = remove        # "switch () {" vs "switch () \n {"
+nl_func_var_def_blk            = 1
+nl_before_case                 = 1
+nl_fcall_brace                 = remove        # "foo() {" vs "foo()\n{"
+nl_fdef_brace                  = add           # "int foo() {" vs "int foo()\n{"
+# nl_after_return                      = TRUE
+nl_brace_while                 = remove
+nl_brace_else                  = add
+nl_squeeze_ifdef               = TRUE
+
+# mod_paren_on_return          = add           # "return 1;" vs "return (1);"
+# mod_full_brace_if            = add           # "if (a) a--;" vs "if (a) { a--; }"
+# mod_full_brace_for           = add           # "for () a--;" vs "for () { a--; }"
+# mod_full_brace_do            = add           # "do a--; while ();" vs "do { a--; } while ();"
+# mod_full_brace_while         = add           # "while (a) a--;" vs "while (a) { a--; }"
+
+sp_before_semi                 = remove
+sp_paren_paren                 = remove        # space between (( and ))
+sp_return_paren                        = remove        # "return (1);" vs "return(1);"
+sp_sizeof_paren                        = remove        # "sizeof (int)" vs "sizeof(int)"
+sp_before_sparen               = force         # "if (" vs "if("
+sp_after_sparen                        = force         # "if () {" vs "if (){"
+sp_after_cast                  = remove        # "(int) a" vs "(int)a"
+sp_inside_braces               = force         # "{ 1 }" vs "{1}"
+sp_inside_braces_struct                = force         # "{ 1 }" vs "{1}"
+sp_inside_braces_enum          = force         # "{ 1 }" vs "{1}"
+sp_inside_paren                        = remove
+sp_inside_fparen               = remove
+sp_inside_sparen               = remove
+sp_inside_square               = remove
+sp_before_square               = add
+#sp_type_func                  = ignore
+sp_assign                      = force
+sp_arith                       = force
+sp_bool                                = force
+sp_compare                     = force
+sp_assign                      = force
+sp_after_comma                 = force
+sp_func_def_paren              = force         # "int foo (){" vs "int foo(){"
+sp_func_call_paren             = force         # "foo (" vs "foo("
+sp_func_proto_paren            = force         # "int foo ();" vs "int foo();"
+
+# align_with_tabs                      = FALSE         # use tabs to align
+# align_on_tabstop             = FALSE         # align on tabstops
+# align_enum_equ_span          = 4
+# align_nl_cont                        = TRUE
+# align_var_def_span           = 2
+# align_var_def_inline         = TRUE
+# align_var_def_star           = TRUE
+# align_var_def_colon          = TRUE
+# align_assign_span            = 1
+# align_struct_init_span               = 3
+# align_var_struct_span                = 3
+# align_right_cmt_span         = 3
+# align_pp_define_span         = 3
+# align_pp_define_gap          = 4
+# align_number_left            = TRUE
+# align_typedef_span           = 5
+# align_typedef_gap            = 3
+
+cmt_star_cont                  = TRUE
+
+eat_blanks_before_close_brace  = TRUE
+eat_blanks_after_open_brace    = TRUE
+
diff --git a/plugins/beautifier/data/c/config.ini b/plugins/beautifier/data/c/config.ini
new file mode 100644
index 0000000..4004cdb
--- /dev/null
+++ b/plugins/beautifier/data/c/config.ini
@@ -0,0 +1,21 @@
+# C language config file
+# Possible commands: uncrustify
+
+[global]
+
+default = gnu-ident.cfg
+
+[gnu-indent.cfg]
+
+command = uncrustify
+name = Gnu identation
+
+[k&r.cfg]
+
+command = uncrustify
+name = Kernighan and Ritchie
+
+[linux-kernel.cfg]
+
+command = uncrustify
+name = Linux Kernel
diff --git a/plugins/beautifier/data/c/gnu-indent.cfg b/plugins/beautifier/data/c/gnu-indent.cfg
new file mode 100644
index 0000000..3f7f76d
--- /dev/null
+++ b/plugins/beautifier/data/c/gnu-indent.cfg
@@ -0,0 +1,82 @@
+#
+# GNU format (sorta)
+# https://github.com/uncrustify/uncrustify/blob/master/etc/gnu-indent.cfg
+
+indent_with_tabs               = 0             # 1=indent to level only, 2=indent with tabs
+input_tab_size                 = 8             # original tab size
+output_tab_size                        = 8             # new tab size
+indent_columns                 = 2
+# indent_label                 = 2             # pos: absolute col, neg: relative column
+indent_align_string            = False         # align broken strings
+indent_brace                   = 2
+
+nl_enum_brace                  = remove        # "enum {" vs "enum \n {"
+nl_union_brace                 = remove        # "union {" vs "union \n {"
+nl_struct_brace                        = remove        # "struct {" vs "struct \n {"
+nl_do_brace                    = add           # "do {" vs "do \n {"
+nl_if_brace                    = add           # "if () {" vs "if () \n {"
+nl_for_brace                   = add           # "for () {" vs "for () \n {"
+nl_else_brace                  = add           # "else {" vs "else \n {"
+nl_while_brace                 = add           # "while () {" vs "while () \n {"
+nl_switch_brace                        = add           # "switch () {" vs "switch () \n {"
+nl_func_var_def_blk            = 1
+nl_before_case                 = 1
+nl_fcall_brace                 = add           # "foo() {" vs "foo()\n{"
+nl_fdef_brace                  = add           # "int foo() {" vs "int foo()\n{"
+# nl_after_return                      = TRUE
+nl_brace_while                 = remove
+nl_brace_else                  = add
+nl_squeeze_ifdef               = TRUE
+
+# mod_paren_on_return          = ignore        # "return 1;" vs "return (1);"
+# mod_full_brace_if            = ignore        # "if (a) a--;" vs "if (a) { a--; }"
+# mod_full_brace_for           = ignore        # "for () a--;" vs "for () { a--; }"
+# mod_full_brace_do            = ignore        # "do a--; while ();" vs "do { a--; } while ();"
+# mod_full_brace_while         = ignore        # "while (a) a--;" vs "while (a) { a--; }"
+
+sp_before_semi                 = remove
+sp_paren_paren                 = remove        # space between (( and ))
+sp_return_paren                        = remove        # "return (1);" vs "return(1);"
+sp_sizeof_paren                        = remove        # "sizeof (int)" vs "sizeof(int)"
+sp_before_sparen               = force         # "if (" vs "if("
+sp_after_sparen                        = force         # "if () {" vs "if (){"
+sp_after_cast                  = remove        # "(int) a" vs "(int)a"
+sp_inside_braces               = force         # "{ 1 }" vs "{1}"
+sp_inside_braces_struct                = force         # "{ 1 }" vs "{1}"
+sp_inside_braces_enum          = force         # "{ 1 }" vs "{1}"
+sp_inside_paren                        = remove
+sp_inside_fparen               = remove
+sp_inside_sparen               = remove
+#sp_type_func                  = ignore
+sp_assign                      = force
+sp_arith                       = force
+sp_bool                                = force
+sp_compare                     = force
+sp_after_comma                 = force
+sp_func_def_paren              = remove        # "int foo (){" vs "int foo(){"
+sp_func_call_paren             = remove        # "foo (" vs "foo("
+sp_func_proto_paren            = remove        # "int foo ();" vs "int foo();"
+
+# align_with_tabs                      = FALSE         # use tabs to align
+# align_on_tabstop             = FALSE         # align on tabstops
+# align_enum_equ_span          = 4
+# align_nl_cont                        = TRUE
+# align_var_def_span           = 2
+# align_var_def_inline         = TRUE
+# align_var_def_star           = TRUE
+# align_var_def_colon          = TRUE
+# align_assign_span            = 1
+# align_struct_init_span               = 3
+# align_var_struct_span                = 3
+# align_right_cmt_span         = 3
+# align_pp_define_span         = 3
+# align_pp_define_gap          = 4
+# align_number_left            = TRUE
+# align_typedef_span           = 5
+# align_typedef_gap            = 3
+
+# cmt_star_cont                        = TRUE
+
+eat_blanks_before_close_brace  = TRUE
+eat_blanks_after_open_brace    = TRUE
+
diff --git a/plugins/beautifier/data/c/k&r.cfg b/plugins/beautifier/data/c/k&r.cfg
new file mode 100644
index 0000000..872de86
--- /dev/null
+++ b/plugins/beautifier/data/c/k&r.cfg
@@ -0,0 +1,83 @@
+#
+# K&R (sort-of)
+# https://github.com/uncrustify/uncrustify/blob/master/etc/kr-indent.cfg
+
+indent_with_tabs               = 2             # 1=indent to level only, 2=indent with tabs
+input_tab_size                 = 8             # original tab size
+output_tab_size                        = 8             # new tab size
+indent_columns                 = output_tab_size
+indent_label                   = 2             # pos: absolute col, neg: relative column
+# indent_align_string          = False         # align broken strings
+# indent_brace                 = 0
+
+nl_enum_brace                  = remove        # "enum {" vs "enum \n {"
+nl_union_brace                 = remove        # "union {" vs "union \n {"
+nl_struct_brace                        = remove        # "struct {" vs "struct \n {"
+nl_do_brace                    = remove        # "do {" vs "do \n {"
+nl_if_brace                    = remove        # "if () {" vs "if () \n {"
+nl_for_brace                   = remove        # "for () {" vs "for () \n {"
+nl_else_brace                  = remove        # "else {" vs "else \n {"
+nl_while_brace                 = remove        # "while () {" vs "while () \n {"
+nl_switch_brace                        = remove        # "switch () {" vs "switch () \n {"
+# nl_func_var_def_blk          = 1
+# nl_before_case                       = 1
+nl_fcall_brace                 = add           # "foo() {" vs "foo()\n{"
+nl_fdef_brace                  = add           # "int foo() {" vs "int foo()\n{"
+# nl_after_return                      = TRUE
+nl_brace_while                 = remove
+nl_brace_else                  = remove
+nl_squeeze_ifdef               = TRUE
+
+# mod_paren_on_return          = add           # "return 1;" vs "return (1);"
+# mod_full_brace_if            = add           # "if (a) a--;" vs "if (a) { a--; }"
+# mod_full_brace_for           = add           # "for () a--;" vs "for () { a--; }"
+# mod_full_brace_do            = add           # "do a--; while ();" vs "do { a--; } while ();"
+# mod_full_brace_while         = add           # "while (a) a--;" vs "while (a) { a--; }"
+
+sp_before_semi                 = remove
+sp_paren_paren                 = remove        # space between (( and ))
+sp_return_paren                        = remove        # "return (1);" vs "return(1);"
+sp_sizeof_paren                        = remove        # "sizeof (int)" vs "sizeof(int)"
+sp_before_sparen               = force         # "if (" vs "if("
+sp_after_sparen                        = force         # "if () {" vs "if (){"
+sp_after_cast                  = remove        # "(int) a" vs "(int)a"
+sp_inside_braces               = force         # "{ 1 }" vs "{1}"
+sp_inside_braces_struct                = force         # "{ 1 }" vs "{1}"
+sp_inside_braces_enum          = force         # "{ 1 }" vs "{1}"
+sp_inside_paren                        = remove        # "( 1 )" vs "(1)"
+sp_inside_fparen               = remove        # "( 1 )" vs "(1)" - functions
+sp_inside_sparen               = remove        # "( 1 )" vs "(1)" - if/for/etc
+# sp_type_func                 = ignore
+sp_assign                      = force
+sp_arith                       = force
+sp_bool                                = force
+sp_compare                     = force
+sp_after_comma                 = force
+sp_func_def_paren              = remove        # "int foo (){" vs "int foo(){"
+sp_func_call_paren             = remove        # "foo (" vs "foo("
+sp_func_proto_paren            = remove        # "int foo ();" vs "int foo();"
+
+# align_with_tabs                      = FALSE         # use tabs to align
+# align_on_tabstop             = FALSE         # align on tabstops
+# align_enum_equ_span          = 4
+# align_nl_cont                        = TRUE
+# align_var_def_span           = 2
+# align_var_def_inline         = TRUE
+# align_var_def_star           = TRUE
+# align_var_def_colon          = TRUE
+# align_assign_span            = 1
+# align_struct_init_span               = 3
+# align_var_struct_span                = 3
+# align_right_cmt_span         = 3
+# align_pp_define_span         = 3
+# align_pp_define_gap          = 4
+# align_number_left            = TRUE
+# align_typedef_span           = 5
+# align_typedef_gap            = 3
+
+# cmt_star_cont                        = TRUE
+
+eat_blanks_before_close_brace  = TRUE
+eat_blanks_after_open_brace    = TRUE
+
+
diff --git a/plugins/beautifier/data/c/linux-kernel.cfg b/plugins/beautifier/data/c/linux-kernel.cfg
new file mode 100644
index 0000000..eb2cd12
--- /dev/null
+++ b/plugins/beautifier/data/c/linux-kernel.cfg
@@ -0,0 +1,122 @@
+#
+# uncrustify config file for the linux kernel
+# https://github.com/uncrustify/uncrustify/blob/master/etc/linux-indent.cfg
+
+indent_with_tabs       = 2             # 1=indent to level only, 2=indent with tabs
+input_tab_size         = 8             # original tab size
+output_tab_size                = 8             # new tab size
+indent_columns         = output_tab_size
+
+indent_label           = 1             # pos: absolute col, neg: relative column
+
+
+#
+# inter-symbol newlines
+#
+
+nl_enum_brace          = remove        # "enum {" vs "enum \n {"
+nl_union_brace         = remove        # "union {" vs "union \n {"
+nl_struct_brace                = remove        # "struct {" vs "struct \n {"
+nl_do_brace            = remove        # "do {" vs "do \n {"
+nl_if_brace            = remove        # "if () {" vs "if () \n {"
+nl_for_brace           = remove        # "for () {" vs "for () \n {"
+nl_else_brace          = remove        # "else {" vs "else \n {"
+nl_while_brace                 = remove        # "while () {" vs "while () \n {"
+nl_switch_brace        = remove        # "switch () {" vs "switch () \n {"
+nl_brace_while         = remove        # "} while" vs "} \n while" - cuddle while
+nl_brace_else          = remove        # "} else" vs "} \n else" - cuddle else
+sp_brace_else          = force
+sp_else_brace          = force
+nl_func_var_def_blk    = 1
+nl_fcall_brace         = remove        # "list_for_each() {" vs "list_for_each()\n{"
+nl_fdef_brace          = add           # "int foo() {" vs "int foo()\n{"
+nl_after_label_colon   = true          # "fail:\nfree(foo);" vs "fail: free(foo);"
+# nl_after_return              = TRUE;
+# nl_before_case       = 1
+
+
+#
+# Source code modifications
+#
+
+mod_paren_on_return    = remove        # "return 1;" vs "return (1);"
+#mod_full_brace_if     = remove        # "if (a) a--;" vs "if (a) { a--; }"
+mod_full_brace_if_chain        = true
+mod_full_brace_for     = remove        # "for () a--;" vs "for () { a--; }"
+mod_full_brace_do      = remove        # "do a--; while ();" vs "do { a--; } while ();"
+mod_full_brace_while   = remove        # "while (a) a--;" vs "while (a) { a--; }"
+mod_full_brace_nl      = 3             # don't remove if more than 3 newlines
+
+
+#
+# inter-character spacing options
+#
+
+sp_return_paren                = force         # "return (1);" vs "return(1);"
+sp_sizeof_paren                = remove        # "sizeof (int)" vs "sizeof(int)"
+sp_before_sparen       = force         # "if (" vs "if("
+sp_after_sparen                = force         # "if () {" vs "if (){"
+sp_after_cast          = remove        # "(int) a" vs "(int)a"
+sp_inside_braces       = force         # "{ 1 }" vs "{1}"
+sp_inside_braces_struct        = force # "{ 1 }" vs "{1}"
+sp_inside_braces_enum  = force # "{ 1 }" vs "{1}"
+sp_assign              = force
+sp_arith               = force
+sp_bool                        = force
+sp_compare             = force
+sp_assign              = force
+sp_after_comma         = force
+sp_func_def_paren      = remove        # "int foo (){" vs "int foo(){"
+sp_func_call_paren     = remove        # "foo (" vs "foo("
+sp_func_proto_paren    = remove        # "int foo ();" vs "int foo();"
+
+
+#
+# Aligning stuff
+#
+
+align_with_tabs                = TRUE          # use tabs to align
+align_on_tabstop       = TRUE          # align on tabstops
+# align_keep_tabs              = true
+align_enum_equ_span    = 4             # '=' in enum definition
+# align_nl_cont                = TRUE
+# align_var_def_span   = 2
+# align_var_def_inline = TRUE
+# align_var_def_star   = FALSE
+# align_var_def_colon  = TRUE
+# align_assign_span    = 1
+align_struct_init_span = 3             # align stuff in a structure init '= { }'
+align_right_cmt_span   = 3
+# align_pp_define_span = 8;
+# align_pp_define_gap  = 4;
+
+cmt_star_cont = true
+
+# indent_brace         = 0
+
+nl_func_paren = remove
+nl_func_decl_start = remove
+nl_func_decl_empty = remove
+nl_func_decl_args = remove
+nl_func_decl_end = remove
+sp_inside_paren = remove
+sp_inside_square = remove
+sp_inside_paren_cast = remove
+sp_inside_fparen = remove
+sp_inside_sparen = remove
+sp_paren_paren = remove
+sp_before_ptr_star = force
+sp_after_ptr_star = remove
+sp_between_ptr_star = remove
+align_func_params = true
+align_var_struct_span = 6
+
+eat_blanks_after_open_brace   = true
+eat_blanks_before_close_brace = true
+pp_indent = remove
+
+nl_start_of_file   = remove
+nl_end_of_file     = force
+nl_end_of_file_min = 1
+nl_comment_func_def = 1
+
diff --git a/plugins/beautifier/data/d/config.ini b/plugins/beautifier/data/d/config.ini
new file mode 100644
index 0000000..12e4f5c
--- /dev/null
+++ b/plugins/beautifier/data/d/config.ini
@@ -0,0 +1,11 @@
+# D language config file
+# Possible commands: uncrustify
+
+[global]
+
+default = d.cfg
+
+[d.cfg]
+
+command = uncrustify
+name = D uncrustify
diff --git a/plugins/beautifier/data/d/d.cfg b/plugins/beautifier/data/d/d.cfg
new file mode 100644
index 0000000..da8cb5d
--- /dev/null
+++ b/plugins/beautifier/data/d/d.cfg
@@ -0,0 +1,83 @@
+#
+# My favorite format
+# https://github.com/uncrustify/uncrustify/blob/master/etc/d.cfg
+
+indent_with_tabs               = 0             # 1=indent to level only, 2=indent with tabs
+input_tab_size                 = 8             # original tab size
+output_tab_size                        = 4             # new tab size
+indent_columns                 = output_tab_size
+indent_label                   = 2             # pos: absolute col, neg: relative column
+indent_align_string            = False         # align broken strings
+indent_brace                   = 0
+
+nl_enum_brace                  = add           # "enum {" vs "enum \n {"
+nl_union_brace                 = add           # "union {" vs "union \n {"
+nl_struct_brace                        = add           # "struct {" vs "struct \n {"
+nl_do_brace                    = add           # "do {" vs "do \n {"
+nl_if_brace                    = add           # "if () {" vs "if () \n {"
+nl_for_brace                   = add           # "for () {" vs "for () \n {"
+nl_else_brace                  = add           # "else {" vs "else \n {"
+nl_while_brace                 = add           # "while () {" vs "while () \n {"
+nl_switch_brace                        = add           # "switch () {" vs "switch () \n {"
+# nl_func_var_def_blk          = 1
+# nl_before_case                       = 1
+nl_fcall_brace                 = add           # "foo() {" vs "foo()\n{"
+nl_fdef_brace                  = add           # "int foo() {" vs "int foo()\n{"
+# nl_after_return                      = TRUE
+nl_brace_while                 = remove
+nl_brace_else                  = add
+nl_squeeze_ifdef               = TRUE
+
+# mod_paren_on_return          = add           # "return 1;" vs "return (1);"
+# mod_full_brace_if            = add           # "if (a) a--;" vs "if (a) { a--; }"
+# mod_full_brace_for           = add           # "for () a--;" vs "for () { a--; }"
+# mod_full_brace_do            = add           # "do a--; while ();" vs "do { a--; } while ();"
+# mod_full_brace_while         = add           # "while (a) a--;" vs "while (a) { a--; }"
+
+sp_before_semi                 = remove
+sp_paren_paren                 = remove        # space between (( and ))
+sp_return_paren                        = remove        # "return (1);" vs "return(1);"
+sp_sizeof_paren                        = remove        # "sizeof (int)" vs "sizeof(int)"
+sp_before_sparen               = force         # "if (" vs "if("
+sp_after_sparen                        = force         # "if () {" vs "if (){"
+sp_after_cast                  = add           # "(int) a" vs "(int)a"
+sp_inside_braces               = force         # "{ 1 }" vs "{1}"
+sp_inside_braces_struct                = force         # "{ 1 }" vs "{1}"
+sp_inside_braces_enum          = force         # "{ 1 }" vs "{1}"
+sp_inside_paren                        = remove
+sp_inside_fparen               = remove
+sp_inside_sparen               = remove
+#sp_type_func                  = ignore
+sp_assign                      = force
+sp_arith                       = force
+sp_bool                                = force
+sp_compare                     = force
+sp_assign                      = force
+sp_after_comma                 = force
+sp_func_def_paren              = remove        # "int foo (){" vs "int foo(){"
+sp_func_call_paren             = remove        # "foo (" vs "foo("
+sp_func_proto_paren            = remove        # "int foo ();" vs "int foo();"
+
+align_with_tabs                        = FALSE         # use tabs to align
+align_on_tabstop               = FALSE         # align on tabstops
+align_enum_equ_span            = 4
+align_nl_cont                  = TRUE
+align_var_def_span             = 2
+align_var_def_inline           = TRUE
+align_var_def_star_style       = 1
+align_var_def_colon            = TRUE
+align_assign_span              = 1
+align_struct_init_span         = 3
+align_var_struct_span          = 3
+align_right_cmt_span           = 3
+align_pp_define_span           = 3
+align_pp_define_gap            = 4
+align_number_left              = TRUE
+align_typedef_span             = 5
+align_typedef_gap              = 3
+
+# cmt_star_cont                        = TRUE
+
+eat_blanks_before_close_brace  = TRUE
+eat_blanks_after_open_brace    = TRUE
+
diff --git a/plugins/beautifier/data/global.ini b/plugins/beautifier/data/global.ini
new file mode 100644
index 0000000..b7e1280
--- /dev/null
+++ b/plugins/beautifier/data/global.ini
@@ -0,0 +1,6 @@
+# map lang_id to another lang_id
+[chdr]
+
+map = c
+default = k&r.cfg
+
diff --git a/plugins/beautifier/data/objc/config.ini b/plugins/beautifier/data/objc/config.ini
new file mode 100644
index 0000000..debd875
--- /dev/null
+++ b/plugins/beautifier/data/objc/config.ini
@@ -0,0 +1,11 @@
+# Objective C language config file
+# Possible commands: uncrustify
+
+[global]
+
+default = objc.cfg
+
+[objc.cfg]
+
+command = uncrustify
+name = Objective C uncrustify
diff --git a/plugins/beautifier/data/objc/objc.cfg b/plugins/beautifier/data/objc/objc.cfg
new file mode 100644
index 0000000..2dd1eaf
--- /dev/null
+++ b/plugins/beautifier/data/objc/objc.cfg
@@ -0,0 +1,139 @@
+#
+# uncrustify config file for objective-c and objective-c++
+# https://github.com/uncrustify/uncrustify/blob/master/etc/objc.cfg
+
+indent_with_tabs        = 0     # 1=indent to level only, 2=indent with tabs
+output_tab_size         = 4     # new tab size
+indent_columns          = output_tab_size
+indent_label            = 2     # pos: absolute col, neg: relative column
+indent_align_assign     = FALSE
+
+#
+# Indenting
+#
+
+# indent_brace          = 0
+indent_switch_case      = indent_columns
+
+#
+# Inter-symbol newlines
+#
+
+nl_enum_brace         = remove   # "enum {" vs "enum \n {"
+nl_union_brace        = remove   # "union {" vs "union \n {"
+nl_struct_brace       = remove   # "struct {" vs "struct \n {"
+nl_do_brace           = remove   # "do {" vs "do \n {"
+nl_if_brace           = remove   # "if () {" vs "if () \n {"
+nl_for_brace          = remove   # "for () {" vs "for () \n {"
+nl_else_brace         = remove   # "else {" vs "else \n {"
+nl_while_brace        = remove   # "while () {" vs "while () \n {"
+nl_switch_brace       = remove   # "switch () {" vs "switch () \n {"
+nl_brace_while        = remove   # "} while" vs "} \n while" - cuddle while
+nl_brace_else         = remove   # "} else" vs "} \n else" - cuddle else
+nl_func_var_def_blk   = 1
+nl_fcall_brace        = remove   # "list_for_each() {" vs "list_for_each()\n{"
+nl_fdef_brace         = remove   # "int foo() {" vs "int foo()\n{"
+# nl_after_return     = TRUE;
+# nl_before_case      = 1
+
+
+#
+# Source code modifications
+#
+
+mod_paren_on_return                       = ignore # "return 1;" vs "return (1);"
+mod_full_brace_if                         = ignore    # "if (a) a--;" vs "if (a) { a--; }"
+mod_full_brace_for                        = add       # "for () a--;" vs "for () { a--; }"
+mod_full_brace_do                         = ignore # "do a--; while ();" vs "do { a--; } while ();"
+mod_full_brace_while                      = remove # "while (a) a--;" vs "while (a) { a--; }"
+mod_full_brace_nl                         = 3          # don't remove if more than 3 newlines
+mod_add_long_ifdef_endif_comment          = 20
+mod_add_long_ifdef_else_comment           = mod_add_long_ifdef_endif_comment
+mod_add_long_switch_closebrace_comment    = mod_add_long_ifdef_endif_comment
+mod_add_long_function_closebrace_comment  = mod_add_long_ifdef_endif_comment
+
+#
+# Inter-character spacing options
+#
+
+# sp_return_paren         = force      # "return (1);" vs "return(1);"
+sp_sizeof_paren              = remove  # "sizeof (int)" vs "sizeof(int)"
+sp_before_sparen             = force      # "if (" vs "if("
+sp_after_sparen              = force      # "if () {" vs "if (){"
+sp_after_cast                = remove  # "(int) a" vs "(int)a"
+sp_inside_braces             = add     # "{ 1 }" vs "{1}"
+sp_inside_braces_struct      = add     # "{ 1 }" vs "{1}"
+sp_inside_braces_enum        = add     # "{ 1 }" vs "{1}"
+sp_inside_fparen             = remove    # "func( param )" vs "func(param)"
+sp_paren_brace               = force
+sp_assign                    = add
+sp_arith                     = add
+sp_bool                      = add
+sp_compare                   = add
+sp_after_comma               = add
+sp_func_def_paren            = remove  # "int foo (){" vs "int foo(){"
+sp_func_call_paren           = remove  # "foo (" vs "foo("
+sp_func_proto_paren          = remove  # "int foo ();" vs "int foo();"
+sp_before_ptr_star           = force
+sp_after_ptr_star            = force
+sp_before_unnamed_ptr_star   = ignore
+sp_between_ptr_star          = remove
+sp_after_ptr_star_func       = force
+sp_before_ptr_star_func      = force
+sp_cmt_cpp_start             = add
+sp_cond_question             = force
+sp_cond_colon                = force
+sp_else_brace                = force
+sp_brace_else                = force
+sp_after_class_colon         = force
+sp_before_class_colon        = force
+sp_before_case_colon         = remove
+# Objective-C specifics
+sp_before_oc_colon           = remove
+sp_after_oc_colon            = remove
+sp_after_oc_scope            = force
+sp_after_oc_type             = remove
+sp_after_oc_return_type      = force
+sp_before_send_oc_colon      = remove
+sp_after_send_oc_colon       = remove
+sp_after_oc_at_sel           = remove
+sp_before_oc_block_caret     = ignore
+sp_after_oc_block_caret      = remove
+
+#
+# Aligning stuff
+#
+
+align_with_tabs               = False     # use tabs to align
+align_on_tabstop              = False     # align on tabstops
+# align_keep_tabs             = True
+align_enum_equ_span           = 4         # '=' in enum definition
+# align_nl_cont               = True
+# align_var_def_span          = 2
+# align_var_def_inline        = True
+# align_var_def_star          = False
+# align_var_def_colon         = True
+# align_assign_span           = 1
+align_struct_init_span        = 4         # align stuff in a structure init '= { }'
+align_right_cmt_span          = 8
+align_right_cmt_gap           = 8
+align_pp_define_span          = 8
+#align_pp_define_gap          = 8
+align_oc_msg_colon_span       = 1         # align parameters in an Obj-C message on the ':' but stop after 
this many lines (0=don't align)
+align_oc_msg_spec_span        = 0         # the span for aligning ObjC msg spec (0=don't align)
+
+#
+# Line Splitting options
+#
+
+# ls_func_split_full          = True     # Whether to fully split long function protos/calls at commas
+
+#
+# Comment modifications
+#
+
+cmt_star_cont                 = True     # Whether to put a star on subsequent comment lines
+
+
+
+
diff --git a/plugins/beautifier/gb-beautifier-config.c b/plugins/beautifier/gb-beautifier-config.c
new file mode 100644
index 0000000..c8f627d
--- /dev/null
+++ b/plugins/beautifier/gb-beautifier-config.c
@@ -0,0 +1,372 @@
+/* gb-beautifier-config.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * 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 "gb-beautifier-private.h"
+#include "gb-beautifier-config.h"
+
+static void
+config_entry_clear_func (gpointer data)
+{
+  GbBeautifierConfigEntry *entry = (GbBeautifierConfigEntry *)data;
+
+  g_assert (entry != NULL);
+
+  g_object_unref (entry->file);
+  g_free (entry->name);
+  g_free (entry->lang_id);
+}
+
+static void
+map_entry_clear_func (gpointer data)
+{
+  GbBeautifierMapEntry *entry = (GbBeautifierMapEntry *)data;
+
+  g_assert (entry != NULL);
+
+  g_free (entry->lang_id);
+  g_free (entry->default_profile);
+}
+
+static gboolean
+gb_beautifier_config_check_duplicates (GbBeautifierWorkbenchAddin *self,
+                                       GArray                     *entries,
+                                       const gchar                *lang_id,
+                                       const gchar                *display_name)
+{
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (entries != NULL);
+  g_assert (!ide_str_empty0 (lang_id));
+  g_assert (!ide_str_empty0 (display_name));
+
+  for (gint i = 0; i < entries->len; ++i)
+    {
+      GbBeautifierConfigEntry *entry = &g_array_index (entries, GbBeautifierConfigEntry, i);
+
+      /* Check for a NULL element at the array end */
+      if (entry->file == NULL)
+        break;
+
+      if (0 == g_strcmp0 (entry->lang_id, lang_id) &&
+          0 == g_strcmp0 (entry->name, display_name))
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+gb_beautifier_map_check_duplicates (GbBeautifierWorkbenchAddin *self,
+                                    GArray                     *map,
+                                    const gchar                *lang_id)
+{
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (map != NULL);
+  g_assert (!ide_str_empty0 (lang_id));
+
+  for (gint i = 0; i < map->len; ++i)
+    {
+      GbBeautifierMapEntry *entry = &g_array_index (map, GbBeautifierMapEntry, i);
+
+      /* Check for a NULL element at the array end */
+      if (entry->lang_id == NULL)
+        break;
+
+      if (0 == g_strcmp0 (entry->lang_id, lang_id))
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+add_entries_from_config_ini_file (GbBeautifierWorkbenchAddin *self,
+                                  const gchar                *base_path,
+                                  const gchar                *lang_id,
+                                  const gchar                *real_lang_id,
+                                  GArray                     *entries,
+                                  const gchar                *map_default,
+                                  gboolean                    is_from_map)
+{
+  g_autoptr(GKeyFile) key_file = NULL;
+  g_autofree gchar *ini_path = NULL;
+  g_auto(GStrv) profiles = NULL;
+  g_autofree gchar *default_profile = NULL;
+  GbBeautifierConfigEntry entry;
+  gsize nb_profiles;
+  GError *error = NULL;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (!ide_str_empty0 (base_path));
+  g_assert (!ide_str_empty0 (lang_id));
+  g_assert (!ide_str_empty0 (real_lang_id));
+  g_assert (entries != NULL);
+
+  key_file = g_key_file_new ();
+  ini_path = g_build_filename (base_path, real_lang_id, "config.ini", NULL);
+  if (!g_key_file_load_from_file (key_file, ini_path, G_KEY_FILE_NONE, &error))
+    return FALSE;
+
+  if (map_default != NULL)
+    default_profile = g_strdup (map_default);
+
+  if (NULL != (profiles = g_key_file_get_groups (key_file, &nb_profiles)))
+    {
+      for (gint i = 0; i < nb_profiles; ++i)
+        {
+          g_autofree gchar *display_name = NULL;
+          g_autofree gchar *command = NULL;
+          gchar *profile;
+
+          profile = profiles [i];
+          if (0 == g_strcmp0 (profile, "global"))
+            {
+              if (!is_from_map && default_profile == NULL)
+                default_profile = g_key_file_get_string (key_file, profile, "default", &error);
+
+              continue;
+            }
+
+          if (NULL == (display_name = g_key_file_get_string (key_file, profile, "name", &error)))
+            goto fail;
+
+          if (gb_beautifier_config_check_duplicates (self, entries, lang_id, display_name))
+            continue;
+
+          if ( NULL != (command = g_key_file_get_string (key_file, profile, "command", &error)))
+            {
+              g_autoptr(GFile) file = NULL;
+              g_autofree gchar *file_path = NULL;
+
+              if (0 == g_strcmp0 (command, "uncrustify"))
+                {
+                  g_clear_pointer (&command, g_free);
+                  entry.command = GB_BEAUTIFIER_CONFIG_COMMAND_UNCRUSTIFY;
+                }
+              else
+                goto fail;
+
+              file_path = g_build_filename (base_path, real_lang_id, profile, NULL);
+              file = g_file_new_for_path (file_path);
+              if (g_file_query_exists (file, NULL))
+                {
+                  entry.name = g_steal_pointer (&display_name);
+                  entry.file = g_steal_pointer (&file);
+                  entry.lang_id = g_strdup (lang_id);
+
+                  if (0 == g_strcmp0 (default_profile, profile))
+                    {
+                      entry.is_default = TRUE;
+                      g_clear_pointer (&default_profile, g_free);
+                    }
+                  else
+                    entry.is_default = FALSE;
+
+                  g_array_append_val (entries, entry);
+                }
+              else
+                g_warning ("Can't find \"%s\"", file_path);
+            }
+          else
+             goto fail;
+        }
+    }
+
+  return TRUE;
+
+fail:
+  g_warning ("\"%s\"", error->message);
+
+  return FALSE;
+}
+
+static gboolean
+is_a_lang_id (GbBeautifierWorkbenchAddin *self,
+              const gchar                *lang_id)
+{
+  GtkSourceLanguageManager *lang_manager;
+  const gchar * const * lang_ids = NULL;
+
+  lang_manager = gtk_source_language_manager_get_default ();
+  lang_ids = gtk_source_language_manager_get_language_ids (lang_manager);
+
+  return g_strv_contains (lang_ids, lang_id);
+}
+
+static gboolean
+add_entries_from_base_path (GbBeautifierWorkbenchAddin *self,
+                            const gchar                *base_path,
+                            GArray                     *entries,
+                            GArray                     *map)
+{
+  g_autoptr(GFileEnumerator) enumerator = NULL;
+  g_autoptr(GFile) parent_file = NULL;
+  GFileInfo *child_info;
+  GError *error = NULL;
+  gboolean ret = FALSE;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (!ide_str_empty0 (base_path));
+  g_assert (entries != NULL);
+  g_assert (map != NULL);
+
+  parent_file = g_file_new_for_path (base_path);
+  if (NULL == (enumerator = g_file_enumerate_children (parent_file,
+                                                       G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME","
+                                                       G_FILE_ATTRIBUTE_STANDARD_TYPE,
+                                                       G_FILE_QUERY_INFO_NONE,
+                                                       NULL,
+                                                       &error)))
+    {
+      g_warning ("\"%s\"", error->message);
+      return FALSE;
+    }
+
+  while ((child_info = g_file_enumerator_next_file (enumerator, NULL, &error)))
+    {
+      g_autoptr(GFileInfo) info = child_info;
+      GFileType type;
+      GbBeautifierMapEntry *entry;
+      const gchar *real_lang_id;
+
+      type = g_file_info_get_file_type (info);
+      if (type == G_FILE_TYPE_DIRECTORY)
+        {
+          real_lang_id = g_file_info_get_display_name (info);
+          if (is_a_lang_id (self, real_lang_id) &&
+              add_entries_from_config_ini_file (self, base_path, real_lang_id, real_lang_id, entries, NULL, 
FALSE))
+            ret = TRUE;
+
+          for (gint i = 0; i < map->len; ++i)
+            {
+              entry = &g_array_index (map, GbBeautifierMapEntry, i);
+              if (0 == g_strcmp0 (entry->profile, real_lang_id) &&
+                  add_entries_from_config_ini_file (self, base_path, entry->lang_id, real_lang_id, entries, 
entry->default_profile, TRUE))
+                ret = TRUE;
+            }
+        }
+    }
+
+  if (error != NULL)
+    g_warning ("\"%s\"", error->message);
+
+  return ret;
+}
+
+static GArray *
+gb_beautifier_config_get_map (GbBeautifierWorkbenchAddin *self,
+                              const gchar                *path)
+{
+  GArray *map;
+  g_autofree gchar *file_name = NULL;
+  g_autoptr(GKeyFile) key_file = NULL;
+  g_auto(GStrv) lang_ids = NULL;
+  gsize nb_lang_ids;
+  GError *error = NULL;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (!ide_str_empty0 (path));
+
+  map = g_array_new (TRUE, TRUE, sizeof (GbBeautifierMapEntry));
+  g_array_set_clear_func (map, map_entry_clear_func);
+  file_name = g_build_filename (path,
+                                "global.ini",
+                                NULL);
+
+  key_file = g_key_file_new ();
+  if (g_key_file_load_from_file (key_file, file_name, G_KEY_FILE_NONE, &error) &&
+      NULL != (lang_ids = g_key_file_get_groups (key_file, &nb_lang_ids)))
+    {
+      for (gint i = 0; i < nb_lang_ids; ++i)
+        {
+          g_autofree gchar *profile = NULL;
+          g_autofree gchar *default_profile = NULL;
+          GbBeautifierMapEntry entry;
+          gchar *lang_id = lang_ids [i];
+
+          if (!is_a_lang_id (self, lang_id) ||
+              NULL == (profile = g_key_file_get_string (key_file, lang_id, "map", &error)))
+            continue;
+
+          if (gb_beautifier_map_check_duplicates (self, map, lang_id))
+            continue;
+
+          default_profile = g_key_file_get_string (key_file, lang_id, "default", &error);
+
+          entry.lang_id = g_strdup (lang_id);
+          entry.profile = g_steal_pointer (&profile);
+          entry.default_profile = g_steal_pointer (&default_profile);
+          g_array_append_val (map, entry);
+        }
+    }
+
+  return map;
+}
+
+GArray *
+gb_beautifier_config_get_entries (GbBeautifierWorkbenchAddin *self)
+{
+  IdeContext *context;
+  IdeVcs *vcs;
+  GArray *entries;
+  GArray *map = NULL;
+  g_autofree gchar *project_config_path = NULL;
+  g_autofree gchar *user_config_path = NULL;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+
+  entries = g_array_new (TRUE, TRUE, sizeof (GbBeautifierConfigEntry));
+  g_array_set_clear_func (entries, config_entry_clear_func);
+
+  /* User wide config: ~/.config/gnome-builder/beautifier_plugin */
+  user_config_path = g_build_filename (g_get_user_config_dir (),
+                                       ide_get_program_name (),
+                                       "beautifier_plugin",
+                                       NULL);
+  map = gb_beautifier_config_get_map (self, user_config_path);
+  add_entries_from_base_path (self, user_config_path, entries, map);
+  if (map != NULL)
+    g_array_free (map, TRUE);
+
+  /* Project wide config */
+  if (NULL != (context = ide_workbench_get_context (self->workbench)) &&
+      NULL != (vcs = ide_context_get_vcs (context)))
+    {
+      GFile *workdir;
+      g_autofree gchar *workdir_path = NULL;
+
+      workdir = ide_vcs_get_working_directory (vcs);
+      workdir_path = g_file_get_path (workdir);
+      project_config_path = g_build_filename (workdir_path,
+                                              ".beautifier",
+                                              NULL);
+      map = gb_beautifier_config_get_map (self, project_config_path);
+      add_entries_from_base_path (self, project_config_path, entries, map);
+      if (map != NULL)
+        g_array_free (map, TRUE);
+    }
+
+  /* System wide config */
+  map = gb_beautifier_config_get_map (self, GB_BEAUTIFIER_PLUGIN_DATADIR);
+  add_entries_from_base_path (self, GB_BEAUTIFIER_PLUGIN_DATADIR, entries, map);
+  if (map != NULL)
+    g_array_free (map, TRUE);
+
+  return entries;
+}
diff --git a/plugins/beautifier/gb-beautifier-config.h b/plugins/beautifier/gb-beautifier-config.h
new file mode 100644
index 0000000..12b7a99
--- /dev/null
+++ b/plugins/beautifier/gb-beautifier-config.h
@@ -0,0 +1,53 @@
+/* gb-beautifier-config.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * 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 GB_BEAUTIFIER_CONFIG_H
+#define GB_BEAUTIFIER_CONFIG_H
+
+#include <glib.h>
+
+#include "gb-beautifier-workbench-addin.h"
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+  GB_BEAUTIFIER_CONFIG_COMMAND_UNCRUSTIFY,
+} GbBeautifierConfigCommand;
+
+typedef struct
+{
+  gchar                     *lang_id;
+  GFile                     *file;
+  gchar                     *name;
+  GbBeautifierConfigCommand  command;
+  guint                      is_default : 1;
+} GbBeautifierConfigEntry;
+
+typedef struct
+{
+  gchar *lang_id;
+  gchar *profile;
+  gchar *default_profile;
+} GbBeautifierMapEntry;
+
+GArray *gb_beautifier_config_get_entries (GbBeautifierWorkbenchAddin *self);
+
+G_END_DECLS
+
+#endif /* GB_BEAUTIFIER_CONFIG_H */
diff --git a/plugins/beautifier/gb-beautifier-helper.c b/plugins/beautifier/gb-beautifier-helper.c
new file mode 100644
index 0000000..aeaf6b5
--- /dev/null
+++ b/plugins/beautifier/gb-beautifier-helper.c
@@ -0,0 +1,155 @@
+/* gb-beautifier-helper.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * 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 <gtksourceview/gtksource.h>
+#include "ide.h"
+
+#include "gb-beautifier-helper.h"
+
+typedef struct
+{
+  GbBeautifierWorkbenchAddin *self;
+  GFile                      *file;
+  GFileIOStream              *stream;
+  gsize                       len;
+} SaveTmpState;
+
+static void
+save_tmp_state_free (gpointer data)
+{
+  SaveTmpState *state = (SaveTmpState *)data;
+
+  if (!g_io_stream_is_closed ((GIOStream *)state->stream))
+    g_io_stream_close ((GIOStream *)state->stream, NULL, NULL);
+
+  g_clear_object (&state->file);
+
+  g_slice_free (SaveTmpState, state);
+}
+
+static void
+gb_beautifier_helper_create_tmp_file_cb (GObject      *object,
+                                         GAsyncResult *result,
+                                         gpointer      user_data)
+{
+  GOutputStream *output_stream = (GOutputStream *)object;
+  g_autoptr(GError) error = NULL;
+  g_autoptr(GTask) task = (GTask *)user_data;
+  SaveTmpState *state;
+  gsize count;
+
+  g_assert (G_IS_OUTPUT_STREAM (output_stream));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  state = (SaveTmpState *)g_task_get_task_data (task);
+  if (!g_output_stream_write_all_finish (output_stream, result, &count, &error))
+    g_task_return_error (task, g_steal_pointer (&error));
+  else if (g_task_return_error_if_cancelled (task))
+    gb_beautifier_helper_remove_tmp_file (state->self, state->file);
+  else
+    g_task_return_pointer (task, g_steal_pointer (&state->file), g_object_unref);
+}
+
+void
+gb_beautifier_helper_create_tmp_file_async (GbBeautifierWorkbenchAddin *self,
+                                            const gchar                *text,
+                                            GAsyncReadyCallback         callback,
+                                            GCancellable               *cancellable,
+                                            gpointer                    user_data)
+{
+  SaveTmpState *state;
+  GFile *file = NULL;
+  GFileIOStream *stream;
+  GOutputStream *output_stream;
+  g_autoptr(GTask) task = NULL;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (!ide_str_empty0 (text));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_assert (callback != NULL);
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, gb_beautifier_helper_create_tmp_file_async);
+  state = g_slice_new0 (SaveTmpState);
+  state->self = self;
+  g_task_set_task_data (task, state, save_tmp_state_free);
+
+  if (NULL == (file = g_file_new_tmp ("gnome-builder-beautifier-XXXXXX.txt", &stream, &error)))
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  state->file = file;
+  state->stream = stream;
+  state->len = strlen (text);
+
+  output_stream = g_io_stream_get_output_stream ((GIOStream *)stream);
+  g_output_stream_write_all_async (output_stream,
+                                   text,
+                                   state->len,
+                                   G_PRIORITY_DEFAULT,
+                                   cancellable,
+                                   gb_beautifier_helper_create_tmp_file_cb,
+                                   g_steal_pointer (&task));
+}
+
+GFile *
+gb_beautifier_helper_create_tmp_file_finish (GbBeautifierWorkbenchAddin  *self,
+                                             GAsyncResult                *result,
+                                             GError                     **error)
+{
+  GTask *task = (GTask *)result;
+
+  g_return_val_if_fail (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self), NULL);
+  g_return_val_if_fail (g_task_is_valid (result, self), NULL);
+
+  return g_task_propagate_pointer (task, error);
+}
+
+void
+gb_beautifier_helper_remove_tmp_file (GbBeautifierWorkbenchAddin *self,
+                                      GFile                      *tmp_file)
+{
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+
+  g_file_delete (tmp_file, NULL, NULL);
+}
+
+const gchar *
+gb_beautifier_helper_get_lang_id (GbBeautifierWorkbenchAddin *self,
+                                  IdeSourceView              *view)
+{
+  GtkTextBuffer *buffer;
+  GtkSourceLanguage *lang;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_SOURCE_VIEW (view));
+
+  buffer = GTK_TEXT_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
+  if (NULL == (lang = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (buffer))))
+    {
+      g_warning ("Beautifier plugin: Can't find a GtkSourceLanguage for the buffer");
+      return NULL;
+    }
+
+  return gtk_source_language_get_id (lang);
+}
diff --git a/plugins/beautifier/gb-beautifier-helper.h b/plugins/beautifier/gb-beautifier-helper.h
new file mode 100644
index 0000000..23cdf92
--- /dev/null
+++ b/plugins/beautifier/gb-beautifier-helper.h
@@ -0,0 +1,46 @@
+/* gb-beautifier-helper.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * 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 GB_BEAUTIFIER_HELPER_H
+#define GB_BEAUTIFIER_HELPER_H
+
+#include <glib-object.h>
+
+#include "ide.h"
+
+#include "gb-beautifier-workbench-addin.h"
+
+G_BEGIN_DECLS
+
+void          gb_beautifier_helper_create_tmp_file_async    (GbBeautifierWorkbenchAddin  *self,
+                                                             const gchar                 *text,
+                                                             GAsyncReadyCallback          callback,
+                                                             GCancellable                *cancellable,
+                                                             gpointer                     user_data);
+GFile        *gb_beautifier_helper_create_tmp_file_finish   (GbBeautifierWorkbenchAddin  *self,
+                                                             GAsyncResult                *result,
+                                                             GError                     **error);
+
+const gchar  *gb_beautifier_helper_get_lang_id              (GbBeautifierWorkbenchAddin  *self,
+                                                             IdeSourceView               *view);
+void          gb_beautifier_helper_remove_tmp_file          (GbBeautifierWorkbenchAddin  *self,
+                                                             GFile                       *tmp_file);
+
+G_END_DECLS
+
+#endif /* GB_BEAUTIFIER_HELPER_H */
diff --git a/plugins/beautifier/gb-beautifier-plugin.c b/plugins/beautifier/gb-beautifier-plugin.c
new file mode 100644
index 0000000..2f702c5
--- /dev/null
+++ b/plugins/beautifier/gb-beautifier-plugin.c
@@ -0,0 +1,30 @@
+/* gb-beautifier-plugin.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * 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 "gb-beautifier-workbench-addin.h"
+
+void
+peas_register_types (PeasObjectModule *module)
+{
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_WORKBENCH_ADDIN,
+                                              GB_TYPE_BEAUTIFIER_WORKBENCH_ADDIN);
+}
diff --git a/plugins/beautifier/gb-beautifier-private.h b/plugins/beautifier/gb-beautifier-private.h
new file mode 100644
index 0000000..d95e021
--- /dev/null
+++ b/plugins/beautifier/gb-beautifier-private.h
@@ -0,0 +1,40 @@
+/* gb-beautifier-private.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * 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 GB_BEAUTIFIER_PRIVATE_H
+#define GB_BEAUTIFIER_PRIVATE_H
+
+#include <glib-object.h>
+
+#include "ide.h"
+
+G_BEGIN_DECLS
+
+struct _GbBeautifierWorkbenchAddin
+{
+  GObject                parent_instance;
+
+  IdeWorkbench          *workbench;
+  IdeEditorPerspective  *editor;
+  GArray                *entries;
+};
+
+G_END_DECLS
+
+#endif /* GB_BEAUTIFIER_PRIVATE_H */
+
diff --git a/plugins/beautifier/gb-beautifier-process.c b/plugins/beautifier/gb-beautifier-process.c
new file mode 100644
index 0000000..76233ab
--- /dev/null
+++ b/plugins/beautifier/gb-beautifier-process.c
@@ -0,0 +1,268 @@
+/* gb-beautifier-process.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * 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 <gtksourceview/gtksource.h>
+#include "ide.h"
+
+#include "gb-beautifier-private.h"
+#include "gb-beautifier-helper.h"
+
+#include "gb-beautifier-process.h"
+
+typedef struct
+{
+  GbBeautifierWorkbenchAddin *self;
+  IdeSourceView              *source_view;
+  GtkTextMark                *begin_mark;
+  GtkTextMark                *end_mark;
+  GbBeautifierConfigCommand   command;
+  GFile                      *src_file;
+  GFile                      *config_file;
+  gchar                      *lang_id;
+  gchar                      *text;
+} ProcessState;
+
+static void
+process_state_free (gpointer data)
+{
+  ProcessState *state = (ProcessState *)data;
+  GtkTextBuffer *buffer;
+
+  g_assert (state != NULL);
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (state->source_view));
+  gtk_text_buffer_delete_mark (buffer, state->begin_mark);
+  gtk_text_buffer_delete_mark (buffer, state->end_mark);
+
+  gb_beautifier_helper_remove_tmp_file (state->self, state->src_file);
+  g_clear_object (&state->src_file);
+
+  g_clear_object (&state->config_file);
+  g_free (state->lang_id);
+  g_free (state->text);
+
+  g_slice_free (ProcessState, state);
+}
+
+static GSubprocess *
+gb_beautifier_process_create_for_uncrustify (GbBeautifierWorkbenchAddin *self,
+                                             ProcessState               *state,
+                                             GError                     *error)
+{
+  GSubprocess *subprocess = NULL;
+  GPtrArray *args;
+  gchar *config_path;
+  gchar *src_path;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (state != NULL);
+
+  config_path = g_file_get_path (state->config_file);
+  src_path = g_file_get_path (state->src_file);
+
+  g_assert (!ide_str_empty0 (config_path));
+  g_assert (!ide_str_empty0 (src_path));
+  g_assert (!ide_str_empty0 (state->lang_id));
+
+  args = g_ptr_array_new ();
+  g_ptr_array_add (args, "uncrustify");
+
+  g_ptr_array_add (args, "-c");
+  g_ptr_array_add (args, config_path);
+  g_ptr_array_add (args, "-f");
+  g_ptr_array_add (args, src_path);
+  g_ptr_array_add (args, NULL);
+
+  subprocess = g_subprocess_newv ((const gchar * const *)args->pdata,
+                                  G_SUBPROCESS_FLAGS_STDOUT_PIPE |
+                                  G_SUBPROCESS_FLAGS_STDERR_PIPE,
+                                  &error);
+
+  g_ptr_array_free (args, TRUE);
+  return subprocess;
+}
+
+static void
+process_communicate_utf8_cb (GObject      *object,
+                             GAsyncResult *result,
+                             gpointer      user_data)
+{
+  g_autoptr (GSubprocess) process = (GSubprocess *)object;
+  g_autoptr (GTask) task = (GTask *)user_data;
+  g_autofree gchar *stdout_str = NULL;
+  g_autoptr(GError) error = NULL;
+  GtkSourceCompletion *completion;
+  GtkTextBuffer *buffer;
+  GtkTextIter begin;
+  GtkTextIter end;
+  ProcessState *state;
+
+  g_assert (G_IS_SUBPROCESS (process));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  if (!g_subprocess_communicate_utf8_finish (process, result, &stdout_str, NULL, &error))
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  if (g_task_return_error_if_cancelled (task))
+    return;
+
+  state = (ProcessState *)g_task_get_task_data (task);
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (state->source_view));
+  completion = gtk_source_view_get_completion (GTK_SOURCE_VIEW (state->source_view));
+
+  if (!ide_str_empty0 (stdout_str))
+    {
+      gtk_source_completion_block_interactive (completion);
+      gtk_text_buffer_begin_user_action (buffer);
+
+      gtk_text_buffer_get_iter_at_mark (buffer, &begin, state->begin_mark);
+      gtk_text_buffer_get_iter_at_mark (buffer, &end, state->end_mark);
+      gtk_text_buffer_delete (buffer, &begin, &end);
+      gtk_text_buffer_insert (buffer, &begin, stdout_str, -1);
+
+      /* Get valid iters from marks */
+      gtk_text_buffer_get_iter_at_mark (buffer, &begin, state->begin_mark);
+      gtk_text_buffer_get_iter_at_mark (buffer, &end, state->end_mark);
+      gtk_text_buffer_select_range (buffer, &begin, &end);
+      g_signal_emit_by_name (state->source_view, "selection-theatric", IDE_SOURCE_VIEW_THEATRIC_EXPAND);
+
+      gtk_text_buffer_end_user_action (buffer);
+      gtk_source_completion_unblock_interactive (completion);
+
+      g_task_return_boolean (task, TRUE);
+    }
+}
+
+static void
+create_tmp_file_cb (GObject      *object,
+                    GAsyncResult *result,
+                    gpointer      user_data)
+{
+  GbBeautifierWorkbenchAddin  *self = (GbBeautifierWorkbenchAddin  *)object;
+  g_autoptr (GTask) task = (GTask *)user_data;
+  g_autoptr(GError) error = NULL;
+  ProcessState *state;
+  GSubprocess *process;
+  GCancellable *cancellable;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  state = (ProcessState *)g_task_get_task_data (task);
+  if (NULL == (state->src_file = gb_beautifier_helper_create_tmp_file_finish (self, result, &error)))
+    goto fail;
+
+  if (state->command == GB_BEAUTIFIER_CONFIG_COMMAND_UNCRUSTIFY)
+    process = gb_beautifier_process_create_for_uncrustify (self, state, error);
+  else
+    g_assert_not_reached ();
+
+  if (process != NULL)
+    {
+      if (g_task_return_error_if_cancelled (task))
+        g_object_unref (process);
+      else
+        {
+          cancellable = g_task_get_cancellable (task);
+          g_subprocess_communicate_utf8_async (process,
+                                               NULL,
+                                               cancellable,
+                                               process_communicate_utf8_cb,
+                                               g_steal_pointer (&task));
+        }
+
+      return;
+    }
+
+fail:
+  g_task_return_error (task, g_steal_pointer (&error));
+  return;
+}
+
+void
+gb_beautifier_process_launch_async (GbBeautifierWorkbenchAddin  *self,
+                                    IdeSourceView               *source_view,
+                                    GtkTextIter                 *begin,
+                                    GtkTextIter                 *end,
+                                    GbBeautifierConfigEntry     *entry,
+                                    GAsyncReadyCallback          callback,
+                                    GCancellable                *cancellable,
+                                    gpointer                     user_data)
+{
+  GtkTextBuffer *buffer;
+  ProcessState *state;
+  g_autoptr(GTask) task = NULL;
+  const gchar *lang_id;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_SOURCE_VIEW (source_view));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_assert (entry != NULL);
+  g_assert (callback != NULL);
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
+  lang_id = gb_beautifier_helper_get_lang_id (self, source_view);
+
+  if (begin == NULL)
+    gtk_text_buffer_get_start_iter (buffer, begin);
+
+  if (end == NULL)
+    gtk_text_buffer_get_end_iter (buffer, begin);
+
+  g_assert (gtk_text_iter_get_buffer (begin) == buffer);
+  g_assert (gtk_text_iter_get_buffer (end) == buffer);
+
+  state = g_slice_new0 (ProcessState);
+  state->self = self;
+  state->source_view = source_view;
+
+  gtk_text_iter_order (begin, end);
+  state->text = gtk_text_buffer_get_text (buffer, begin, end, FALSE);
+  state->begin_mark = gtk_text_buffer_create_mark (buffer, NULL, begin, TRUE);
+  state->end_mark = gtk_text_buffer_create_mark (buffer, NULL, end, FALSE);
+  state->command = entry->command;
+  state->config_file = g_file_dup (entry->file);
+  state->lang_id = g_strdup (lang_id);
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, gb_beautifier_process_launch_async);
+  g_task_set_task_data (task, state, process_state_free);
+
+  gb_beautifier_helper_create_tmp_file_async (self,
+                                              state->text,
+                                              create_tmp_file_cb,
+                                              cancellable,
+                                              g_steal_pointer (&task));
+}
+
+gboolean
+gb_beautifier_process_launch_finish (GbBeautifierWorkbenchAddin  *self,
+                                     GAsyncResult                *result,
+                                     GError                     **error)
+{
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (g_task_is_valid (result, self));
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
diff --git a/plugins/beautifier/gb-beautifier-process.h b/plugins/beautifier/gb-beautifier-process.h
new file mode 100644
index 0000000..5fc2cfd
--- /dev/null
+++ b/plugins/beautifier/gb-beautifier-process.h
@@ -0,0 +1,43 @@
+/* gb-beautifier-process.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * 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 GB_BEAUTIFIER_PROCESS_H
+#define GB_BEAUTIFIER_PROCESS_H
+
+#include <glib-object.h>
+
+#include "gb-beautifier-config.h"
+#include "gb-beautifier-workbench-addin.h"
+
+G_BEGIN_DECLS
+
+void          gb_beautifier_process_launch_async      (GbBeautifierWorkbenchAddin  *self,
+                                                       IdeSourceView               *source_view,
+                                                       GtkTextIter                 *begin,
+                                                       GtkTextIter                 *end,
+                                                       GbBeautifierConfigEntry     *entry,
+                                                       GAsyncReadyCallback          callback,
+                                                       GCancellable                *cancellable,
+                                                       gpointer                     user_data);
+gboolean      gb_beautifier_process_launch_finish     (GbBeautifierWorkbenchAddin  *self,
+                                                       GAsyncResult                *result,
+                                                       GError                     **error);
+
+G_END_DECLS
+
+#endif /* GB_BEAUTIFIER_PROCESS_H */
diff --git a/plugins/beautifier/gb-beautifier-workbench-addin.c 
b/plugins/beautifier/gb-beautifier-workbench-addin.c
new file mode 100644
index 0000000..9b459e6
--- /dev/null
+++ b/plugins/beautifier/gb-beautifier-workbench-addin.c
@@ -0,0 +1,374 @@
+/* gb-beautifier-workbench_addin.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * 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 "gb-beautifier-private.h"
+#include "gb-beautifier-helper.h"
+#include "gb-beautifier-process.h"
+
+#include "gb-beautifier-workbench-addin.h"
+
+static void workbench_addin_iface_init (IdeWorkbenchAddinInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (GbBeautifierWorkbenchAddin, gb_beautifier_workbench_addin, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (IDE_TYPE_WORKBENCH_ADDIN, workbench_addin_iface_init))
+
+static void
+process_launch_async_cb (GObject      *object,
+                         GAsyncResult *result,
+                         gpointer      user_data)
+{
+  GbBeautifierWorkbenchAddin *self = (GbBeautifierWorkbenchAddin *)object;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (G_IS_ASYNC_RESULT (result));
+
+  if (!gb_beautifier_process_launch_finish (self, result, &error))
+    g_warning ("\"%s\"", error->message);
+}
+
+static void
+view_activate_beautify_action_cb (GSimpleAction *action,
+                                  GVariant      *variant,
+                                  gpointer       user_data)
+{
+  GbBeautifierWorkbenchAddin *self = (GbBeautifierWorkbenchAddin *)user_data;
+  IdeEditorView *view;
+  IdeSourceView *source_view;
+  GtkTextBuffer *buffer;
+  GCancellable *cancellable;
+  GbBeautifierConfigEntry *entry;
+  const gchar *param;
+  GtkTextIter begin;
+  GtkTextIter end;
+  guint64 index;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING));
+  g_assert (G_IS_SIMPLE_ACTION (action));
+
+  view = g_object_get_data (G_OBJECT (action), "gb-beautifier-workbench-addin");
+  if (view == NULL || !IDE_IS_EDITOR_VIEW (view))
+    return;
+
+  source_view = ide_editor_view_get_active_source_view (view);
+  if (!GTK_SOURCE_IS_VIEW (source_view))
+    {
+      g_warning ("Beautifier Plugin: the view is not a GtkSourceView");
+      return;
+    }
+
+  if (!gtk_text_view_get_editable (GTK_TEXT_VIEW (source_view)))
+    {
+      g_warning ("Beautifier Plugin: the buffer is not writable");
+      return;
+    }
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));
+  gtk_text_buffer_get_selection_bounds (buffer, &begin, &end);
+  if (gtk_text_iter_equal (&begin, &end))
+    {
+      g_warning ("Beautifier Plugin: Nothing selected");
+      return;
+    }
+
+  param = g_variant_get_string (variant, NULL);
+  index = g_ascii_strtod (param, NULL);
+  entry = &g_array_index (self->entries, GbBeautifierConfigEntry, index);
+  g_assert (entry != NULL);
+
+  cancellable = g_cancellable_new ();
+  gb_beautifier_process_launch_async (self,
+                                      source_view,
+                                      &begin,
+                                      &end,
+                                      entry,
+                                      process_launch_async_cb,
+                                      cancellable,
+                                      NULL);
+}
+
+static void
+view_populate_submenu (GbBeautifierWorkbenchAddin *self,
+                       IdeSourceView              *view,
+                       GMenu                      *submenu,
+                       GArray                     *entries)
+{
+  const gchar *lang_id;
+  GtkApplication *app;
+  gchar *default_action_name;
+  GMenu *default_menu;
+  gboolean has_entries = FALSE;
+  gboolean default_set = FALSE;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_SOURCE_VIEW (view));
+  g_assert (G_IS_MENU (submenu));
+  g_assert (entries != NULL);
+
+  app = GTK_APPLICATION (g_application_get_default ());
+
+  if (NULL != (default_action_name = g_object_get_data (G_OBJECT (view), "gb-beautifier-default-action")))
+    {
+      gtk_application_set_accels_for_action (app, default_action_name, (const gchar*[]) {NULL});
+      g_object_set_data_full (G_OBJECT (view), "gb-beautifier-default-action", NULL, g_free);
+    }
+
+  default_menu = ide_application_get_menu_by_id (IDE_APPLICATION_DEFAULT, "gb-beautify-default-section");
+  g_menu_remove_all (default_menu);
+
+  lang_id = gb_beautifier_helper_get_lang_id (self, view);
+  for (gint i = 0; i < entries->len; ++i)
+    {
+      GbBeautifierConfigEntry *entry;
+      g_autoptr(GMenuItem) item = NULL;
+      g_autofree gchar *param = NULL;
+
+      entry = &g_array_index (entries, GbBeautifierConfigEntry, i);
+      if (0 == g_strcmp0 (entry->lang_id, lang_id))
+        {
+          param = g_strdup_printf ("%i", i);
+          if (!default_set && entry->is_default)
+            {
+              item = g_menu_item_new (entry->name, NULL);
+              default_action_name = g_strdup_printf ("view.beautify-default::%i", i);
+              g_object_set_data_full (G_OBJECT (view),
+                                      "gb-beautifier-default-action",
+                                      default_action_name,
+                                      g_free);
+              g_menu_item_set_action_and_target (item, "view.beautify-default", "s", param);
+              gtk_application_set_accels_for_action (app,
+                                                     default_action_name,
+                                                     (const gchar*[]) {"<Control><Alt>b", NULL});
+
+              g_menu_append_item (default_menu, item);
+              default_set = TRUE;
+            }
+          else
+            {
+              item = g_menu_item_new (entry->name, NULL);
+              g_menu_item_set_action_and_target (item, "view.beautify", "s", param);
+              g_menu_append_item (submenu, item);
+            }
+
+          has_entries = TRUE;
+        }
+    }
+
+  if (!has_entries)
+    {
+      g_autofree gchar *label = NULL;
+      g_autoptr(GMenuItem) item = NULL;
+      GtkTextBuffer *buffer;
+      GtkSourceLanguage *source_language;
+      const gchar *language;
+
+      buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+      source_language = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (buffer));
+      if (source_language != NULL &&
+          NULL != (language = gtk_source_language_get_name (source_language)))
+        label = g_strdup_printf (_("No beautifier available for “%s”"), language);
+      else
+        label = g_strdup_printf (_("No beautifier available"));
+
+      item = g_menu_item_new (label, NULL);
+      /* Set the item to a disable state */
+      g_menu_item_set_action_and_target (item, "view.beautify-menu", NULL);
+      g_menu_append_item (submenu, item);
+    }
+}
+
+static void
+view_populate_popup (GbBeautifierWorkbenchAddin *self,
+                     GtkWidget                  *popup,
+                     IdeSourceView              *source_view)
+{
+  GMenu *submenu;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (GTK_IS_WIDGET (popup));
+  g_assert (IDE_IS_SOURCE_VIEW (source_view));
+
+  submenu = ide_application_get_menu_by_id (IDE_APPLICATION_DEFAULT, "gb-beautify-profiles-section");
+  g_menu_remove_all (submenu);
+  view_populate_submenu (self, source_view, submenu, self->entries);
+}
+
+static GActionEntry GbBeautifierActions [] = {
+  {"beautify", view_activate_beautify_action_cb, "s"},
+  {"beautify-default", view_activate_beautify_action_cb, "s"},
+};
+
+static void
+setup_view_cb (GtkWidget                  *widget,
+               GbBeautifierWorkbenchAddin *self)
+{
+  IdeEditorView *view = (IdeEditorView *)widget;
+  IdeSourceView *source_view;
+  GActionGroup *actions;
+  GAction *action;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_EDITOR_VIEW (view));
+
+  actions = gtk_widget_get_action_group (GTK_WIDGET (view), "view");
+  g_action_map_add_action_entries (G_ACTION_MAP (actions),
+                                   GbBeautifierActions,
+                                   G_N_ELEMENTS (GbBeautifierActions),
+                                   self);
+
+  action = g_action_map_lookup_action (G_ACTION_MAP (actions), "beautify");
+  g_object_set_data (G_OBJECT (action), "gb-beautifier-workbench-addin", view);
+  action = g_action_map_lookup_action (G_ACTION_MAP (actions), "beautify-default");
+  g_object_set_data (G_OBJECT (action), "gb-beautifier-workbench-addin", view);
+
+  g_object_set_data (G_OBJECT (view), "gb-beautifier-workbench-addin", self);
+
+  source_view = ide_editor_view_get_active_source_view (view);
+  g_signal_connect_object (source_view,
+                           "populate-popup",
+                           G_CALLBACK (view_populate_popup),
+                           self,
+                           G_CONNECT_SWAPPED);
+}
+
+static void
+cleanup_view_cb (GtkWidget                  *widget,
+                 GbBeautifierWorkbenchAddin *self)
+{
+  IdeEditorView *view = (IdeEditorView *)widget;
+  GActionGroup *actions;
+  GtkApplication *app;
+  gchar *default_action_name;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_EDITOR_VIEW (view));
+
+  app = GTK_APPLICATION (g_application_get_default ());
+
+  if (NULL != (actions = gtk_widget_get_action_group (GTK_WIDGET (view), "view")))
+    {
+      g_action_map_remove_action (G_ACTION_MAP (actions), "beautify");
+      g_action_map_remove_action (G_ACTION_MAP (actions), "beautify-default");
+    }
+
+  g_object_set_data (G_OBJECT (view), "gb-beautifier-workbench-addin", NULL);
+  if (NULL != (default_action_name = g_object_get_data (G_OBJECT (view), "gb-beautifier-default-action")))
+    {
+      gtk_application_set_accels_for_action (app, default_action_name, (const gchar*[]) {NULL});
+      g_object_set_data_full (G_OBJECT (view), "gb-beautifier-default-action", NULL, g_free);
+    }
+}
+
+static void
+view_added_cb (GbBeautifierWorkbenchAddin *self,
+               GtkWidget                  *widget)
+{
+  IdeLayoutView *view = (IdeLayoutView *)widget;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_LAYOUT_VIEW (view));
+
+  if (!IDE_IS_EDITOR_VIEW (view))
+    return;
+
+  setup_view_cb (GTK_WIDGET (view), self);
+}
+
+static void
+view_removed_cb (GbBeautifierWorkbenchAddin *self,
+                 GtkWidget                  *widget)
+{
+  IdeLayoutView *view = (IdeLayoutView *)widget;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_LAYOUT_VIEW (view));
+
+  if (!IDE_IS_EDITOR_VIEW (view))
+    return;
+
+  cleanup_view_cb (GTK_WIDGET (view), self);
+}
+
+static void
+gb_beautifier_workbench_addin_load (IdeWorkbenchAddin *addin,
+                                    IdeWorkbench      *workbench)
+{
+  GbBeautifierWorkbenchAddin *self = (GbBeautifierWorkbenchAddin *)addin;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_WORKBENCH (workbench));
+
+  ide_set_weak_pointer (&self->workbench, workbench);
+  self->editor = IDE_EDITOR_PERSPECTIVE (ide_workbench_get_perspective_by_name (workbench, "editor"));
+  self->entries = gb_beautifier_config_get_entries (self);
+
+  ide_perspective_views_foreach (IDE_PERSPECTIVE (self->editor), (GtkCallback)setup_view_cb, self);
+
+  g_signal_connect_object (self->editor,
+                           "view-added",
+                           G_CALLBACK (view_added_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+  g_signal_connect_object (self->editor,
+                           "view-removed",
+                           G_CALLBACK (view_removed_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+}
+
+static void
+gb_beautifier_workbench_addin_unload (IdeWorkbenchAddin *addin,
+                                      IdeWorkbench      *workbench)
+{
+  GbBeautifierWorkbenchAddin *self = (GbBeautifierWorkbenchAddin *)addin;
+
+  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_WORKBENCH (workbench));
+
+  ide_perspective_views_foreach (IDE_PERSPECTIVE (self->editor), (GtkCallback)cleanup_view_cb, self);
+  if (self->entries != NULL)
+    {
+      g_array_free (self->entries, TRUE);
+      self->entries = NULL;
+    }
+
+  ide_clear_weak_pointer (&self->workbench);
+}
+
+static void
+gb_beautifier_workbench_addin_class_init (GbBeautifierWorkbenchAddinClass *klass)
+{
+}
+
+static void
+gb_beautifier_workbench_addin_init (GbBeautifierWorkbenchAddin *self)
+{
+}
+
+static void
+workbench_addin_iface_init (IdeWorkbenchAddinInterface *iface)
+{
+  iface->load = gb_beautifier_workbench_addin_load;
+  iface->unload = gb_beautifier_workbench_addin_unload;
+}
diff --git a/plugins/beautifier/gb-beautifier-workbench-addin.h 
b/plugins/beautifier/gb-beautifier-workbench-addin.h
new file mode 100644
index 0000000..ed18209
--- /dev/null
+++ b/plugins/beautifier/gb-beautifier-workbench-addin.h
@@ -0,0 +1,32 @@
+/* gb-beautifier-workbench-addin.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * 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 GB_BEAUTIFIER_WORKBENCH_ADDIN_H
+#define GB_BEAUTIFIER_WORKBENCH_ADDIN_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_BEAUTIFIER_WORKBENCH_ADDIN (gb_beautifier_workbench_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbBeautifierWorkbenchAddin, gb_beautifier_workbench_addin, GB, 
BEAUTIFIER_WORKBENCH_ADDIN, GObject)
+
+G_END_DECLS
+
+#endif /* GB_BEAUTIFIER_WORKBENCH_ADDIN_H */
diff --git a/plugins/beautifier/gb-beautifier.gresource.xml b/plugins/beautifier/gb-beautifier.gresource.xml
new file mode 100644
index 0000000..4312603
--- /dev/null
+++ b/plugins/beautifier/gb-beautifier.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/builder/plugins/beautifier-plugin">
+    <file>gtk/menus.ui</file>
+  </gresource>
+</gresources>
diff --git a/plugins/beautifier/gtk/menus.ui b/plugins/beautifier/gtk/menus.ui
new file mode 100644
index 0000000..1f6fc9e
--- /dev/null
+++ b/plugins/beautifier/gtk/menus.ui
@@ -0,0 +1,19 @@
+<?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="gb-beautify-section">
+          <attribute name="after">ide-source-view-popup-menu-line-section</attribute>
+          <submenu id="gb-beautify-submenu">
+            <attribute name="label" translatable="yes">Beautify</attribute>
+            <section id="gb-beautify-default-section">
+            </section>
+            <section id="gb-beautify-profiles-section">
+            </section>
+          </submenu>
+        </section>
+      </submenu>
+    </section>
+  </menu>
+</interface>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]