forked from enlightenment/edi
autosuggest: refactor to split clang suggest code from editor
Make room for other suggest providers too
This commit is contained in:
parent
9cef5db6c5
commit
49b55e838e
|
@ -23,6 +23,7 @@ AM_CPPFLAGS = \
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
edi_config.h \
|
edi_config.h \
|
||||||
editor/edi_editor.h \
|
editor/edi_editor.h \
|
||||||
|
editor/edi_editor_suggest_provider.h \
|
||||||
edi_content_provider.h \
|
edi_content_provider.h \
|
||||||
screens/edi_screens.h \
|
screens/edi_screens.h \
|
||||||
edi_filepanel.h \
|
edi_filepanel.h \
|
||||||
|
@ -34,6 +35,7 @@ mainview/edi_mainview.h
|
||||||
edi_SOURCES = \
|
edi_SOURCES = \
|
||||||
edi_config.c \
|
edi_config.c \
|
||||||
editor/edi_editor_search.c \
|
editor/edi_editor_search.c \
|
||||||
|
editor/edi_editor_suggest_provider.c \
|
||||||
editor/edi_editor.c \
|
editor/edi_editor.c \
|
||||||
edi_content_provider.c \
|
edi_content_provider.c \
|
||||||
screens/edi_welcome.c \
|
screens/edi_welcome.c \
|
||||||
|
|
|
@ -12,8 +12,12 @@
|
||||||
#include "mainview/edi_mainview.h"
|
#include "mainview/edi_mainview.h"
|
||||||
#include "edi_config.h"
|
#include "edi_config.h"
|
||||||
|
|
||||||
|
#include "editor/edi_editor_suggest_provider.h"
|
||||||
|
|
||||||
#include "edi_private.h"
|
#include "edi_private.h"
|
||||||
|
|
||||||
|
static void _suggest_popup_show(Edi_Editor *editor);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned int line;
|
unsigned int line;
|
||||||
|
@ -26,19 +30,6 @@ typedef struct
|
||||||
Edi_Location end;
|
Edi_Location end;
|
||||||
} Edi_Range;
|
} 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
|
void
|
||||||
edi_editor_save(Edi_Editor *editor)
|
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);
|
editor->save_timer = ecore_timer_add(EDI_CONTENT_SAVE_TIMEOUT, _edi_editor_autosave_cb, editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_LIBCLANG
|
|
||||||
static char *
|
static char *
|
||||||
_edi_editor_current_word_get(Edi_Editor *editor, unsigned int row, unsigned int col)
|
_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;
|
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 *
|
static Evas_Object *
|
||||||
_suggest_list_content_get(void *data, Evas_Object *obj, const char *part)
|
_suggest_list_content_get(void *data, Evas_Object *obj, const char *part)
|
||||||
{
|
{
|
||||||
Edi_Editor *editor;
|
Edi_Editor *editor;
|
||||||
Edi_Mainview_Item *item;
|
Edi_Mainview_Item *item;
|
||||||
Suggest_Item *suggest_it = data;
|
Edi_Editor_Suggest_Item *suggest_it = data;
|
||||||
char *format, *display;
|
char *format, *display;
|
||||||
const char *font;
|
const char *font, *summary;
|
||||||
int font_size, displen;
|
int font_size, displen;
|
||||||
|
|
||||||
if (strcmp(part, "elm.swallow.content"))
|
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");
|
editor = (Edi_Editor *)evas_object_data_get(item->view, "editor");
|
||||||
elm_code_widget_font_get(editor->entry, &font, &font_size);
|
elm_code_widget_font_get(editor->entry, &font, &font_size);
|
||||||
|
|
||||||
|
summary = edi_editor_suggest_provider_get(editor)->summary_get(editor, suggest_it);
|
||||||
format = "<align=left><font=\"%s\"><font_size=%d> %s</font_size></font></align>";
|
format = "<align=left><font=\"%s\"><font_size=%d> %s</font_size></font></align>";
|
||||||
displen = strlen(suggest_it->name) + strlen(format) + strlen(font);
|
displen = strlen(summary) + strlen(format) + strlen(font);
|
||||||
display = malloc(sizeof(char) * displen);
|
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);
|
Evas_Object *label = elm_label_add(obj);
|
||||||
elm_label_ellipsis_set(label, EINA_TRUE);
|
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_Editor *editor;
|
||||||
Edi_Mainview_Item *item;
|
Edi_Mainview_Item *item;
|
||||||
Suggest_Item *suggest_it;
|
Edi_Editor_Suggest_Item *suggest_it;
|
||||||
Evas_Object *label = data;
|
Evas_Object *label = data;
|
||||||
char *format, *display;
|
char *display;
|
||||||
const char *font, *ret_str, *param_str;
|
|
||||||
int font_size, displen;
|
|
||||||
|
|
||||||
suggest_it = elm_object_item_data_get(event_info);
|
suggest_it = elm_object_item_data_get(event_info);
|
||||||
|
|
||||||
item = edi_mainview_item_current_get();
|
item = edi_mainview_item_current_get();
|
||||||
|
|
||||||
if (!item)
|
if (!item)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
editor = (Edi_Editor *)evas_object_data_get(item->view, "editor");
|
editor = (Edi_Editor *)evas_object_data_get(item->view, "editor");
|
||||||
elm_code_widget_font_get(editor->entry, &font, &font_size);
|
display = edi_editor_suggest_provider_get(editor)->detail_get(editor, suggest_it);
|
||||||
|
|
||||||
ret_str = _suggest_item_return_get(suggest_it);
|
|
||||||
param_str = _suggest_item_parameter_get(suggest_it);
|
|
||||||
|
|
||||||
format = "<align=left><font=\"%s\"><font_size=%d>%s<br><b>%s</b><br> %s</font_size></font></align>";
|
|
||||||
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);
|
|
||||||
|
|
||||||
elm_object_text_set(label, display);
|
elm_object_text_set(label, display);
|
||||||
free(display);
|
free(display);
|
||||||
|
@ -211,7 +162,7 @@ _suggest_list_cb_selected(void *data, Evas_Object *obj EINA_UNUSED, void *event_
|
||||||
static void
|
static void
|
||||||
_suggest_list_update(Edi_Editor *editor, char *word)
|
_suggest_list_update(Edi_Editor *editor, char *word)
|
||||||
{
|
{
|
||||||
Suggest_Item *suggest_it;
|
Edi_Editor_Suggest_Item *suggest_it;
|
||||||
Eina_List *list, *l;
|
Eina_List *list, *l;
|
||||||
Elm_Genlist_Item_Class *ic;
|
Elm_Genlist_Item_Class *ic;
|
||||||
Elm_Object_Item *item;
|
Elm_Object_Item *item;
|
||||||
|
@ -226,7 +177,10 @@ _suggest_list_update(Edi_Editor *editor, char *word)
|
||||||
|
|
||||||
EINA_LIST_FOREACH(list, l, suggest_it)
|
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,
|
elm_genlist_item_append(editor->suggest_genlist,
|
||||||
ic,
|
ic,
|
||||||
|
@ -253,25 +207,20 @@ _suggest_list_update(Edi_Editor *editor, char *word)
|
||||||
static void
|
static void
|
||||||
_suggest_list_set(Edi_Editor *editor)
|
_suggest_list_set(Edi_Editor *editor)
|
||||||
{
|
{
|
||||||
Elm_Code *code;
|
|
||||||
CXCodeCompleteResults *res;
|
|
||||||
struct CXUnsavedFile unsaved_file;
|
|
||||||
char *curword;
|
char *curword;
|
||||||
const char *path;
|
|
||||||
unsigned int row, col;
|
unsigned int row, col;
|
||||||
|
Edi_Editor_Suggest_Provider *provider;
|
||||||
Eina_List *list = NULL;
|
Eina_List *list = NULL;
|
||||||
|
|
||||||
if (!editor->as_unit)
|
provider = edi_editor_suggest_provider_get(editor);
|
||||||
return;
|
|
||||||
|
|
||||||
list = (Eina_List *)evas_object_data_get(editor->suggest_genlist,
|
list = (Eina_List *)evas_object_data_get(editor->suggest_genlist,
|
||||||
"suggest_list");
|
"suggest_list");
|
||||||
if (list)
|
if (list)
|
||||||
{
|
{
|
||||||
Suggest_Item *suggest_it;
|
Edi_Editor_Suggest_Item *suggest_it;
|
||||||
|
|
||||||
EINA_LIST_FREE(list, suggest_it)
|
EINA_LIST_FREE(list, suggest_it)
|
||||||
_suggest_item_free(suggest_it);
|
provider->item_free(suggest_it);
|
||||||
|
|
||||||
list = NULL;
|
list = NULL;
|
||||||
evas_object_data_del(editor->suggest_genlist, "suggest_list");
|
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);
|
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);
|
curword = _edi_editor_current_word_get(editor, row, col);
|
||||||
|
list = edi_editor_suggest_provider_get(editor)->lookup(editor, curword);
|
||||||
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);
|
|
||||||
|
|
||||||
evas_object_data_set(editor->suggest_genlist, "suggest_list", list);
|
evas_object_data_set(editor->suggest_genlist, "suggest_list", list);
|
||||||
_suggest_list_update(editor, curword);
|
_suggest_list_update(editor, curword);
|
||||||
|
@ -380,16 +265,18 @@ _suggest_bg_cb_hide(void *data, Evas *e EINA_UNUSED,
|
||||||
{
|
{
|
||||||
Eina_List *list = NULL;
|
Eina_List *list = NULL;
|
||||||
Edi_Editor *editor;
|
Edi_Editor *editor;
|
||||||
|
Edi_Editor_Suggest_Provider *provider;
|
||||||
|
|
||||||
editor = (Edi_Editor *)data;
|
editor = (Edi_Editor *)data;
|
||||||
|
provider = edi_editor_suggest_provider_get(editor);
|
||||||
list = (Eina_List *)evas_object_data_get(editor->suggest_genlist,
|
list = (Eina_List *)evas_object_data_get(editor->suggest_genlist,
|
||||||
"suggest_list");
|
"suggest_list");
|
||||||
if (list)
|
if (list)
|
||||||
{
|
{
|
||||||
Suggest_Item *suggest_it;
|
Edi_Editor_Suggest_Item *suggest_it;
|
||||||
|
|
||||||
EINA_LIST_FREE(list, suggest_it)
|
EINA_LIST_FREE(list, suggest_it)
|
||||||
_suggest_item_free(suggest_it);
|
provider->item_free(suggest_it);
|
||||||
|
|
||||||
list = NULL;
|
list = NULL;
|
||||||
evas_object_data_del(editor->suggest_genlist, "suggest_list");
|
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)
|
void *event_info)
|
||||||
{
|
{
|
||||||
Edi_Editor *editor = (Edi_Editor *)data;
|
Edi_Editor *editor = (Edi_Editor *)data;
|
||||||
Suggest_Item *suggest_it;
|
Edi_Editor_Suggest_Item *suggest_it;
|
||||||
Elm_Object_Item *it;
|
Elm_Object_Item *it;
|
||||||
Evas_Object *genlist = obj;
|
Evas_Object *genlist = obj;
|
||||||
Evas_Event_Key_Down *ev = event_info;
|
Evas_Event_Key_Down *ev = event_info;
|
||||||
|
|
||||||
if (!strcmp(ev->key, "Return"))
|
if (!strcmp(ev->key, "Return"))
|
||||||
{
|
{
|
||||||
|
const char *term;
|
||||||
|
|
||||||
it = elm_genlist_selected_item_get(genlist);
|
it = elm_genlist_selected_item_get(genlist);
|
||||||
suggest_it = elm_object_item_data_get(it);
|
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);
|
evas_object_hide(editor->suggest_bg);
|
||||||
}
|
}
|
||||||
else if (!strcmp(ev->key, "Up"))
|
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)
|
void *event_info)
|
||||||
{
|
{
|
||||||
Elm_Object_Item *it = event_info;
|
Elm_Object_Item *it = event_info;
|
||||||
Suggest_Item *suggest_it;
|
Edi_Editor_Suggest_Item *suggest_it;
|
||||||
Edi_Editor *editor = (Edi_Editor *)data;
|
Edi_Editor *editor = (Edi_Editor *)data;
|
||||||
|
|
||||||
suggest_it = elm_object_item_data_get(it);
|
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);
|
evas_object_hide(editor->suggest_bg);
|
||||||
}
|
}
|
||||||
|
@ -597,40 +488,6 @@ _suggest_popup_setup(Edi_Editor *editor)
|
||||||
_suggest_list_cb_selected, label);
|
_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
|
static void
|
||||||
_smart_cb_key_down(void *data EINA_UNUSED, Evas *e EINA_UNUSED,
|
_smart_cb_key_down(void *data EINA_UNUSED, Evas *e EINA_UNUSED,
|
||||||
Evas_Object *obj EINA_UNUSED, void *event)
|
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();
|
edi_mainview_goto_popup_show();
|
||||||
}
|
}
|
||||||
#if HAVE_LIBCLANG
|
else if (edi_editor_suggest_provider_has(editor) && !strcmp(ev->key, "space"))
|
||||||
else if (!strcmp(ev->key, "space"))
|
|
||||||
{
|
{
|
||||||
_suggest_list_set(editor);
|
_suggest_list_set(editor);
|
||||||
_suggest_popup_show(editor);
|
_suggest_popup_show(editor);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#if HAVE_LIBCLANG
|
|
||||||
if ((!alt) && (!ctrl))
|
if (edi_editor_suggest_provider_has(editor))
|
||||||
_suggest_popup_key_down_cb(editor, ev->key, ev->string);
|
{
|
||||||
#endif
|
if ((!alt) && (!ctrl))
|
||||||
|
_suggest_popup_key_down_cb(editor, ev->key, ev->string);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1046,10 +903,8 @@ _unfocused_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UN
|
||||||
if (_edi_config->autosave)
|
if (_edi_config->autosave)
|
||||||
edi_editor_save(editor);
|
edi_editor_save(editor);
|
||||||
|
|
||||||
#if HAVE_LIBCLANG
|
|
||||||
if (editor->suggest_bg)
|
if (editor->suggest_bg)
|
||||||
evas_object_hide(editor->suggest_bg);
|
evas_object_hide(editor->suggest_bg);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1067,10 +922,8 @@ _mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED,
|
||||||
editor = (Edi_Editor *)data;
|
editor = (Edi_Editor *)data;
|
||||||
event = (Evas_Event_Mouse_Up *)event_info;
|
event = (Evas_Event_Mouse_Up *)event_info;
|
||||||
|
|
||||||
#if HAVE_LIBCLANG
|
|
||||||
if (editor->suggest_bg)
|
if (editor->suggest_bg)
|
||||||
evas_object_hide(editor->suggest_bg);
|
evas_object_hide(editor->suggest_bg);
|
||||||
#endif
|
|
||||||
|
|
||||||
ctrl = evas_key_modifier_is_set(event->modifiers, "Control");
|
ctrl = evas_key_modifier_is_set(event->modifiers, "Control");
|
||||||
if (event->button != 3 || !ctrl)
|
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
|
static void
|
||||||
_editor_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *o, void *event_info EINA_UNUSED)
|
_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 *ev_handler = data;
|
||||||
|
|
||||||
ecore_event_handler_del(ev_handler);
|
ecore_event_handler_del(ev_handler);
|
||||||
#if HAVE_LIBCLANG
|
|
||||||
Evas_Object *view = o;
|
if (edi_editor_suggest_provider_has(editor))
|
||||||
Edi_Editor *editor = (Edi_Editor *)evas_object_data_get(view, "editor");
|
edi_editor_suggest_provider_get(editor)->del(editor);
|
||||||
_clang_autosuggest_dispose(editor);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Evas_Object *
|
Evas_Object *
|
||||||
|
@ -1195,8 +1047,8 @@ edi_editor_add(Evas_Object *parent, Edi_Mainview_Item *item)
|
||||||
|
|
||||||
editor = calloc(1, sizeof(*editor));
|
editor = calloc(1, sizeof(*editor));
|
||||||
editor->entry = widget;
|
editor->entry = widget;
|
||||||
|
editor->mimetype = item->mimetype;
|
||||||
editor->show_highlight = !strcmp(item->editortype, "code");
|
editor->show_highlight = !strcmp(item->editortype, "code");
|
||||||
editor->show_suggest = !strcmp(item->editortype, "code");
|
|
||||||
evas_object_event_callback_add(widget, EVAS_CALLBACK_KEY_DOWN,
|
evas_object_event_callback_add(widget, EVAS_CALLBACK_KEY_DOWN,
|
||||||
_smart_cb_key_down, editor);
|
_smart_cb_key_down, editor);
|
||||||
evas_object_smart_callback_add(widget, "changed,user", _changed_cb, 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);
|
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);
|
evas_object_event_callback_add(vbox, EVAS_CALLBACK_DEL, _editor_del_cb, ev_handler);
|
||||||
|
|
||||||
#if HAVE_LIBCLANG
|
if (edi_editor_suggest_provider_has(editor))
|
||||||
if (editor->show_suggest)
|
{
|
||||||
_clang_autosuggest_setup(editor);
|
edi_editor_suggest_provider_get(editor)->add(editor);
|
||||||
#endif
|
_suggest_popup_setup(editor);
|
||||||
|
}
|
||||||
|
|
||||||
return vbox;
|
return vbox;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,8 @@ struct _Edi_Editor
|
||||||
Eina_Bool highlight_cancel;
|
Eina_Bool highlight_cancel;
|
||||||
time_t save_time;
|
time_t save_time;
|
||||||
|
|
||||||
Eina_Bool show_suggest;
|
const char *mimetype;
|
||||||
|
|
||||||
/* Add new members here. */
|
/* Add new members here. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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_ */
|
|
@ -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 = "<align=left><font=\"%s\"><font_size=%d>%s<br><b>%s</b><br> %s</font_size></font></align>";
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue