From 49b55e838e3589e6b4cf2a8b115d8d2f3918460c Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sat, 24 Dec 2016 23:31:29 +0000 Subject: [PATCH] autosuggest: refactor to split clang suggest code from editor Make room for other suggest providers too --- src/bin/Makefile.am | 2 + src/bin/editor/edi_editor.c | 250 ++++-------------- src/bin/editor/edi_editor.h | 3 +- src/bin/editor/edi_editor_suggest_provider.c | 57 ++++ src/bin/editor/edi_editor_suggest_provider.h | 75 ++++++ .../editor/edi_editor_suggest_provider_c.c | 219 +++++++++++++++ 6 files changed, 407 insertions(+), 199 deletions(-) create mode 100644 src/bin/editor/edi_editor_suggest_provider.c create mode 100644 src/bin/editor/edi_editor_suggest_provider.h create mode 100644 src/bin/editor/edi_editor_suggest_provider_c.c diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 3785b61..2e74628 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -23,6 +23,7 @@ AM_CPPFLAGS = \ noinst_HEADERS = \ edi_config.h \ editor/edi_editor.h \ +editor/edi_editor_suggest_provider.h \ edi_content_provider.h \ screens/edi_screens.h \ edi_filepanel.h \ @@ -34,6 +35,7 @@ mainview/edi_mainview.h edi_SOURCES = \ edi_config.c \ editor/edi_editor_search.c \ +editor/edi_editor_suggest_provider.c \ editor/edi_editor.c \ edi_content_provider.c \ screens/edi_welcome.c \ diff --git a/src/bin/editor/edi_editor.c b/src/bin/editor/edi_editor.c index d52d84f..ee64aba 100644 --- a/src/bin/editor/edi_editor.c +++ b/src/bin/editor/edi_editor.c @@ -12,8 +12,12 @@ #include "mainview/edi_mainview.h" #include "edi_config.h" +#include "editor/edi_editor_suggest_provider.h" + #include "edi_private.h" +static void _suggest_popup_show(Edi_Editor *editor); + typedef struct { unsigned int line; @@ -26,19 +30,6 @@ typedef struct Edi_Location end; } Edi_Range; -#if HAVE_LIBCLANG -typedef struct -{ - enum CXCursorKind kind; - char *ret; - char *name; - char *param; - Eina_Bool is_param_cand; -} Suggest_Item; - -static void _suggest_popup_show(Edi_Editor *editor); -#endif - void edi_editor_save(Edi_Editor *editor) { @@ -77,7 +68,6 @@ _changed_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUS editor->save_timer = ecore_timer_add(EDI_CONTENT_SAVE_TIMEOUT, _edi_editor_autosave_cb, editor); } -#if HAVE_LIBCLANG static char * _edi_editor_current_word_get(Edi_Editor *editor, unsigned int row, unsigned int col) { @@ -110,41 +100,14 @@ _edi_editor_current_word_get(Edi_Editor *editor, unsigned int row, unsigned int return curword; } -static const char * -_suggest_item_return_get(Suggest_Item *item) -{ - if (!item->ret) - return ""; - - return item->ret; -} - -static const char * -_suggest_item_parameter_get(Suggest_Item *item) -{ - if (!item->param) - return ""; - - return item->param; -} - -static void -_suggest_item_free(Suggest_Item *item) -{ - if (item->ret) free(item->ret); - if (item->name) free(item->name); - if (item->param) free(item->param); - free(item); -} - static Evas_Object * _suggest_list_content_get(void *data, Evas_Object *obj, const char *part) { Edi_Editor *editor; Edi_Mainview_Item *item; - Suggest_Item *suggest_it = data; + Edi_Editor_Suggest_Item *suggest_it = data; char *format, *display; - const char *font; + const char *font, *summary; int font_size, displen; if (strcmp(part, "elm.swallow.content")) @@ -158,10 +121,11 @@ _suggest_list_content_get(void *data, Evas_Object *obj, const char *part) editor = (Edi_Editor *)evas_object_data_get(item->view, "editor"); elm_code_widget_font_get(editor->entry, &font, &font_size); + summary = edi_editor_suggest_provider_get(editor)->summary_get(editor, suggest_it); format = " %s"; - displen = strlen(suggest_it->name) + strlen(format) + strlen(font); + displen = strlen(summary) + strlen(format) + strlen(font); display = malloc(sizeof(char) * displen); - snprintf(display, displen, format, font, font_size, suggest_it->name); + snprintf(display, displen, format, font, font_size, summary); Evas_Object *label = elm_label_add(obj); elm_label_ellipsis_set(label, EINA_TRUE); @@ -178,31 +142,18 @@ _suggest_list_cb_selected(void *data, Evas_Object *obj EINA_UNUSED, void *event_ { Edi_Editor *editor; Edi_Mainview_Item *item; - Suggest_Item *suggest_it; + Edi_Editor_Suggest_Item *suggest_it; Evas_Object *label = data; - char *format, *display; - const char *font, *ret_str, *param_str; - int font_size, displen; + char *display; suggest_it = elm_object_item_data_get(event_info); - item = edi_mainview_item_current_get(); if (!item) return; editor = (Edi_Editor *)evas_object_data_get(item->view, "editor"); - elm_code_widget_font_get(editor->entry, &font, &font_size); - - ret_str = _suggest_item_return_get(suggest_it); - param_str = _suggest_item_parameter_get(suggest_it); - - format = "%s
%s
%s"; - displen = strlen(ret_str) + strlen(param_str) + strlen(suggest_it->name) - + strlen(format) + strlen(font); - display = malloc(sizeof(char) * displen); - snprintf(display, displen, format, font, font_size, ret_str, suggest_it->name, - param_str); + display = edi_editor_suggest_provider_get(editor)->detail_get(editor, suggest_it); elm_object_text_set(label, display); free(display); @@ -211,7 +162,7 @@ _suggest_list_cb_selected(void *data, Evas_Object *obj EINA_UNUSED, void *event_ static void _suggest_list_update(Edi_Editor *editor, char *word) { - Suggest_Item *suggest_it; + Edi_Editor_Suggest_Item *suggest_it; Eina_List *list, *l; Elm_Genlist_Item_Class *ic; Elm_Object_Item *item; @@ -226,7 +177,10 @@ _suggest_list_update(Edi_Editor *editor, char *word) EINA_LIST_FOREACH(list, l, suggest_it) { - if (eina_str_has_prefix(suggest_it->name, word)) + const char *term; + term = edi_editor_suggest_provider_get(editor)->summary_get(editor, suggest_it); + + if (eina_str_has_prefix(term, word)) { elm_genlist_item_append(editor->suggest_genlist, ic, @@ -253,25 +207,20 @@ _suggest_list_update(Edi_Editor *editor, char *word) static void _suggest_list_set(Edi_Editor *editor) { - Elm_Code *code; - CXCodeCompleteResults *res; - struct CXUnsavedFile unsaved_file; char *curword; - const char *path; unsigned int row, col; + Edi_Editor_Suggest_Provider *provider; Eina_List *list = NULL; - if (!editor->as_unit) - return; - + provider = edi_editor_suggest_provider_get(editor); list = (Eina_List *)evas_object_data_get(editor->suggest_genlist, "suggest_list"); if (list) { - Suggest_Item *suggest_it; + Edi_Editor_Suggest_Item *suggest_it; EINA_LIST_FREE(list, suggest_it) - _suggest_item_free(suggest_it); + provider->item_free(suggest_it); list = NULL; evas_object_data_del(editor->suggest_genlist, "suggest_list"); @@ -279,72 +228,8 @@ _suggest_list_set(Edi_Editor *editor) elm_code_widget_cursor_position_get(editor->entry, &row, &col); - code = elm_code_widget_code_get(editor->entry); - path = elm_code_file_path_get(code->file); - curword = _edi_editor_current_word_get(editor, row, col); - - unsaved_file.Filename = path; - unsaved_file.Contents = elm_code_widget_text_between_positions_get( - editor->entry, 1, 1, col, row); - unsaved_file.Length = strlen(unsaved_file.Contents); - - res = clang_codeCompleteAt(editor->as_unit, path, row, col - strlen(curword), - &unsaved_file, 1, - CXCodeComplete_IncludeMacros | - CXCodeComplete_IncludeCodePatterns); - - clang_sortCodeCompletionResults(res->Results, res->NumResults); - - for (unsigned int i = 0; i < res->NumResults; i++) - { - const CXCompletionString str = res->Results[i].CompletionString; - Suggest_Item *suggest_it; - Eina_Strbuf *buf = NULL; - - suggest_it = calloc(1, sizeof(Suggest_Item)); - suggest_it->kind = res->Results[i].CursorKind; - if (suggest_it->kind == CXCursor_OverloadCandidate) - suggest_it->is_param_cand = EINA_TRUE; - - for (unsigned int j = 0; j < clang_getNumCompletionChunks(str); j++) - { - enum CXCompletionChunkKind ch_kind; - const CXString str_out = clang_getCompletionChunkText(str, j); - - ch_kind = clang_getCompletionChunkKind(str, j); - - switch (ch_kind) - { - case CXCompletionChunk_ResultType: - suggest_it->ret = strdup(clang_getCString(str_out)); - break; - case CXCompletionChunk_TypedText: - case CXCompletionChunk_Text: - suggest_it->name = strdup(clang_getCString(str_out)); - break; - case CXCompletionChunk_LeftParen: - case CXCompletionChunk_Placeholder: - case CXCompletionChunk_Comma: - case CXCompletionChunk_CurrentParameter: - if (!buf) - buf = eina_strbuf_new(); - eina_strbuf_append(buf, clang_getCString(str_out)); - break; - case CXCompletionChunk_RightParen: - eina_strbuf_append(buf, clang_getCString(str_out)); - suggest_it->param = eina_strbuf_string_steal(buf); - eina_strbuf_free(buf); - buf = NULL; - break; - default: - break; - } - } - list = eina_list_append(list, suggest_it); - } - - clang_disposeCodeCompleteResults(res); + list = edi_editor_suggest_provider_get(editor)->lookup(editor, curword); evas_object_data_set(editor->suggest_genlist, "suggest_list", list); _suggest_list_update(editor, curword); @@ -380,16 +265,18 @@ _suggest_bg_cb_hide(void *data, Evas *e EINA_UNUSED, { Eina_List *list = NULL; Edi_Editor *editor; + Edi_Editor_Suggest_Provider *provider; editor = (Edi_Editor *)data; + provider = edi_editor_suggest_provider_get(editor); list = (Eina_List *)evas_object_data_get(editor->suggest_genlist, "suggest_list"); if (list) { - Suggest_Item *suggest_it; + Edi_Editor_Suggest_Item *suggest_it; EINA_LIST_FREE(list, suggest_it) - _suggest_item_free(suggest_it); + provider->item_free(suggest_it); list = NULL; evas_object_data_del(editor->suggest_genlist, "suggest_list"); @@ -404,17 +291,20 @@ _suggest_list_cb_key_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { Edi_Editor *editor = (Edi_Editor *)data; - Suggest_Item *suggest_it; + Edi_Editor_Suggest_Item *suggest_it; Elm_Object_Item *it; Evas_Object *genlist = obj; Evas_Event_Key_Down *ev = event_info; if (!strcmp(ev->key, "Return")) { + const char *term; + it = elm_genlist_selected_item_get(genlist); suggest_it = elm_object_item_data_get(it); - _suggest_list_selection_insert(editor, suggest_it->name); + term = edi_editor_suggest_provider_get(editor)->summary_get(editor, suggest_it); + _suggest_list_selection_insert(editor, term); evas_object_hide(editor->suggest_bg); } else if (!strcmp(ev->key, "Up")) @@ -440,11 +330,12 @@ _suggest_list_cb_clicked_double(void *data, Evas_Object *obj EINA_UNUSED, void *event_info) { Elm_Object_Item *it = event_info; - Suggest_Item *suggest_it; + Edi_Editor_Suggest_Item *suggest_it; Edi_Editor *editor = (Edi_Editor *)data; suggest_it = elm_object_item_data_get(it); - _suggest_list_selection_insert(editor, suggest_it->name); + _suggest_list_selection_insert(editor, + edi_editor_suggest_provider_get(editor)->summary_get(editor, suggest_it)); evas_object_hide(editor->suggest_bg); } @@ -597,40 +488,6 @@ _suggest_popup_setup(Edi_Editor *editor) _suggest_list_cb_selected, label); } -static void -_clang_autosuggest_setup(Edi_Editor *editor) -{ - Elm_Code *code; - const char *path; - char **clang_argv; - const char *args; - unsigned int clang_argc; - - code = elm_code_widget_code_get(editor->entry); - path = elm_code_file_path_get(code->file); - - //Initialize Clang - args = "-I/usr/inclue/ " EFL_CFLAGS " " CLANG_INCLUDES " -Wall -Wextra"; - clang_argv = eina_str_split_full(args, " ", 0, &clang_argc); - - editor->as_idx = clang_createIndex(0, 0); - - editor->as_unit = clang_parseTranslationUnit(editor->as_idx, path, - (const char *const *)clang_argv, - (int)clang_argc, NULL, 0, - clang_defaultEditingTranslationUnitOptions()); - - _suggest_popup_setup(editor); -} - -static void -_clang_autosuggest_dispose(Edi_Editor *editor) -{ - clang_disposeTranslationUnit(editor->as_unit); - clang_disposeIndex(editor->as_idx); -} -#endif - static void _smart_cb_key_down(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event) @@ -673,18 +530,18 @@ _smart_cb_key_down(void *data EINA_UNUSED, Evas *e EINA_UNUSED, { edi_mainview_goto_popup_show(); } -#if HAVE_LIBCLANG - else if (!strcmp(ev->key, "space")) + else if (edi_editor_suggest_provider_has(editor) && !strcmp(ev->key, "space")) { _suggest_list_set(editor); _suggest_popup_show(editor); } -#endif } -#if HAVE_LIBCLANG - if ((!alt) && (!ctrl)) - _suggest_popup_key_down_cb(editor, ev->key, ev->string); -#endif + + if (edi_editor_suggest_provider_has(editor)) + { + if ((!alt) && (!ctrl)) + _suggest_popup_key_down_cb(editor, ev->key, ev->string); + } } static void @@ -1046,10 +903,8 @@ _unfocused_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UN if (_edi_config->autosave) edi_editor_save(editor); -#if HAVE_LIBCLANG if (editor->suggest_bg) evas_object_hide(editor->suggest_bg); -#endif } static void @@ -1067,10 +922,8 @@ _mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, editor = (Edi_Editor *)data; event = (Evas_Event_Mouse_Up *)event_info; -#if HAVE_LIBCLANG if (editor->suggest_bg) evas_object_hide(editor->suggest_bg); -#endif ctrl = evas_key_modifier_is_set(event->modifiers, "Control"); if (event->button != 3 || !ctrl) @@ -1142,14 +995,13 @@ _edi_editor_config_changed(void *data, int type EINA_UNUSED, void *event EINA_UN static void _editor_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *o, void *event_info EINA_UNUSED) { + Edi_Editor *editor = (Edi_Editor *)evas_object_data_get(o, "editor"); Ecore_Event_Handler *ev_handler = data; ecore_event_handler_del(ev_handler); -#if HAVE_LIBCLANG - Evas_Object *view = o; - Edi_Editor *editor = (Edi_Editor *)evas_object_data_get(view, "editor"); - _clang_autosuggest_dispose(editor); -#endif + + if (edi_editor_suggest_provider_has(editor)) + edi_editor_suggest_provider_get(editor)->del(editor); } Evas_Object * @@ -1195,8 +1047,8 @@ edi_editor_add(Evas_Object *parent, Edi_Mainview_Item *item) editor = calloc(1, sizeof(*editor)); editor->entry = widget; + editor->mimetype = item->mimetype; editor->show_highlight = !strcmp(item->editortype, "code"); - editor->show_suggest = !strcmp(item->editortype, "code"); evas_object_event_callback_add(widget, EVAS_CALLBACK_KEY_DOWN, _smart_cb_key_down, editor); evas_object_smart_callback_add(widget, "changed,user", _changed_cb, editor); @@ -1233,9 +1085,11 @@ edi_editor_add(Evas_Object *parent, Edi_Mainview_Item *item) ev_handler = ecore_event_handler_add(EDI_EVENT_CONFIG_CHANGED, _edi_editor_config_changed, widget); evas_object_event_callback_add(vbox, EVAS_CALLBACK_DEL, _editor_del_cb, ev_handler); -#if HAVE_LIBCLANG - if (editor->show_suggest) - _clang_autosuggest_setup(editor); -#endif + if (edi_editor_suggest_provider_has(editor)) + { + edi_editor_suggest_provider_get(editor)->add(editor); + _suggest_popup_setup(editor); + } + return vbox; } diff --git a/src/bin/editor/edi_editor.h b/src/bin/editor/edi_editor.h index 9a135f8..4b74930 100644 --- a/src/bin/editor/edi_editor.h +++ b/src/bin/editor/edi_editor.h @@ -64,7 +64,8 @@ struct _Edi_Editor Eina_Bool highlight_cancel; time_t save_time; - Eina_Bool show_suggest; + const char *mimetype; + /* Add new members here. */ }; diff --git a/src/bin/editor/edi_editor_suggest_provider.c b/src/bin/editor/edi_editor_suggest_provider.c new file mode 100644 index 0000000..4eb6bbe --- /dev/null +++ b/src/bin/editor/edi_editor_suggest_provider.c @@ -0,0 +1,57 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "edi_editor_suggest_provider.h" + +#include "edi_config.h" + +#include "edi_private.h" + +#include "edi_editor_suggest_provider_c.c" + +static Edi_Editor_Suggest_Provider _edi_editor_suggest_provider_registry[] = +{ + { + "c", _edi_editor_sugggest_c_add, _edi_editor_sugget_c_del, + _edi_editor_suggest_c_lookup, _edi_editor_suggest_c_summary_get, + _edi_editor_suggest_c_detail_get, _edi_editor_suggest_c_item_free + }, + + {NULL, NULL, NULL, NULL, NULL, NULL, NULL} +}; + +Edi_Editor_Suggest_Provider *edi_editor_suggest_provider_get(Edi_Editor *editor) +{ + Edi_Editor_Suggest_Provider *provider; + const char *mime = editor->mimetype; + const char *id = NULL; + + if (!mime) + return NULL; + + if (!strcasecmp(mime, "text/x-chdr") || !strcasecmp(mime, "text/x-csrc") + || !strcasecmp(mime, "text/x-modelica")) + id = "c"; + + if (!id) + return NULL; + + provider = _edi_editor_suggest_provider_registry; + while (provider != NULL && provider->id != NULL) + { + if (!strncmp(id, provider->id, strlen(provider->id))) + return provider; + + provider++; + } + + return NULL; +} + +Eina_Bool +edi_editor_suggest_provider_has(Edi_Editor *editor) +{ + return !!edi_editor_suggest_provider_get(editor); +} + diff --git a/src/bin/editor/edi_editor_suggest_provider.h b/src/bin/editor/edi_editor_suggest_provider.h new file mode 100644 index 0000000..ecfd114 --- /dev/null +++ b/src/bin/editor/edi_editor_suggest_provider.h @@ -0,0 +1,75 @@ +#ifndef EDI_EDITOR_SUGGEST_PROVIDER_H_ +# define EDI_EDITOR_SUGGEST_PROVIDER_H_ + +#include "editor/edi_editor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file + * @brief These routines are used for managing content suggestion providers. + * i.e. like autosuggest in visual studio. + */ + +/** + * @typedef Edi_Editor_Suggest_Item + * A handle for passig a suggest item to the ui and back + */ +typedef void *Edi_Editor_Suggest_Item; + +/** + * @struct Edi_Editor_Suggest_Provider + * A description of the requirements for a suggestion provider. + * This handles the set up and teardown of a provider as well as the lookup and + * description lookup functions + */ +typedef struct _Edi_Editor_Suggest_Provider +{ + const char *id; + + void (*add)(Edi_Editor *editor); + void (*del)(Edi_Editor *editor); + Eina_List *(*lookup)(Edi_Editor *editor, const char *word); + const char *(*summary_get)(Edi_Editor *editor, Edi_Editor_Suggest_Item *item); + char *(*detail_get)(Edi_Editor *editor, Edi_Editor_Suggest_Item *item); + void (*item_free)(Edi_Editor_Suggest_Item *item); +} Edi_Editor_Suggest_Provider; + +/** + * @brief Lookup information in suggest provider registry. + * @defgroup Lookup + * + * @{ + * + * Look up a suggest provider based on the provided editor. + * + * @param editor the editor session for a file you wish to get a suggestion provider for + * + * @return an Edi_Editor_Suggest_Provider if one is registered or NULL otherwise + * + * @ingroup Lookup + */ +Edi_Editor_Suggest_Provider *edi_editor_suggest_provider_get(Edi_Editor *editor); + +/** + * Query whether a suggest provider is available for the spcified editor session. + * + * @param editor the editor session for a file you wish to get a suggestion provider for + * + * @ingroup Lookup + */ +Eina_Bool edi_editor_suggest_provider_has(Edi_Editor *editor); + +/** + * @} + */ + + + +#ifdef __cplusplus +} +#endif + +#endif /* EDI_EDITOR_SUGGEST_PROVIDER_H_ */ diff --git a/src/bin/editor/edi_editor_suggest_provider_c.c b/src/bin/editor/edi_editor_suggest_provider_c.c new file mode 100644 index 0000000..6ddb68f --- /dev/null +++ b/src/bin/editor/edi_editor_suggest_provider_c.c @@ -0,0 +1,219 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "edi_editor_suggest_provider.h" + +#include "edi_config.h" + +#include "edi_private.h" + +#if HAVE_LIBCLANG +typedef struct +{ + enum CXCursorKind kind; + char *ret; + char *name; + char *param; + Eina_Bool is_param_cand; +} _Clang_Suggest_Item; + +static void +_clang_autosuggest_setup(Edi_Editor *editor) +{ + Elm_Code *code; + const char *path; + char **clang_argv; + const char *args; + unsigned int clang_argc; + + code = elm_code_widget_code_get(editor->entry); + path = elm_code_file_path_get(code->file); + + //Initialize Clang + args = "-I/usr/inclue/ " EFL_CFLAGS " " CLANG_INCLUDES " -Wall -Wextra"; + clang_argv = eina_str_split_full(args, " ", 0, &clang_argc); + + editor->as_idx = clang_createIndex(0, 0); + + editor->as_unit = clang_parseTranslationUnit(editor->as_idx, path, + (const char *const *)clang_argv, + (int)clang_argc, NULL, 0, + clang_defaultEditingTranslationUnitOptions()); +} + +static void +_clang_autosuggest_dispose(Edi_Editor *editor) +{ + clang_disposeTranslationUnit(editor->as_unit); + clang_disposeIndex(editor->as_idx); +} +#endif + +static const char * +_suggest_item_return_get(Edi_Editor_Suggest_Item *item) +{ +#if HAVE_LIBCLANG + if (((_Clang_Suggest_Item *)item)->ret) + return ((_Clang_Suggest_Item *)item)->ret; +#endif + + return ""; +} + +static const char * +_suggest_item_parameter_get(Edi_Editor_Suggest_Item *item) +{ +#if HAVE_LIBCLANG + if (((_Clang_Suggest_Item *)item)->param) + return ((_Clang_Suggest_Item *)item)->param; +#endif + + return ""; +} + +void +_edi_editor_sugggest_c_add(Edi_Editor *editor) +{ +#if HAVE_LIBCLANG + _clang_autosuggest_setup(editor); +#endif +} + +void +_edi_editor_sugget_c_del(Edi_Editor *editor) +{ +#if HAVE_LIBCLANG + _clang_autosuggest_dispose(editor); +#endif +} + +Eina_List * +_edi_editor_suggest_c_lookup(Edi_Editor *editor, const char *curword) +{ + Eina_List *list = NULL; + +#if HAVE_LIBCLANG + CXCodeCompleteResults *res; + struct CXUnsavedFile unsaved_file; + Elm_Code *code; + const char *path; + unsigned int col, row; + + if (!editor->as_unit) + return list; + + code = elm_code_widget_code_get(editor->entry); + path = elm_code_file_path_get(code->file); + elm_code_widget_cursor_position_get(editor->entry, &row, &col); + + unsaved_file.Filename = path; + unsaved_file.Contents = elm_code_widget_text_between_positions_get( + editor->entry, 1, 1, col, row); + unsaved_file.Length = strlen(unsaved_file.Contents); + + res = clang_codeCompleteAt(editor->as_unit, path, row, col - strlen(curword), + &unsaved_file, 1, + CXCodeComplete_IncludeMacros | + CXCodeComplete_IncludeCodePatterns); + + clang_sortCodeCompletionResults(res->Results, res->NumResults); + + for (unsigned int i = 0; i < res->NumResults; i++) + { + const CXCompletionString str = res->Results[i].CompletionString; + _Clang_Suggest_Item *suggest_it; + Eina_Strbuf *buf = NULL; + + suggest_it = calloc(1, sizeof(_Clang_Suggest_Item)); + suggest_it->kind = res->Results[i].CursorKind; + if (suggest_it->kind == CXCursor_OverloadCandidate) + suggest_it->is_param_cand = EINA_TRUE; + + for (unsigned int j = 0; j < clang_getNumCompletionChunks(str); j++) + { + enum CXCompletionChunkKind ch_kind; + const CXString str_out = clang_getCompletionChunkText(str, j); + + ch_kind = clang_getCompletionChunkKind(str, j); + + switch (ch_kind) + { + case CXCompletionChunk_ResultType: + suggest_it->ret = strdup(clang_getCString(str_out)); + break; + case CXCompletionChunk_TypedText: + case CXCompletionChunk_Text: + suggest_it->name = strdup(clang_getCString(str_out)); + break; + case CXCompletionChunk_LeftParen: + case CXCompletionChunk_Placeholder: + case CXCompletionChunk_Comma: + case CXCompletionChunk_CurrentParameter: + if (!buf) + buf = eina_strbuf_new(); + eina_strbuf_append(buf, clang_getCString(str_out)); + break; + case CXCompletionChunk_RightParen: + eina_strbuf_append(buf, clang_getCString(str_out)); + suggest_it->param = eina_strbuf_string_steal(buf); + eina_strbuf_free(buf); + buf = NULL; + break; + default: + break; + } + } + list = eina_list_append(list, suggest_it); + } + clang_disposeCodeCompleteResults(res); +#endif + + return list; +} + +const char * +_edi_editor_suggest_c_summary_get(Edi_Editor *editor EINA_UNUSED, Edi_Editor_Suggest_Item *item) +{ +#if HAVE_LIBCLANG + return ((_Clang_Suggest_Item *)item)->name; +#else + return ""; +#endif +} + +static void +_edi_editor_suggest_c_item_free(Edi_Editor_Suggest_Item *item) +{ +#if HAVE_LIBCLANG + _Clang_Suggest_Item *clang_item = (_Clang_Suggest_Item *)item; + + if (clang_item->ret) free(clang_item->ret); + if (clang_item->name) free(clang_item->name); + if (clang_item->param) free(clang_item->param); + free(clang_item); +#endif +} + +char * +_edi_editor_suggest_c_detail_get(Edi_Editor *editor, Edi_Editor_Suggest_Item *item) +{ + char *format, *display; + const char *font, *term_str, *ret_str, *param_str; + int font_size, displen; + + elm_code_widget_font_get(editor->entry, &font, &font_size); + + term_str = _edi_editor_suggest_c_summary_get(editor, item); + ret_str = _suggest_item_return_get(item); + param_str = _suggest_item_parameter_get(item); + + format = "%s
%s
%s"; + displen = strlen(ret_str) + strlen(param_str) + strlen(term_str) + + strlen(format) + strlen(font); + display = malloc(sizeof(char) * displen); + snprintf(display, displen, format, font, font_size, ret_str, term_str, param_str); + + return display; +} +