diff --git a/.gitignore b/.gitignore index 32da06d..25477c4 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ /src/bin/edi /src/bin/edi_build -/src/tests/edi_suite /data/desktop/edi.desktop /doc/edi.1 edi-*.tar.?z* @@ -60,6 +59,14 @@ po/remove-potcdate.sin po/stamp-po /coverage/ +/src/tests/edi_suite /src/tests/edi_suite.* /src/tests/test-suite.log /src/tests/check-results.xml + +/elm_code/bin/elm_code_test + +/elm_code/tests/elm_code_suite +/elm_code/tests/elm_code_suite.* +/elm_code/tests/test-suite.log +/elm_code/tests/check-results.xml diff --git a/Makefile.am b/Makefile.am index 822c51a..3e59bc3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,7 +29,7 @@ MAINTAINERCLEANFILES = \ $(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.gz \ $(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.bz2 -SUBDIRS = data doc packaging po src +SUBDIRS = data doc packaging po elm_code src ACLOCAL_AMFLAGS = -I m4 @@ -73,7 +73,7 @@ endif if EFL_HAVE_TESTS -TESTS = src/tests/edi_suite +TESTS = elm_code/tests/elm_code_suite src/tests/edi_suite lcov-check: if EFL_HAVE_LCOV diff --git a/configure.ac b/configure.ac index b3cf135..a4080f3 100644 --- a/configure.ac +++ b/configure.ac @@ -34,6 +34,7 @@ PKG_CHECK_MODULES([EFL], evas >= 1.8.0 ecore >= 1.8.0 edje >= 1.8.0 + eo >= 1.8.0 elementary >= 1.8.0 eio >= 1.8.0 ]) @@ -101,6 +102,10 @@ src/Makefile src/bin/Makefile src/lib/Makefile src/tests/Makefile +elm_code/Makefile +elm_code/lib/Makefile +elm_code/bin/Makefile +elm_code/tests/Makefile doc/edi.1 ]) AC_OUTPUT diff --git a/elm_code/Makefile.am b/elm_code/Makefile.am new file mode 100644 index 0000000..15871c9 --- /dev/null +++ b/elm_code/Makefile.am @@ -0,0 +1,4 @@ +MAINTAINERCLEANFILES = Makefile.in + +SUBDIRS = lib bin tests + diff --git a/elm_code/bin/Makefile.am b/elm_code/bin/Makefile.am new file mode 100644 index 0000000..363beb8 --- /dev/null +++ b/elm_code/bin/Makefile.am @@ -0,0 +1,20 @@ +MAINTAINERCLEANFILES = Makefile.in + +bin_PROGRAMS = elm_code_test + +AM_CPPFLAGS = -DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +-I$(top_builddir)/elm_code/bin/ \ +-I$(top_srcdir)/elm_code/bin/ \ +-I$(top_builddir)/elm_code/lib/ \ +-I$(top_srcdir)/elm_code/lib/ \ +-DEFL_BETA_API_SUPPORT \ +@EFL_CFLAGS@ + +elm_code_test_SOURCES = elm_code_test_main.c +elm_code_test_LDADD = @EFL_LIBS@ $(top_builddir)/elm_code/lib/libelm_code.la + +localedir = $(datadir)/locale +DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ + +EXTRA_DIST = elm_code_test_private.h + diff --git a/elm_code/bin/elm_code_test_main.c b/elm_code/bin/elm_code_test_main.c new file mode 100644 index 0000000..95a5214 --- /dev/null +++ b/elm_code/bin/elm_code_test_main.c @@ -0,0 +1,205 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* NOTE: Respecting header order is important for portability. + * Always put system first, then EFL, then your public header, + * and finally your private one. */ + +#include +#include + +#include "gettext.h" + +#include + +#include "elm_code_test_private.h" + +#define COPYRIGHT "Copyright © 2014 andy and various contributors (see AUTHORS)." + +static void +_elm_code_test_win_del(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + elm_exit(); +} + +static Evas_Object * +_elm_code_test_welcome_setup(Evas_Object *parent) +{ + Elm_Code *code; + Evas_Object *widget; + + code = elm_code_create(); + elm_code_file_new(code); + widget = elm_code_widget_add(parent, code); + elm_code_file_line_append(code->file, "Hello World, Elm Code!"); + elm_code_file_line_token_add(code->file, 1, 14, 21, ELM_CODE_TOKEN_TYPE_COMMENT); + elm_code_file_line_append(code->file, ""); + elm_code_file_line_append(code->file, "This is a demo of elm_code's capabilities."); + + elm_code_file_line_append(code->file, "*** Currently experimental ***"); + elm_code_file_line_status_set(code->file, 4, ELM_CODE_STATUS_TYPE_ERROR); + + evas_object_size_hint_weight_set(widget, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(widget, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(widget); + + return widget; +} + +static Evas_Object * +_elm_code_test_diff_setup(Evas_Object *parent) +{ + Elm_Code *code; + Evas_Object *widget, *hbox; + + hbox = elm_box_add(parent); + evas_object_size_hint_weight_set(hbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(hbox, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_homogeneous_set(hbox, EINA_TRUE); + elm_box_horizontal_set(hbox, EINA_TRUE); + evas_object_show(hbox); + + // left side of diff + code = elm_code_create(); + elm_code_file_new(code); + widget = elm_code_widget_add(parent, code); + + elm_code_file_line_append(code->file, "Some content to diff"); + elm_code_file_line_append(code->file, ""); + elm_code_file_line_append(code->file, "more"); + elm_code_file_line_append(code->file, "removed"); + elm_code_file_line_append(code->file, "will change"); + elm_code_file_line_append(code->file, "unchanged"); + + elm_code_file_line_status_set(code->file, 4, ELM_CODE_STATUS_TYPE_REMOVED); + elm_code_file_line_token_add(code->file, 4, 1, 7, ELM_CODE_TOKEN_TYPE_REMOVED); + elm_code_file_line_status_set(code->file, 5, ELM_CODE_STATUS_TYPE_CHANGED); + elm_code_file_line_token_add(code->file, 5, 1, 5, ELM_CODE_TOKEN_TYPE_REMOVED); + + evas_object_size_hint_weight_set(widget, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(widget, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(widget); + elm_box_pack_end(hbox, widget); + + // right side of diff + code = elm_code_create(); + elm_code_file_new(code); + widget = elm_code_widget_add(parent, code); + + elm_code_file_line_append(code->file, "Some content to diff"); + elm_code_file_line_append(code->file, "added"); + elm_code_file_line_append(code->file, "more"); + elm_code_file_line_append(code->file, ""); + elm_code_file_line_append(code->file, "changed"); + elm_code_file_line_append(code->file, "unchanged"); + + elm_code_file_line_status_set(code->file, 2, ELM_CODE_STATUS_TYPE_ADDED); + elm_code_file_line_token_add(code->file, 2, 1, 5, ELM_CODE_TOKEN_TYPE_ADDED); + elm_code_file_line_status_set(code->file, 5, ELM_CODE_STATUS_TYPE_CHANGED); + elm_code_file_line_token_add(code->file, 5, 7, 7, ELM_CODE_TOKEN_TYPE_ADDED); + + evas_object_size_hint_weight_set(widget, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(widget, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(widget); + elm_box_pack_end(hbox, widget); + + return hbox; +} + +static Evas_Object * +elm_code_test_win_setup(void) +{ + Evas_Object *win; + Evas_Object *vbox; + + win = elm_win_util_standard_add("main", "Elm_code_test"); + if (!win) return NULL; + + vbox = elm_box_add(win); + evas_object_size_hint_weight_set(vbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(vbox, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_homogeneous_set(vbox, EINA_TRUE); + evas_object_show(vbox); + + elm_win_focus_highlight_enabled_set(win, EINA_TRUE); + evas_object_smart_callback_add(win, "delete,request", _elm_code_test_win_del, NULL); + + elm_box_pack_end(vbox, _elm_code_test_welcome_setup(vbox)); + + elm_box_pack_end(vbox, _elm_code_test_diff_setup(vbox)); + + elm_win_resize_object_add(win, vbox); + + evas_object_resize(win, 320 * elm_config_scale_get(), 180 * elm_config_scale_get()); + evas_object_show(win); + + return win; +} + +static const Ecore_Getopt optdesc = { + "elm_code_test", + "%prog [options]", + PACKAGE_VERSION, + COPYRIGHT, + "BSD with advertisement clause", + "An EFL elm_code_test program", + 0, + { + ECORE_GETOPT_LICENSE('L', "license"), + ECORE_GETOPT_COPYRIGHT('C', "copyright"), + ECORE_GETOPT_VERSION('V', "version"), + ECORE_GETOPT_HELP('h', "help"), + ECORE_GETOPT_SENTINEL + } +}; + +EAPI_MAIN int +elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED) +{ + Evas_Object *win; + int args; + Eina_Bool quit_option = EINA_FALSE; + + Ecore_Getopt_Value values[] = { + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_NONE + }; + +#if ENABLE_NLS + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + bind_textdomain_codeset(PACKAGE, "UTF-8"); + textdomain(PACKAGE); +#endif + + elm_code_init(); + + args = ecore_getopt_parse(&optdesc, values, argc, argv); + if (args < 0) + { + EINA_LOG_CRIT("Could not parse arguments."); + goto end; + } + else if (quit_option) + { + goto end; + } + + elm_app_info_set(elm_main, "elm_code_test", "images/elm_code.png"); + + if (!(win = elm_code_test_win_setup())) + goto end; + + elm_run(); + + end: + elm_code_shutdown(); + elm_shutdown(); + + return 0; +} +ELM_MAIN() diff --git a/elm_code/bin/elm_code_test_private.h b/elm_code/bin/elm_code_test_private.h new file mode 100644 index 0000000..04fb817 --- /dev/null +++ b/elm_code/bin/elm_code_test_private.h @@ -0,0 +1,6 @@ +#ifndef ELM_CODE_TEST_PRIVATE_H_ +# define ELM_CODE_TEST_PRIVATE_H_ + +// FIXME: put some private stuff related to your binary + +#endif diff --git a/elm_code/bin/gettext.h b/elm_code/bin/gettext.h new file mode 100644 index 0000000..e76b592 --- /dev/null +++ b/elm_code/bin/gettext.h @@ -0,0 +1,280 @@ +/* Convenience header for conditional use of GNU . + Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009 Free Software Foundation, Inc. + + 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, 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 + Library General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include + +/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by + the gettext() and ngettext() macros. This is an alternative to calling + textdomain(), and is useful for libraries. */ +# ifdef DEFAULT_TEXT_DOMAIN +# undef gettext +# define gettext(Msgid) \ + dgettext (DEFAULT_TEXT_DOMAIN, Msgid) +# undef ngettext +# define ngettext(Msgid1, Msgid2, N) \ + dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) +# endif + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of a NOP. We don't include + as well because people using "gettext.h" will not include , + and also including would fail on SunOS 4, whereas + is OK. */ +#if defined(__sun) +# include +#endif + +/* Many header files from the libstdc++ coming with g++ 3.3 or newer include + , which chokes if dcgettext is defined as a macro. So include + it now, to make later inclusions of a NOP. */ +#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) +# include +# if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H +# include +# endif +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# undef gettext +# define gettext(Msgid) ((const char *) (Msgid)) +# undef dgettext +# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) +# undef dcgettext +# define dcgettext(Domainname, Msgid, Category) \ + ((void) (Category), dgettext (Domainname, Msgid)) +# undef ngettext +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 \ + ? ((void) (Msgid2), (const char *) (Msgid1)) \ + : ((void) (Msgid1), (const char *) (Msgid2))) +# undef dngettext +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) +# undef dcngettext +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N)) +# undef textdomain +# define textdomain(Domainname) ((const char *) (Domainname)) +# undef bindtextdomain +# define bindtextdomain(Domainname, Dirname) \ + ((void) (Domainname), (const char *) (Dirname)) +# undef bind_textdomain_codeset +# define bind_textdomain_codeset(Domainname, Codeset) \ + ((void) (Domainname), (const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +/* The separator between msgctxt and msgid in a .mo file. */ +#define GETTEXT_CONTEXT_GLUE "\004" + +/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a + MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be + short and rarely need to change. + The letter 'p' stands for 'particular' or 'special'. */ +#ifdef DEFAULT_TEXT_DOMAIN +# define pgettext(Msgctxt, Msgid) \ + pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) +#else +# define pgettext(Msgctxt, Msgid) \ + pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) +#endif +#define dpgettext(Domainname, Msgctxt, Msgid) \ + pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) +#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ + pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) +#ifdef DEFAULT_TEXT_DOMAIN +# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) +#else +# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) +#endif +#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) +#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ + npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category) + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +pgettext_aux (const char *domain, + const char *msg_ctxt_id, const char *msgid, + int category) +{ + const char *translation = dcgettext (domain, msg_ctxt_id, category); + if (translation == msg_ctxt_id) + return msgid; + else + return translation; +} + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +npgettext_aux (const char *domain, + const char *msg_ctxt_id, const char *msgid, + const char *msgid_plural, unsigned long int n, + int category) +{ + const char *translation = + dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); + if (translation == msg_ctxt_id || translation == msgid_plural) + return (n == 1 ? msgid : msgid_plural); + else + return translation; +} + +/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID + can be arbitrary expressions. But for string literals these macros are + less efficient than those above. */ + +#include + +#define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \ + (((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \ + /* || __STDC_VERSION__ >= 199901L */ ) + +#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS +#include +#endif + +#define pgettext_expr(Msgctxt, Msgid) \ + dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) +#define dpgettext_expr(Domainname, Msgctxt, Msgid) \ + dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +dcpgettext_expr (const char *domain, + const char *msgctxt, const char *msgid, + int category) +{ + size_t msgctxt_len = strlen (msgctxt) + 1; + size_t msgid_len = strlen (msgid) + 1; + const char *translation; +#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + char msg_ctxt_id[msgctxt_len + msgid_len]; +#else + char buf[1024]; + char *msg_ctxt_id = + (msgctxt_len + msgid_len <= sizeof (buf) + ? buf + : (char *) malloc (msgctxt_len + msgid_len)); + if (msg_ctxt_id != NULL) +#endif + { + memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); + msg_ctxt_id[msgctxt_len - 1] = '\004'; + memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); + translation = dcgettext (domain, msg_ctxt_id, category); +#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + if (msg_ctxt_id != buf) + free (msg_ctxt_id); +#endif + if (translation != msg_ctxt_id) + return translation; + } + return msgid; +} + +#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ + dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) +#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ + dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +dcnpgettext_expr (const char *domain, + const char *msgctxt, const char *msgid, + const char *msgid_plural, unsigned long int n, + int category) +{ + size_t msgctxt_len = strlen (msgctxt) + 1; + size_t msgid_len = strlen (msgid) + 1; + const char *translation; +#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + char msg_ctxt_id[msgctxt_len + msgid_len]; +#else + char buf[1024]; + char *msg_ctxt_id = + (msgctxt_len + msgid_len <= sizeof (buf) + ? buf + : (char *) malloc (msgctxt_len + msgid_len)); + if (msg_ctxt_id != NULL) +#endif + { + memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); + msg_ctxt_id[msgctxt_len - 1] = '\004'; + memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); + translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); +#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + if (msg_ctxt_id != buf) + free (msg_ctxt_id); +#endif + if (!(translation == msg_ctxt_id || translation == msgid_plural)) + return translation; + } + return (n == 1 ? msgid : msgid_plural); +} + +#endif /* _LIBGETTEXT_H */ diff --git a/elm_code/lib/Elm_Code.h b/elm_code/lib/Elm_Code.h new file mode 100644 index 0000000..eadf59d --- /dev/null +++ b/elm_code/lib/Elm_Code.h @@ -0,0 +1,135 @@ +#ifndef ELM_CODE_H_ +# define ELM_CODE_H_ + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ELM_CODE_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ELM_CODE_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file + * @brief These routines are used for loading Elm Code widgets. + */ + +/** + * @brief Init / shutdown functions. + * @defgroup Init Init / Shutdown + * + * @{ + * + * Functions of obligatory usage, handling proper initialization + * and shutdown routines. + * + * Before the usage of any other function, Elm Code should be properly + * initialized with @ref elm_code_init() and the last call to Elm Code's + * functions should be @ref elm_code_shutdown(), so everything will + * be correctly freed. + * + * Elm Code logs everything with Eina Log, using the "elm_code" log domain. + * + */ + +/** + * Initialize Elm Code. + * + * Initializes Elm Code, its dependencies and modules. Should be the first + * function of Elm Code to be called. + * + * @return The init counter value. + * + * @see elm_code_shutdown(). + * + * @ingroup Init + */ +EAPI int elm_code_init(void); + +/** + * Shutdown Elm Code + * + * Shutdown Elm Code. If init count reaches 0, all the internal structures will + * be freed. Any Elm Code library call after this point will leads to an error. + * + * @return Elm Code's init counter value. + * + * @see elm_code_init(). + * + * @ingroup Init + */ +EAPI int elm_code_shutdown(void); + +/** + * Create a new Elm Code instance + * + * This method creates a new Elm Code instance which will need a + * backing file set for storage. + * Once an Elm Code has been created you can create widgets that render the content. + * + * "return an allocated Elm_Code that references the given file + */ +EAPI Elm_Code *elm_code_create(); + +/** + * Free an Elm Code instance + * + * Releases the resources retained by the code instance and any files it references. + */ +EAPI void elm_code_free(Elm_Code *code); + +/** + * @} + * + * @brief Callbacks and message passing. + * @defgroup Callbacks Managing the information flow between Elm_Code objects and Evas_Object widgets + * + * @{ + * + * Managing the callbacks and other behaviours that cross the backend - frontend divide. + */ + + +EAPI void elm_code_callback_fire(Elm_Code *code, const Eo_Event_Description *signal, void *data); + + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ELM_CODE_H_ */ diff --git a/elm_code/lib/Makefile.am b/elm_code/lib/Makefile.am new file mode 100644 index 0000000..5339cc5 --- /dev/null +++ b/elm_code/lib/Makefile.am @@ -0,0 +1,27 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/elm_code/lib \ +-I$(top_builddir)/elm_code/lib \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +-DEFL_BETA_API_SUPPORT \ +@EFL_CFLAGS@ \ +-DEFL_EFL_BUILD + +lib_LTLIBRARIES = libelm_code.la + +includes_HEADERS = \ +elm_code_file.h \ +elm_code_parse.h \ +elm_code_widget.h \ +Elm_Code.h +includesdir = $(includedir)/edi-@VMAJ@ + +libelm_code_la_SOURCES = \ +elm_code_file.c \ +elm_code_parse.c \ +elm_code_widget.c \ +elm_code.c +libelm_code_la_LIBADD = @EFL_LIBS@ -lm +libelm_code_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@ diff --git a/elm_code/lib/elm_code.c b/elm_code/lib/elm_code.c new file mode 100644 index 0000000..bd4a148 --- /dev/null +++ b/elm_code/lib/elm_code.c @@ -0,0 +1,112 @@ +#ifdef HAVE_CONFIG +# include "config.h" +#endif + +#include + +#include "Elm_Code.h" +#include "elm_code_parse.h" + +#include "elm_code_private.h" + +static int _elm_code_init = 0; +int _elm_code_lib_log_dom = -1; + +const Eo_Event_Description ELM_CODE_EVENT_LINE_SET_DONE = + EO_EVENT_DESCRIPTION("line,set,done", ""); +const Eo_Event_Description ELM_CODE_EVENT_FILE_LOAD_DONE = + EO_EVENT_DESCRIPTION("file, load,done", ""); + +EAPI int +elm_code_init(void) +{ + _elm_code_init++; + if (_elm_code_init > 1) return _elm_code_init; + + eina_init(); + + _elm_code_lib_log_dom = eina_log_domain_register("elm_code", EINA_COLOR_CYAN); + if (_elm_code_lib_log_dom < 0) + { + EINA_LOG_ERR("Elm Code can not create its log domain."); + goto shutdown_eina; + } + + // Put here your initialization logic of your library + + eina_log_timing(_elm_code_lib_log_dom, EINA_LOG_STATE_STOP, EINA_LOG_STATE_INIT); + + return _elm_code_init; + + shutdown_eina: + eina_shutdown(); + _elm_code_init--; + + return _elm_code_init; +} + +EAPI int +elm_code_shutdown(void) +{ + _elm_code_init--; + if (_elm_code_init != 0) return _elm_code_init; + + eina_log_timing(_elm_code_lib_log_dom, + EINA_LOG_STATE_START, + EINA_LOG_STATE_SHUTDOWN); + + // Put here your shutdown logic + + eina_log_domain_unregister(_elm_code_lib_log_dom); + _elm_code_lib_log_dom = -1; + + eina_shutdown(); + + return _elm_code_init; +} + +EAPI Elm_Code * +elm_code_create() +{ + Elm_Code *ret; + + ret = calloc(1, sizeof(Elm_Code)); + + return ret; +} + +EAPI void +elm_code_free(Elm_Code *code) +{ + Evas_Object *widget; + Elm_Code_Parser *parser; + + if (code->file) + elm_code_file_free(code->file); + + EINA_LIST_FREE(code->widgets, widget) + { + evas_object_hide(widget); + evas_object_del(widget); + } + + EINA_LIST_FREE(code->parsers, parser) + { + free(parser); + } + + free(code); +} + +EAPI void +elm_code_callback_fire(Elm_Code *code, const Eo_Event_Description *signal, void *data) +{ + Eina_List *item; + Evas_Object *widget; + + EINA_LIST_FOREACH(code->widgets, item, widget) + { + eo_do(widget, eo_event_callback_call(signal, data)); + } +} + diff --git a/elm_code/lib/elm_code_common.h b/elm_code/lib/elm_code_common.h new file mode 100644 index 0000000..79f5d6c --- /dev/null +++ b/elm_code/lib/elm_code_common.h @@ -0,0 +1,67 @@ +#ifndef ELM_CODE_COMMON_H_ +# define ELM_CODE_COMMON_H_ + +#include +#include + +typedef struct _Elm_Code Elm_Code; + +EAPI extern const Eo_Event_Description ELM_CODE_EVENT_LINE_SET_DONE; +EAPI extern const Eo_Event_Description ELM_CODE_EVENT_FILE_LOAD_DONE; + +typedef enum { + ELM_CODE_STATUS_TYPE_DEFAULT = 0, + ELM_CODE_STATUS_TYPE_ERROR, + + ELM_CODE_STATUS_TYPE_ADDED, + ELM_CODE_STATUS_TYPE_REMOVED, + ELM_CODE_STATUS_TYPE_CHANGED, + + ELM_CODE_STATUS_TYPE_PASSED, + ELM_CODE_STATUS_TYPE_FAILED, + + ELM_CODE_STATUS_TYPE_COUNT +} Elm_Code_Status_Type; + + +typedef enum { + ELM_CODE_TOKEN_TYPE_DEFAULT = ELM_CODE_STATUS_TYPE_COUNT, + ELM_CODE_TOKEN_TYPE_COMMENT, + + + ELM_CODE_TOKEN_TYPE_ADDED, + ELM_CODE_TOKEN_TYPE_REMOVED, + ELM_CODE_TOKEN_TYPE_CHANGED, + + ELM_CODE_TOKEN_TYPE_COUNT +} Elm_Code_Token_Type; + +#include "elm_code_file.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +/** + * @file + * @brief Common data structures and constants. + */ + +struct _Elm_Code +{ + Elm_Code_File *file; + Eina_List *widgets; + Eina_List *parsers; +}; + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ELM_CODE_COMMON_H_ */ diff --git a/elm_code/lib/elm_code_file.c b/elm_code/lib/elm_code_file.c new file mode 100644 index 0000000..e2d9daa --- /dev/null +++ b/elm_code/lib/elm_code_file.c @@ -0,0 +1,200 @@ +#ifdef HAVE_CONFIG +# include "config.h" +#endif + +#include "Elm_Code.h" +#include "elm_code_file.h" +#include "elm_code_parse.h" + +#include "elm_code_private.h" + +static Elm_Code_Line *_elm_code_blank_create(int line) +{ + Elm_Code_Line *ecl; + + ecl = calloc(1, sizeof(Elm_Code_Line)); + if (!ecl) return NULL; + + ecl->number = line; + ecl->status = ELM_CODE_STATUS_TYPE_DEFAULT; + return ecl; +} + +static void _elm_code_file_line_append_data(Elm_Code_File *file, const char *content, int length, int row) +{ + Elm_Code_Line *line; + + line = _elm_code_blank_create(row); + if (!line) return; + + line->content = malloc(sizeof(char) * (length + 1)); + strncpy(line->content, content, length); + line->content[length] = 0; + + file->lines = eina_list_append(file->lines, line); + + if (file->parent) + { + elm_code_parse_line(file->parent, line); + elm_code_callback_fire(file->parent, &ELM_CODE_EVENT_LINE_SET_DONE, line); + } +} + +EAPI Elm_Code_File *elm_code_file_new(Elm_Code *code) +{ + Elm_Code_File *ret; + + ret = calloc(1, sizeof(Elm_Code_File)); + code->file = ret; + ret->parent = code; + + return ret; +} + +EAPI Elm_Code_File *elm_code_file_open(Elm_Code *code, const char *path) +{ + Elm_Code_File *ret; + Eina_File *file; + Eina_File_Line *line; + Eina_Iterator *it; + unsigned int lastindex; + + ret = elm_code_file_new(code); + file = eina_file_open(path, EINA_FALSE); + ret->file = file; + lastindex = 1; + + it = eina_file_map_lines(file); + EINA_ITERATOR_FOREACH(it, line) + { + Elm_Code_Line *ecl; + + /* Working around the issue that eina_file_map_lines does not trigger an item for empty lines */ + while (lastindex < line->index - 1) + { + ecl = _elm_code_blank_create(++lastindex); + if (!ecl) continue; + + ret->lines = eina_list_append(ret->lines, ecl); + } + + _elm_code_file_line_append_data(ret, line->start, line->length, lastindex = line->index); + } + eina_iterator_free(it); + + if (ret->parent) + { + elm_code_parse_file(ret->parent, ret); + elm_code_callback_fire(ret->parent, &ELM_CODE_EVENT_FILE_LOAD_DONE, ret); + } + return ret; +} + +EAPI void elm_code_file_free(Elm_Code_File *file) +{ + Elm_Code_Line *l; + + EINA_LIST_FREE(file->lines, l) + { + if (l->content) + free(l->content); + free(l); + } + + free(file); +} + +EAPI void elm_code_file_close(Elm_Code_File *file) +{ + eina_file_close(file->file); +} + +EAPI const char *elm_code_file_filename_get(Elm_Code_File *file) +{ + return basename((char *)eina_file_filename_get(file->file)); +} + +EAPI const char *elm_code_file_path_get(Elm_Code_File *file) +{ + return eina_file_filename_get(file->file); +} + +EAPI void elm_code_file_clear(Elm_Code_File *file) +{ + Elm_Code_Line *l; + + EINA_LIST_FREE(file->lines, l) + { + if (l->content) + free(l->content); + free(l); + } + + if (file->parent) + elm_code_callback_fire(file->parent, &ELM_CODE_EVENT_FILE_LOAD_DONE, file); +} + +EAPI unsigned int elm_code_file_lines_get(Elm_Code_File *file) +{ + return eina_list_count(file->lines); +} + + +EAPI void elm_code_file_line_append(Elm_Code_File *file, const char *line) +{ + int row; + + row = elm_code_file_lines_get(file); + _elm_code_file_line_append_data(file, line, strlen(line), row+1); +} + +EAPI Elm_Code_Line *elm_code_file_line_get(Elm_Code_File *file, unsigned int number) +{ + return eina_list_nth(file->lines, number - 1); +} + +EAPI char *elm_code_file_line_content_get(Elm_Code_File *file, unsigned int number) +{ + Elm_Code_Line *line; + + line = elm_code_file_line_get(file, number); + + if (!line) + return NULL; + return line->content; +} + +EAPI void elm_code_file_line_status_set(Elm_Code_File *file, unsigned int number, Elm_Code_Status_Type status) +{ + Elm_Code_Line *line; + + line = elm_code_file_line_get(file, number); + + if (!line) + return; + + line->status = status; + + if (file->parent) + elm_code_callback_fire(file->parent, &ELM_CODE_EVENT_LINE_SET_DONE, line); +} + +EAPI void elm_code_file_line_token_add(Elm_Code_File *file, unsigned int number, int start, int end, + Elm_Code_Token_Type type) +{ + Elm_Code_Line *line; + Elm_Code_Token *tok; + + line = elm_code_file_line_get(file, number); + tok = calloc(1, sizeof(Elm_Code_Token)); + + tok->start = start; + tok->end = end; + tok->type = type; + + line->tokens = eina_list_append(line->tokens, tok); + + if (file->parent) + elm_code_callback_fire(file->parent, &ELM_CODE_EVENT_LINE_SET_DONE, line); +} + diff --git a/elm_code/lib/elm_code_file.h b/elm_code/lib/elm_code_file.h new file mode 100644 index 0000000..c3ebfb9 --- /dev/null +++ b/elm_code/lib/elm_code_file.h @@ -0,0 +1,102 @@ +#ifndef ELM_CODE_FILE_H_ +# define ELM_CODE_FILE_H_ + +#include + +#include "elm_code_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file + * @brief These routines are used for interacting with files using Elm Code. + */ + +typedef struct _Elm_Code_Token +{ + int start, end; + + Elm_Code_Token_Type type; + +} Elm_Code_Token; + +typedef struct _Elm_Code_Line +{ + char *content; + unsigned int number; + + Elm_Code_Status_Type status; + Eina_List *tokens; + + +} Elm_Code_Line; + +typedef struct _Elm_Code_File +{ + void *parent; + + Eina_List *lines; + Eina_File *file; + +} Elm_Code_File; + +/** + * @brief File handling functions. + * @defgroup File I/O at a file level + * + * @{ + * + * Functions for file handling within elm code. + * + */ + +EAPI Elm_Code_File *elm_code_file_new(Elm_Code *code); + +EAPI Elm_Code_File *elm_code_file_open(Elm_Code *code, const char *path); + +EAPI void elm_code_file_free(Elm_Code_File *file); + +EAPI void elm_code_file_close(Elm_Code_File *file); + +EAPI const char *elm_code_file_filename_get(Elm_Code_File *file); + +EAPI const char *elm_code_file_path_get(Elm_Code_File *file); + +/** + * @} + * + * @brief Content functions. + * @defgroup Content Functions for accessing file content + * + * @{ + * + * File content handling functions. + * + */ + +EAPI void elm_code_file_clear(Elm_Code_File *file); + +EAPI unsigned int elm_code_file_lines_get(Elm_Code_File *file); + +EAPI void elm_code_file_line_append(Elm_Code_File *file, const char *line); + +EAPI Elm_Code_Line *elm_code_file_line_get(Elm_Code_File *file, unsigned int line); + +EAPI char *elm_code_file_line_content_get(Elm_Code_File *file, unsigned int line); + +EAPI void elm_code_file_line_status_set(Elm_Code_File *file, unsigned int line, Elm_Code_Status_Type status); + +EAPI void elm_code_file_line_token_add(Elm_Code_File *file, unsigned int number, int start, int end, + Elm_Code_Token_Type type); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ELM_CODE_FILE_H_ */ diff --git a/elm_code/lib/elm_code_parse.c b/elm_code/lib/elm_code_parse.c new file mode 100644 index 0000000..2b1ddc2 --- /dev/null +++ b/elm_code/lib/elm_code_parse.c @@ -0,0 +1,47 @@ +#ifdef HAVE_CONFIG +# include "config.h" +#endif + +#include "Elm_Code.h" +#include "elm_code_parse.h" + +#include "elm_code_private.h" + +EAPI void elm_code_parse_line(Elm_Code *code, Elm_Code_Line *line) +{ + Elm_Code_Parser *parser; + Eina_List *item; + + EINA_LIST_FOREACH(code->parsers, item, parser) + { + parser->parse_line(line); + } +} + +EAPI void elm_code_parse_file(Elm_Code *code, Elm_Code_File *file) +{ + Elm_Code_Parser *parser; + Eina_List *item; + + EINA_LIST_FOREACH(code->parsers, item, parser) + { + parser->parse_file(file); + } +} + +EAPI void elm_code_parser_add(Elm_Code *code, + void (*parse_line)(Elm_Code_Line *), + void (*parse_file)(Elm_Code_File *)) +{ + Elm_Code_Parser *parser; + + parser = calloc(1, sizeof(Elm_Code_Parser)); + if (!parser) + return; + + parser->parse_line = parse_line; + parser->parse_file = parse_file; + + code->parsers = eina_list_append(code->parsers, parser); +} + diff --git a/elm_code/lib/elm_code_parse.h b/elm_code/lib/elm_code_parse.h new file mode 100644 index 0000000..ab50c34 --- /dev/null +++ b/elm_code/lib/elm_code_parse.h @@ -0,0 +1,49 @@ +#ifndef ELM_CODE_PARSE_H_ +# define ELM_CODE_PARSE_H_ + +#include + +#include "elm_code_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file + * @brief These routines are used for handling the parsing of Elm Code content. + */ + +typedef struct _Elm_Code_Parser +{ + void (*parse_line)(Elm_Code_Line *); + + void (*parse_file)(Elm_Code_File *); +} Elm_Code_Parser; + +/** + * @brief Parser helper functions. + * @defgroup Parser Hooking in and launching parsers + * + * @{ + * + * Parser functions for marking up elm code. + * + */ + +EAPI void elm_code_parser_add(Elm_Code *code, void (*parse_line)(Elm_Code_Line *), + void (*parse_file)(Elm_Code_File *)); + +EAPI void elm_code_parse_line(Elm_Code *code, Elm_Code_Line *line); + +EAPI void elm_code_parse_file(Elm_Code *code, Elm_Code_File *file); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ELM_CODE_PARSE_H_ */ diff --git a/elm_code/lib/elm_code_private.h b/elm_code/lib/elm_code_private.h new file mode 100644 index 0000000..d1ff328 --- /dev/null +++ b/elm_code/lib/elm_code_private.h @@ -0,0 +1,27 @@ +#ifndef ELM_CODE_PRIVATE_H +# define ELM_CODE_PRIVATE_H + +extern int _elm_code_lib_log_dom; + +#ifdef ERR +# undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_elm_code_lib_log_dom, __VA_ARGS__) +#ifdef INF +# undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_elm_code_lib_log_dom, __VA_ARGS__) +#ifdef WRN +# undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_elm_code_lib_log_dom, __VA_ARGS__) +#ifdef CRIT +# undef CRIT +#endif +#define CRIT(...) EINA_LOG_DOM_CRIT(_elm_code_lib_log_dom, __VA_ARGS__) +#ifdef DBG +# undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_elm_code_lib_log_dom, __VA_ARGS__) + +#endif diff --git a/elm_code/lib/elm_code_widget.c b/elm_code/lib/elm_code_widget.c new file mode 100644 index 0000000..9d44163 --- /dev/null +++ b/elm_code/lib/elm_code_widget.c @@ -0,0 +1,224 @@ +#ifdef HAVE_CONFIG +# include "config.h" +#endif + +#include +#include + +#include "elm_code_widget.h" + +#include "elm_code_private.h" + +Eina_Unicode status_icons[] = { + ' ', + '!', + + '+', + '-', + ' ', + + 0x2713, + 0x2717, + + 0 +}; + +static Eina_Bool _elm_code_widget_resize(Evas_Object *o) +{ + int w, h, cw, ch; + + evas_object_geometry_get(o, NULL, NULL, &w, &h); + evas_object_textgrid_cell_size_get(o, &cw, &ch); + evas_object_textgrid_size_set(o, ceil(((double) w) / cw), + ceil(((double) h) / ch)); + + return h > 0 && w > 0; +} + +static void _elm_code_widget_fill_line_token(Evas_Textgrid_Cell *cells, int count, int start, int end, Elm_Code_Token_Type type) +{ + int x; + + for (x = start; x <= end && x < count; x++) + { + cells[x].fg = type; + } +} + +EAPI void elm_code_widget_fill_line_tokens(Evas_Textgrid_Cell *cells, int count, Elm_Code_Line *line) +{ + Eina_List *item; + Elm_Code_Token *token; + int start, length; + + start = 1; + length = strlen(line->content); + + EINA_LIST_FOREACH(line->tokens, item, token) + { + + _elm_code_widget_fill_line_token(cells, count, start, token->start, ELM_CODE_TOKEN_TYPE_DEFAULT); + + // TODO handle a token starting before the previous finishes + _elm_code_widget_fill_line_token(cells, count, token->start, token->end, token->type); + + start = token->end + 1; + } + + _elm_code_widget_fill_line_token(cells, count, start, length, ELM_CODE_TOKEN_TYPE_DEFAULT); +} + +static void _elm_code_widget_fill_line(Evas_Object *o, Evas_Textgrid_Cell *cells, Elm_Code_Line *line) +{ + char *chr; + unsigned int length, x; + int w; + + if (!_elm_code_widget_resize(o)) + return; + + length = strlen(line->content); + evas_object_textgrid_size_get(o, &w, NULL); + + cells[0].codepoint = status_icons[line->status]; + cells[0].bold = 1; + cells[0].fg = ELM_CODE_TOKEN_TYPE_DEFAULT; + cells[0].bg = line->status; + + chr = (char *)line->content; + for (x = 1; x < (unsigned int) w && x <= length; x++) + { + cells[x].codepoint = *chr; + cells[x].bg = line->status; + + chr++; + } + for (; x < (unsigned int) w; x++) + { + cells[x].codepoint = 0; + cells[x].bg = line->status; + } + + elm_code_widget_fill_line_tokens(cells, w, line); + + evas_object_textgrid_update_add(o, 0, line->number - 1, w, 1); +} + +EAPI void elm_code_widget_fill(Evas_Object *o, Elm_Code *code) +{ + Elm_Code_Line *line; + Evas_Textgrid_Cell *cells; + int w, h; + unsigned int y; + + if (!_elm_code_widget_resize(o)) + return; + evas_object_textgrid_size_get(o, &w, &h); + + for (y = 1; y <= (unsigned int) h && y <= elm_code_file_lines_get(code->file); y++) + { + line = elm_code_file_line_get(code->file, y); + + cells = evas_object_textgrid_cellrow_get(o, y - 1); + _elm_code_widget_fill_line(o, cells, line); + } +} + +static Eina_Bool +_elm_code_widget_line_cb(void *data EINA_UNUSED, Eo *obj, + const Eo_Event_Description *desc EINA_UNUSED, void *event_info) +{ + Elm_Code_Line *line; + Evas_Object *o; + int h; + + Evas_Textgrid_Cell *cells; + + line = (Elm_Code_Line *)event_info; + o = (Evas_Object *)obj; + + evas_object_textgrid_size_get(o, NULL, &h); + + if (line->number > (unsigned int) h) + return EINA_TRUE; + + cells = evas_object_textgrid_cellrow_get(o, line->number - 1); + _elm_code_widget_fill_line(o, cells, line); + + return EINA_TRUE; +} + + +static Eina_Bool +_elm_code_widget_file_cb(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Evas_Object *o; + Elm_Code *code; + + code = (Elm_Code *)data; + o = (Evas_Object *)obj; + + elm_code_widget_fill(o, code); + return EINA_TRUE; +} + +static void +_elm_code_widget_resize_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, + void *event_info EINA_UNUSED) +{ + Elm_Code *code; + + code = (Elm_Code *)data; + + elm_code_widget_fill(obj, code); +} + +EAPI Evas_Object *elm_code_widget_add(Evas_Object *parent, Elm_Code *code) +{ + Evas_Object *o; + + o = evas_object_textgrid_add(parent); + + evas_object_textgrid_font_set(o, "Mono", 10 * elm_config_scale_get()); + + // setup status colors + evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_STATUS_TYPE_DEFAULT, + 36, 36, 36, 255); + evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_STATUS_TYPE_ERROR, + 205, 54, 54, 255); + + evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_STATUS_TYPE_ADDED, + 36, 96, 36, 255); + evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_STATUS_TYPE_REMOVED, + 96, 36, 36, 255); + evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_STATUS_TYPE_CHANGED, + 36, 36, 96, 255); + + evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_STATUS_TYPE_PASSED, + 54, 96, 54, 255); + evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_STATUS_TYPE_FAILED, + 96, 54, 54, 255); + + // setup token colors + evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_TOKEN_TYPE_DEFAULT, + 205, 205, 205, 255); + evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_TOKEN_TYPE_COMMENT, + 54, 205, 255, 255); + + evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_TOKEN_TYPE_ADDED, + 54, 255, 54, 255); + evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_TOKEN_TYPE_REMOVED, + 255, 54, 54, 255); + evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_TOKEN_TYPE_CHANGED, + 54, 54, 255, 255); + + evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE, _elm_code_widget_resize_cb, code); + + eo_do(o,eo_event_callback_add(&ELM_CODE_EVENT_LINE_SET_DONE, _elm_code_widget_line_cb, code)); + eo_do(o,eo_event_callback_add(&ELM_CODE_EVENT_FILE_LOAD_DONE, _elm_code_widget_file_cb, code)); + + code->widgets = eina_list_append(code->widgets, o); + return o; +} + diff --git a/elm_code/lib/elm_code_widget.h b/elm_code/lib/elm_code_widget.h new file mode 100644 index 0000000..8c2bf77 --- /dev/null +++ b/elm_code/lib/elm_code_widget.h @@ -0,0 +1,40 @@ +#ifndef ELM_CODE_WIDGET_H_ +# define ELM_CODE_WIDGET_H_ + +#include +#include +#include "elm_code_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file + * @brief These routines are used for rendering instances of Elm Code. + */ + +/** + * @brief UI Loading functions. + * @defgroup Init Creating a widget to render an Elm Code backend + * + * @{ + * + * Functions for UI loading. + * + */ + +EAPI Evas_Object *elm_code_widget_add(Evas_Object *parent, Elm_Code *code); +EAPI void elm_code_widget_fill(Evas_Object *o, Elm_Code *code); + +EAPI void elm_code_widget_fill_line_tokens(Evas_Textgrid_Cell *cells, int count, Elm_Code_Line *line); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ELM_CODE_WIDGET_H_ */ diff --git a/elm_code/tests/Makefile.am b/elm_code/tests/Makefile.am new file mode 100644 index 0000000..d1edb30 --- /dev/null +++ b/elm_code/tests/Makefile.am @@ -0,0 +1,26 @@ + +if EFL_HAVE_TESTS + +check_PROGRAMS = elm_code_suite + +elm_code_suite_SOURCES = \ +elm_code_file_test_load.c \ +elm_code_file_test_memory.c \ +elm_code_test_basic.c \ +elm_code_test_parse.c \ +elm_code_test_widget.c \ +elm_code_suite.c + +elm_code_suite_CPPFLAGS = -I$(top_builddir)/elm_code/lib/ \ +-DPACKAGE_TESTS_DIR=\"$(top_srcdir)/elm_code/tests/\" \ +-DPACKAGE_BUILD_DIR=\"`pwd`/$(top_builddir)/elm_code/tests/\" \ +-DEFL_BETA_API_SUPPORT \ +@EFL_CFLAGS@ \ +@CHECK_CFLAGS@ + +elm_code_suite_LDADD = @CHECK_LIBS@ $(top_builddir)/elm_code/lib/libelm_code.la +elm_code_suite_DEPENDENCIES = $(top_builddir)/elm_code/lib/libelm_code.la + +endif + +EXTRA_DIST = elm_code_suite.h diff --git a/elm_code/tests/elm_code_file_test_load.c b/elm_code/tests/elm_code_file_test_load.c new file mode 100644 index 0000000..ad7dc38 --- /dev/null +++ b/elm_code/tests/elm_code_file_test_load.c @@ -0,0 +1,78 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "elm_code_suite.h" + +START_TEST (elm_code_file_load) +{ + char *path = "elm_code/tests/testfile.txt"; + char real[EINA_PATH_MAX]; + Elm_Code_File *file; + Elm_Code *code; + + code = elm_code_create(); + file = elm_code_file_open(code, path); + realpath(path, real); + + ck_assert_str_eq(basename(path), elm_code_file_filename_get(file)); + ck_assert_str_eq(real, elm_code_file_path_get(file)); + elm_code_file_close(file); + elm_code_free(code); +} +END_TEST + +START_TEST (elm_code_file_load_lines) +{ + char *path = "elm_code/tests/testfile.txt"; + Elm_Code_File *file; + Elm_Code *code; + + code = elm_code_create(); + file = elm_code_file_open(code, path); + + ck_assert_uint_eq(4, elm_code_file_lines_get(file)); + elm_code_file_close(file); + elm_code_free(code); +} +END_TEST + +START_TEST (elm_code_file_load_blank_lines) +{ + char *path = "elm_code/tests/testfile-withblanks.txt"; + Elm_Code_File *file; + Elm_Code *code; + + code = elm_code_create(); + file = elm_code_file_open(code, path); + + ck_assert_uint_eq(8, elm_code_file_lines_get(file)); + elm_code_file_close(file); + elm_code_free(code); +} +END_TEST + +START_TEST (elm_code_file_load_content) +{ + char *path = "elm_code/tests/testfile.txt"; + Elm_Code_File *file; + Elm_Code *code; + + code = elm_code_create(); + file = elm_code_file_open(code, path); + + ck_assert_str_eq("line2", elm_code_file_line_content_get(file, 2)); + ck_assert_str_eq("another line", elm_code_file_line_content_get(file, 4)); + elm_code_file_close(file); + elm_code_free(code); +} +END_TEST + +void elm_code_file_test_load(TCase *tc) +{ + tcase_add_test(tc, elm_code_file_load); + tcase_add_test(tc, elm_code_file_load_lines); + tcase_add_test(tc, elm_code_file_load_blank_lines); + tcase_add_test(tc, elm_code_file_load_content); +} + diff --git a/elm_code/tests/elm_code_file_test_memory.c b/elm_code/tests/elm_code_file_test_memory.c new file mode 100644 index 0000000..b359868 --- /dev/null +++ b/elm_code/tests/elm_code_file_test_memory.c @@ -0,0 +1,46 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "elm_code_suite.h" + +START_TEST (elm_code_file_memory_lines) +{ + Elm_Code_File *file; + Elm_Code *code; + + code = elm_code_create(); + file = elm_code_file_new(code); + ck_assert_uint_eq(0, elm_code_file_lines_get(file)); + + elm_code_file_line_append(file, "a line"); + + ck_assert_uint_eq(1, elm_code_file_lines_get(file)); + elm_code_free(code); +} +END_TEST + +START_TEST (elm_code_file_memory_tokens) +{ + Elm_Code_File *file; + Elm_Code_Line *line; + Elm_Code *code; + + code = elm_code_create(); + file = elm_code_file_new(code); + + elm_code_file_line_append(file, "a line"); + elm_code_file_line_token_add(file, 1, 2, 5, ELM_CODE_TOKEN_TYPE_COMMENT); + + line = elm_code_file_line_get(file, 1); + ck_assert_uint_eq(1, eina_list_count(line->tokens)); + elm_code_free(code); +} +END_TEST + +void elm_code_file_test_memory(TCase *tc) +{ + tcase_add_test(tc, elm_code_file_memory_lines); + tcase_add_test(tc, elm_code_file_memory_tokens); +} + diff --git a/elm_code/tests/elm_code_suite.c b/elm_code/tests/elm_code_suite.c new file mode 100644 index 0000000..e2250cd --- /dev/null +++ b/elm_code/tests/elm_code_suite.c @@ -0,0 +1,126 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "Elm_Code.h" +#include "elm_code_suite.h" + +#define COPYRIGHT "Copyright © 2014 Andy Williams and various contributors (see AUTHORS)." + +static const struct { + const char *name; + void (*build)(TCase *tc); +} tests[] = { + { "file_load", elm_code_file_test_load }, + { "file_memory", elm_code_file_test_memory }, + { "parse", elm_code_test_parse }, + { "basic", elm_code_test_basic }, + { "widget", elm_code_test_widget }, +}; + +START_TEST(elm_code_initialization) +{ + fail_if(elm_code_init() != 1); + +// TODO add other init checks here + + fail_if(elm_code_shutdown() != 0); +} +END_TEST + +void +edi_test_basic(TCase *tc) +{ + tcase_add_test(tc, elm_code_initialization); +} + +static const Ecore_Getopt optdesc = { + "elm_code", + "%prog [options]", + PACKAGE_VERSION, + COPYRIGHT, + "BSD with advertisement clause", + "Elm Code", + 0, + { + ECORE_GETOPT_STORE_TRUE('l', "list", "list available tests"), + ECORE_GETOPT_STORE_STR('t', "test", "test to run"), + ECORE_GETOPT_LICENSE('L', "license"), + ECORE_GETOPT_COPYRIGHT('C', "copyright"), + ECORE_GETOPT_VERSION('V', "version"), + ECORE_GETOPT_HELP('h', "help"), + ECORE_GETOPT_SENTINEL + } +}; + +int +main(int argc EINA_UNUSED, char **argv EINA_UNUSED) +{ + Suite *s; + SRunner *sr; + TCase *tc = NULL; + char *test = NULL; + unsigned int i; + int failed_count = -1; + int args; + Eina_Bool quit_option = EINA_FALSE; + Eina_Bool list_option = EINA_FALSE; + + Ecore_Getopt_Value values[] = { + ECORE_GETOPT_VALUE_BOOL(list_option), + ECORE_GETOPT_VALUE_STR(test), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_NONE + }; + + eina_init(); + + args = ecore_getopt_parse(&optdesc, values, argc, argv); + if (args < 0) + { + EINA_LOG_CRIT("Could not parse arguments."); + goto end; + } + else if (quit_option) + { + goto end; + } + else if (list_option) + { + fprintf(stdout, "Available tests :\n"); + for (i = 0; i < sizeof (tests) / sizeof (tests[0]); i++) + fprintf(stdout, "\t%s\n", tests[i].name); + goto end; + } + + s = suite_create("Elm_Code"); + + for (i = 0; i < sizeof (tests) / sizeof (tests[0]); i++) + { + if (test && strcmp(tests[i].name, test)) + continue ; + + tc = tcase_create(tests[i].name); + tcase_set_timeout(tc, 0); + + tests[i].build(tc); + suite_add_tcase(s, tc); + } + + sr = srunner_create(s); + srunner_set_xml(sr, PACKAGE_BUILD_DIR "/check-results.xml"); + + srunner_run_all(sr, CK_ENV); + failed_count = srunner_ntests_failed(sr); + srunner_free(sr); + + end: + eina_shutdown(); + + return (failed_count == 0) ? 0 : 255; +} diff --git a/elm_code/tests/elm_code_suite.h b/elm_code/tests/elm_code_suite.h new file mode 100644 index 0000000..58d6317 --- /dev/null +++ b/elm_code/tests/elm_code_suite.h @@ -0,0 +1,14 @@ +#ifndef _ELM_CODE_SUITE_H +#define _ELM_CODE_SUITE_H + +#include + +#include + +void elm_code_file_test_load(TCase *tc); +void elm_code_file_test_memory(TCase *tc); +void elm_code_test_basic(TCase *tc); +void elm_code_test_parse(TCase *tc); +void elm_code_test_widget(TCase *tc); + +#endif /* _EDLM_CODE_SUITE_H */ diff --git a/elm_code/tests/elm_code_test_basic.c b/elm_code/tests/elm_code_test_basic.c new file mode 100644 index 0000000..81a34bb --- /dev/null +++ b/elm_code/tests/elm_code_test_basic.c @@ -0,0 +1,24 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "elm_code_suite.h" + +START_TEST (elm_code_create_test) +{ + char *path = "elm_code/tests/testfile.txt"; + Elm_Code *code; + + code = elm_code_create(); + elm_code_file_open(code, path); + + ck_assert(code); + elm_code_free(code); +} +END_TEST + +void elm_code_test_basic(TCase *tc) +{ + tcase_add_test(tc, elm_code_create_test); +} + diff --git a/elm_code/tests/elm_code_test_parse.c b/elm_code/tests/elm_code_test_parse.c new file mode 100644 index 0000000..3c4868e --- /dev/null +++ b/elm_code/tests/elm_code_test_parse.c @@ -0,0 +1,68 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "elm_code_suite.h" +#include "elm_code_parse.h" + +static int line_calls, file_calls; + +static void _parser_line_callback(Elm_Code_Line *line EINA_UNUSED) +{ + line_calls++; +} + +static void _parser_file_callback(Elm_Code_File *file EINA_UNUSED) +{ + file_calls++; +} + +START_TEST (elm_code_parse_hook_memory_test) +{ + Elm_Code *code; + Elm_Code_File *file; + + line_calls = 0; + file_calls = 0; + + code = elm_code_create(); + file = elm_code_file_new(code); + + elm_code_parser_add(code, _parser_line_callback, _parser_file_callback); + elm_code_file_line_append(file, "some \"test content\" for parsing"); + + ck_assert_int_eq(1, line_calls); + ck_assert_int_eq(0, file_calls); + + elm_code_free(code); +} +END_TEST + +START_TEST (elm_code_parse_hook_file_test) +{ + Elm_Code *code; + Elm_Code_File *file; + char *path = "elm_code/tests/testfile.txt"; + + line_calls = 0; + file_calls = 0; + + code = elm_code_create(); + + elm_code_parser_add(code, _parser_line_callback, _parser_file_callback); + file = elm_code_file_open(code, path); + + ck_assert_int_eq(4, line_calls); + ck_assert_int_eq(1, file_calls); + + elm_code_file_close(file); + elm_code_free(code); +} +END_TEST + +void elm_code_test_parse(TCase *tc) +{ + tcase_add_test(tc, elm_code_parse_hook_memory_test); + tcase_add_test(tc, elm_code_parse_hook_file_test); +} + diff --git a/elm_code/tests/elm_code_test_widget.c b/elm_code/tests/elm_code_test_widget.c new file mode 100644 index 0000000..27b867e --- /dev/null +++ b/elm_code/tests/elm_code_test_widget.c @@ -0,0 +1,46 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "elm_code_suite.h" + +static void _assert_cell_type(Evas_Textgrid_Cell cell, Elm_Code_Token_Type type) +{ + ck_assert(cell.fg == type); +} + +START_TEST (elm_code_widget_token_render_simple_test) +{ + Elm_Code_File *file; + Elm_Code_Line *line; + Elm_Code *code; + int length; + + Evas_Textgrid_Cell cells[25]; + + code = elm_code_create(); + file = elm_code_file_new(code); + elm_code_file_line_append(file, "some \"test content\", 45"); + line = elm_code_file_line_get(file, 1); + length = strlen(line->content); + + elm_code_file_line_token_add(file, 1, 6+1, 18+1, ELM_CODE_TOKEN_TYPE_COMMENT); + elm_code_file_line_token_add(file, 1, 22+1, 23+1, ELM_CODE_TOKEN_TYPE_COMMENT); + + elm_code_widget_fill_line_tokens(cells, length, line); + _assert_cell_type(cells[0], ELM_CODE_TOKEN_TYPE_DEFAULT); + _assert_cell_type(cells[3], ELM_CODE_TOKEN_TYPE_DEFAULT); + _assert_cell_type(cells[5], ELM_CODE_TOKEN_TYPE_DEFAULT); + _assert_cell_type(cells[15], ELM_CODE_TOKEN_TYPE_COMMENT); + _assert_cell_type(cells[19], ELM_CODE_TOKEN_TYPE_DEFAULT); + _assert_cell_type(cells[22], ELM_CODE_TOKEN_TYPE_COMMENT); + + elm_code_free(code); +} +END_TEST + +void elm_code_test_widget(TCase *tc) +{ + tcase_add_test(tc, elm_code_widget_token_render_simple_test); +} + diff --git a/elm_code/tests/testfile-withblanks.txt b/elm_code/tests/testfile-withblanks.txt new file mode 100644 index 0000000..0f2ead3 --- /dev/null +++ b/elm_code/tests/testfile-withblanks.txt @@ -0,0 +1,8 @@ +line 1 +line2 + +another link + + +double blank +8 diff --git a/elm_code/tests/testfile.txt b/elm_code/tests/testfile.txt new file mode 100644 index 0000000..8fd6a8b --- /dev/null +++ b/elm_code/tests/testfile.txt @@ -0,0 +1,4 @@ +line 1 +line2 +a third +another line diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 1af7148..35bc17f 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -6,8 +6,9 @@ bin_PROGRAMS = edi edi_build AM_CPPFLAGS = -DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ -I$(top_builddir)/src/bin/ \ -I$(top_srcdir)/src/bin/ \ +-I$(top_srcdir)/elm_code/lib \ -I$(top_builddir)/src/lib/ \ --I$(top_srcdir)/src/lib/ \ +-DEFL_BETA_API_SUPPORT \ @EFL_CFLAGS@ edi_SOURCES = \ @@ -21,7 +22,7 @@ mainview/edi_mainview_item.c \ mainview/edi_mainview.c \ edi_main.c -edi_LDADD = @EFL_LIBS@ $(top_builddir)/src/lib/libedi.la +edi_LDADD = @EFL_LIBS@ $(top_builddir)/elm_code/lib/libelm_code.la $(top_builddir)/src/lib/libedi.la edi_build_SOURCES = \ edi_build_main.c diff --git a/src/bin/edi_consolepanel.c b/src/bin/edi_consolepanel.c index 20fe7c1..f790d58 100644 --- a/src/bin/edi_consolepanel.c +++ b/src/bin/edi_consolepanel.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -18,6 +19,13 @@ static Evas_Object *_console_box; static const char *_current_dir = NULL; +static int _edi_test_count; +static int _edi_test_pass; +static int _edi_test_fail; + +static Elm_Code *_edi_test_code; +static void _edi_test_line_callback(const char *content); + static const char *_edi_consolepanel_icon_for_line(const char *line) { if (strstr(line, " error:") != NULL) @@ -153,6 +161,8 @@ static void _edi_consolepanel_append_line_type(const char *line, Eina_Bool err) elm_box_pack_end(_console_box, box); _edi_consolepanel_scroll_to_bottom(); + + _edi_test_line_callback(line); } void edi_consolepanel_append_line(const char *line) @@ -168,6 +178,11 @@ void edi_consolepanel_append_error_line(const char *line) void edi_consolepanel_clear() { elm_box_clear(_console_box); + + elm_code_file_clear(_edi_test_code->file); + _edi_test_count = 0; + _edi_test_pass = 0; + _edi_test_fail = 0; } static Eina_Bool @@ -196,6 +211,87 @@ _exe_error(void *d EINA_UNUSED, int t EINA_UNUSED, void *event_info) return ECORE_CALLBACK_RENEW; } +static void _edi_test_append(const char *content, Elm_Code_Status_Type type) +{ + elm_code_file_line_append(_edi_test_code->file, content); + elm_code_file_line_status_set(_edi_test_code->file, elm_code_file_lines_get(_edi_test_code->file), type); +} + +static void _edi_test_line_parse_suite(const char *path) +{ + Eina_File *file; + Eina_File_Line *line; + Eina_Iterator *it; + char logfile[PATH_MAX], *tmp; + int pathlength; + Elm_Code_Status_Type status; + + pathlength = strlen(path); + snprintf(logfile, pathlength + 4 + 1, "%s.log", path); + + file = eina_file_open(logfile, EINA_FALSE); + + it = eina_file_map_lines(file); + EINA_ITERATOR_FOREACH(it, line) + { + status = ELM_CODE_STATUS_TYPE_DEFAULT; + tmp = malloc(line->length + 1); + strncpy(tmp, line->start, line->length); + tmp[line->length] = 0; + + if (strstr(tmp, ":P:")) + status = ELM_CODE_STATUS_TYPE_PASSED; + else if (strstr(tmp, ":F:")) + status = ELM_CODE_STATUS_TYPE_FAILED; + + _edi_test_append(tmp, status); + free(tmp); + } + eina_iterator_free(it); +} + +static void _edi_test_line_parse_suite_pass_line(const char *line) +{ + _edi_test_line_parse_suite(line); + _edi_test_append("Suite passed", ELM_CODE_STATUS_TYPE_DEFAULT); +} + +static void _edi_test_line_parse_suite_fail_line(const char *line) +{ + _edi_test_line_parse_suite(line); + _edi_test_append("Suite failed", ELM_CODE_STATUS_TYPE_DEFAULT); +} + +static void _edi_test_line_parse_summary_line(const char *line) +{ + _edi_test_append(line, ELM_CODE_STATUS_TYPE_DEFAULT); +} + +static void _edi_test_line_callback(const char *content) +{ + if (!content) + return; + + if (content[0] == '#') + { + _edi_test_line_parse_summary_line(content + 2); + return; + } + + if (!strncmp(content, "PASS:", 5)) + { + _edi_test_count++; + _edi_test_pass++; + _edi_test_line_parse_suite_pass_line(content + 6); + } + else if (!strncmp(content, "FAIL:", 5)) + { + _edi_test_count++; + _edi_test_fail++; + _edi_test_line_parse_suite_fail_line(content + 6); + } +} + void edi_consolepanel_add(Evas_Object *parent) { Evas_Object *scroll, *vbx; @@ -217,3 +313,22 @@ void edi_consolepanel_add(Evas_Object *parent) ecore_event_handler_add(ECORE_EXE_EVENT_DATA, _exe_data, NULL); ecore_event_handler_add(ECORE_EXE_EVENT_ERROR, _exe_error, NULL); } + +void edi_testpanel_add(Evas_Object *parent) +{ + Elm_Code *code; + Evas_Object *widget; + + code = elm_code_create(); + _edi_test_code = code; + elm_code_file_new(code); + + widget = elm_code_widget_add(parent, code); + + evas_object_size_hint_weight_set(widget, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(widget, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(widget); + + elm_object_content_set(parent, widget); +} + diff --git a/src/bin/edi_consolepanel.h b/src/bin/edi_consolepanel.h index bd51a8b..37cf1fc 100644 --- a/src/bin/edi_consolepanel.h +++ b/src/bin/edi_consolepanel.h @@ -38,6 +38,10 @@ EAPI void edi_consolepanel_add(Evas_Object *parent); */ EAPI void edi_consolepanel_show(); +EAPI void edi_testpanel_add(Evas_Object *parent); + +EAPI void edi_testpanel_show(); + /** * @} */ diff --git a/src/bin/edi_logpanel.c b/src/bin/edi_logpanel.c index 20af9f6..c065fb5 100644 --- a/src/bin/edi_logpanel.c +++ b/src/bin/edi_logpanel.c @@ -3,12 +3,14 @@ #endif #include +#include #include "edi_logpanel.h" #include "edi_private.h" -static Evas_Object *_info_box; +static Evas_Object *_info_widget; +static Elm_Code *_elm_code; void print_cb(const Eina_Log_Domain *domain, Eina_Log_Level level, @@ -19,47 +21,39 @@ void print_cb(const Eina_Log_Domain *domain, EINA_UNUSED void *data, va_list args) { - Evas_Object *txt; - unsigned int printed, buffer_len = 512; + unsigned int printed, line_count, buffer_len = 512; char buffer [buffer_len]; printed = snprintf(buffer, buffer_len, "%s:%s:%s (%d): ", domain->domain_str, file, fnc, line); vsnprintf(buffer + printed, buffer_len - printed, fmt, args); - txt = elm_label_add(_info_box); + elm_code_file_line_append(_elm_code->file, buffer); if (level <= EINA_LOG_LEVEL_ERR) - evas_object_color_set(txt, 255, 63, 63, 255); - else - evas_object_color_set(txt, 255, 255, 255, 255); + { + line_count = elm_code_file_lines_get(_elm_code->file); - elm_object_text_set(txt, buffer); - evas_object_size_hint_weight_set(txt, EVAS_HINT_EXPAND, 0.1); - evas_object_size_hint_align_set(txt, 0.0, EVAS_HINT_FILL); - evas_object_show(txt); - - elm_box_pack_end(_info_box, txt); + elm_code_file_line_status_set(_elm_code->file, line_count, ELM_CODE_STATUS_TYPE_ERROR); + } } void edi_logpanel_add(Evas_Object *parent) { - Evas_Object *scroll, *vbx; + Evas_Object *widget; + Elm_Code *code; - scroll = elm_scroller_add(parent); - elm_scroller_gravity_set(scroll, 0.0, 0.0); - evas_object_size_hint_weight_set(scroll, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_align_set(scroll, EVAS_HINT_FILL, EVAS_HINT_FILL); - evas_object_show(scroll); + code = elm_code_create(); + elm_code_file_new(code); + widget = elm_code_widget_add(parent, code); + evas_object_size_hint_weight_set(widget, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(widget, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(widget); - vbx = elm_box_add(parent); - evas_object_size_hint_weight_set(vbx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(vbx); - elm_object_content_set(scroll, vbx); - - _info_box = vbx; + _elm_code = code; + _info_widget = widget; eina_log_print_cb_set(print_cb, NULL); eina_log_color_disable_set(EINA_TRUE); - elm_object_content_set(parent, scroll); + elm_object_content_set(parent, widget); } diff --git a/src/bin/edi_main.c b/src/bin/edi_main.c index b475512..ebc2a2b 100644 --- a/src/bin/edi_main.c +++ b/src/bin/edi_main.c @@ -23,7 +23,7 @@ #define COPYRIGHT "Copyright © 2014 Andy Williams and various contributors (see AUTHORS)." -static Evas_Object *_edi_filepanel, *_edi_logpanel, *_edi_consolepanel; +static Evas_Object *_edi_filepanel, *_edi_logpanel, *_edi_consolepanel, *_edi_testpanel; static Evas_Object *_edi_main_win, *_edi_new_popup, *_edi_goto_popup; static void @@ -58,6 +58,11 @@ void edi_consolepanel_show() elm_panel_hidden_set(_edi_consolepanel, EINA_FALSE); } +void edi_testpanel_show() +{ + elm_panel_hidden_set(_edi_testpanel, EINA_FALSE); +} + static Evas_Object * edi_content_setup(Evas_Object *win, const char *path) { @@ -69,6 +74,7 @@ edi_content_setup(Evas_Object *win, const char *path) _edi_filepanel = elm_panel_add(win); _edi_logpanel = elm_panel_add(win); _edi_consolepanel = elm_panel_add(win); + _edi_testpanel = elm_panel_add(win); // add main content content_out = elm_box_add(win); @@ -119,6 +125,7 @@ edi_content_setup(Evas_Object *win, const char *path) elm_toolbar_item_append(tb, NULL, "Logs", _edi_toggle_panel, _edi_logpanel); elm_toolbar_item_append(tb, NULL, "Console", _edi_toggle_panel, _edi_consolepanel); + elm_toolbar_item_append(tb, NULL, "Tests", _edi_toggle_panel, _edi_testpanel); elm_panel_orient_set(_edi_logpanel, ELM_PANEL_ORIENT_BOTTOM); evas_object_size_hint_weight_set(_edi_logpanel, EVAS_HINT_EXPAND, 0.15); @@ -142,6 +149,17 @@ edi_content_setup(Evas_Object *win, const char *path) elm_table_pack(panes, _edi_consolepanel, 0, 4, 6, 1); evas_object_show(_edi_consolepanel); + elm_panel_orient_set(_edi_testpanel, ELM_PANEL_ORIENT_BOTTOM); + evas_object_size_hint_weight_set(_edi_testpanel, EVAS_HINT_EXPAND, 0.15); + evas_object_size_hint_align_set(_edi_testpanel, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(_edi_testpanel); + + elm_panel_hidden_set(_edi_testpanel, EINA_FALSE); + elm_panel_hidden_set(_edi_testpanel, EINA_TRUE); + edi_testpanel_add(_edi_testpanel); + elm_table_pack(panes, _edi_testpanel, 0, 4, 6, 1); + evas_object_show(_edi_testpanel); + evas_object_show(panes); return panes; } @@ -304,12 +322,15 @@ _tb_goto_cb(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUS } static Eina_Bool -_edi_build_prep(Evas_Object *button) +_edi_build_prep(Evas_Object *button, Eina_Bool test) { elm_toolbar_item_selected_set(elm_toolbar_selected_item_get(button), EINA_FALSE); edi_consolepanel_clear(); - edi_consolepanel_show(); + if (test) + edi_testpanel_show(); + else + edi_consolepanel_show(); if (!edi_builder_can_build()) { @@ -323,28 +344,28 @@ _edi_build_prep(Evas_Object *button) static void _tb_build_cb(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { - if (_edi_build_prep(obj)) + if (_edi_build_prep(obj, EINA_FALSE)) edi_builder_build(); } static void _tb_test_cb(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { - if (_edi_build_prep(obj)) + if (_edi_build_prep(obj, EINA_TRUE)) edi_builder_test(); } /* static void _tb_run_cb(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { - if (_edi_build_prep(obj)) + if (_edi_build_prep(obj, EINA_FALSE)) edi_builder_run(); } */ static void _tb_clean_cb(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { - if (_edi_build_prep(obj)) + if (_edi_build_prep(obj, EINA_FALSE)) edi_builder_clean(); } diff --git a/src/bin/editor/edi_editor.c b/src/bin/editor/edi_editor.c index 4ab6155..2c756f9 100644 --- a/src/bin/editor/edi_editor.c +++ b/src/bin/editor/edi_editor.c @@ -24,7 +24,7 @@ static Edi_Color EDI_COLOR_FOREGROUND = ""; static Edi_Color EDI_COLOR_COMMENT = ""; -//static Edi_Color EDI_COLOR_STRING = ""; +static Edi_Color EDI_COLOR_STRING = ""; static Edi_Color EDI_COLOR_NUMBER = "";// font_weight=Bold"; static Edi_Color EDI_COLOR_BRACE = ""; static Edi_Color EDI_COLOR_TYPE = ""; @@ -411,7 +411,10 @@ _clang_load_highlighting(const char *path, Edi_Editor *editor) } break; case CXToken_Literal: - color = EDI_COLOR_NUMBER; + if (cursors[i].kind == CXCursor_StringLiteral || cursors[i].kind == CXCursor_CharacterLiteral) + color = EDI_COLOR_STRING; + else + color = EDI_COLOR_NUMBER; break; case CXToken_Comment: color = EDI_COLOR_COMMENT; diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 39bb0d0..760c16d 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -10,7 +10,10 @@ AM_CPPFLAGS = \ lib_LTLIBRARIES = libedi.la -includes_HEADERS = Edi.h +includes_HEADERS = \ +edi_builder.h \ +edi_path.h \ +Edi.h includesdir = $(includedir)/edi-@VMAJ@ libedi_la_SOURCES = \ diff --git a/src/lib/edi_builder.c b/src/lib/edi_builder.c index 017e63f..eebeedc 100644 --- a/src/lib/edi_builder.c +++ b/src/lib/edi_builder.c @@ -54,7 +54,7 @@ EAPI void edi_builder_test(void) { chdir(edi_project_get()); - ecore_exe_pipe_run("make check", ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_PIPE_READ | + ecore_exe_pipe_run("CK_VERBOSITY=verbose make check", ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR_LINE_BUFFERED | ECORE_EXE_PIPE_ERROR, NULL); }