[gnome-builder/wip/slaf/beautifier: 6/21] beautifier plugin: initial commit
- From: Sébastien Lafargue <slafargue src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/slaf/beautifier: 6/21] beautifier plugin: initial commit
- Date: Mon, 5 Dec 2016 22:24:35 +0000 (UTC)
commit 1a950d8a05eeff6a110826a483ca04e123540edc
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]