Add keybinding for construct completion, and set the default to tab.
Separate complete_constructs() code from sci_cb_auto_forif(). git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@1426 ea778897-0a13-0410-b9d1-a72fbfd435f5
This commit is contained in:
parent
62bcccd1ba
commit
a52574c582
@ -1,3 +1,11 @@
|
||||
2007-03-27 Nick Treleaven <nick.treleaven@btinternet.com>
|
||||
|
||||
* src/keybindings.c, src/keybindings.h, src/sci_cb.c, src/sci_cb.h,
|
||||
doc/geany.docbook:
|
||||
Add keybinding for construct completion, and set the default to tab.
|
||||
Separate complete_constructs() code from sci_cb_auto_forif().
|
||||
|
||||
|
||||
2007-03-26 Nick Treleaven <nick.treleaven@btinternet.com>
|
||||
|
||||
* src/keybindings.c, TODO:
|
||||
|
||||
@ -1504,9 +1504,22 @@
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Suppress auto completion</entry>
|
||||
<entry>If you type something like if or for and press this key, it
|
||||
will not be auto completed.
|
||||
<entry>Complete construct</entry>
|
||||
<entry>If you type a construct like <literal>if</literal> or
|
||||
<literal>for</literal> and press this key, it
|
||||
will be completed with a matching template.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Suppress construct completion</entry>
|
||||
<entry>If you type a construct like <literal>if</literal> or
|
||||
<literal>for</literal> and press this key, it
|
||||
will not be completed, and a space or tab will be inserted,
|
||||
depending on what the construct completion keybinding is set to.
|
||||
For example, if you have set the
|
||||
construct completion keybinding to <literal>space</literal>,
|
||||
then setting this to <literal>Shift+space</literal> will
|
||||
prevent construct completion and insert a space.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
|
||||
@ -254,8 +254,10 @@ void keybindings_init(void)
|
||||
GDK_space, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "edit_calltip", _("Show calltip"));
|
||||
keys[GEANY_KEYS_EDIT_MACROLIST] = fill(cb_func_edit,
|
||||
GDK_Return, GDK_CONTROL_MASK, "edit_macrolist", _("Show macro list"));
|
||||
keys[GEANY_KEYS_EDIT_COMPLETECONSTRUCT] = fill(NULL, // has special callback
|
||||
GDK_Tab, 0, "edit_completeconstruct", _("Complete construct"));
|
||||
keys[GEANY_KEYS_EDIT_SUPPRESSCOMPLETION] = fill(cb_func_edit,
|
||||
GDK_space, GDK_SHIFT_MASK, "edit_suppresscompletion", _("Suppress auto completion"));
|
||||
0, 0, "edit_suppresscompletion", _("Suppress construct completion"));
|
||||
|
||||
keys[GEANY_KEYS_EDIT_SELECTWORD] = fill(cb_func_edit,
|
||||
0, 0, "edit_selectword", _("Select current word"));
|
||||
@ -516,6 +518,29 @@ static gboolean check_fixed_kb(GdkEventKey *event)
|
||||
}
|
||||
|
||||
|
||||
/* We have a special case for GEANY_KEYS_EDIT_COMPLETECONSTRUCT, because we need to
|
||||
* return FALSE if no completion occurs, so the tab or space is handled normally. */
|
||||
static gboolean check_construct_completion(GdkEventKey *event)
|
||||
{
|
||||
const guint i = GEANY_KEYS_EDIT_COMPLETECONSTRUCT;
|
||||
|
||||
if (keys[i]->key == event->keyval && keys[i]->mods == event->state)
|
||||
{
|
||||
gint idx = document_get_cur_idx();
|
||||
|
||||
if (DOC_IDX_VALID(idx))
|
||||
{
|
||||
ScintillaObject *sci = doc_list[idx].sci;
|
||||
gint pos = sci_get_current_position(sci);
|
||||
|
||||
if (app->pref_editor_auto_complete_constructs)
|
||||
return sci_cb_auto_forif(idx, pos);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* central keypress event handler, almost all keypress events go to this function */
|
||||
gboolean keybindings_got_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
|
||||
{
|
||||
@ -526,7 +551,9 @@ gboolean keybindings_got_event(GtkWidget *widget, GdkEventKey *event, gpointer u
|
||||
// ignore numlock key, not necessary but nice
|
||||
if (event->state & GDK_MOD2_MASK) event->state -= GDK_MOD2_MASK;
|
||||
|
||||
// special cases
|
||||
if (check_fixed_kb(event)) return TRUE;
|
||||
if (check_construct_completion(event)) return TRUE;
|
||||
|
||||
for (i = 0; i < GEANY_MAX_KEYS; i++)
|
||||
{
|
||||
@ -542,8 +569,11 @@ gboolean keybindings_got_event(GtkWidget *widget, GdkEventKey *event, gpointer u
|
||||
|
||||
if (event->keyval == k && event->state == keys[i]->mods)
|
||||
{
|
||||
if (keys[i]->cb_func == NULL)
|
||||
return FALSE; // ignore the keybinding
|
||||
|
||||
// call the corresponding callback function for this shortcut
|
||||
if (keys[i]->cb_func != NULL) keys[i]->cb_func(i);
|
||||
keys[i]->cb_func(i);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@ -939,9 +969,21 @@ static void cb_func_edit(guint key_id)
|
||||
case GEANY_KEYS_EDIT_MACROLIST:
|
||||
sci_cb_show_macro_list(doc_list[idx].sci);
|
||||
break;
|
||||
|
||||
case GEANY_KEYS_EDIT_SUPPRESSCOMPLETION:
|
||||
sci_add_text(doc_list[idx].sci, " ");
|
||||
switch (keys[GEANY_KEYS_EDIT_COMPLETECONSTRUCT]->key)
|
||||
{
|
||||
case GDK_space:
|
||||
sci_add_text(doc_list[idx].sci, " ");
|
||||
break;
|
||||
case GDK_Tab:
|
||||
sci_add_text(doc_list[idx].sci, "\t");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GEANY_KEYS_EDIT_SELECTWORD:
|
||||
sci_cb_select_word(doc_list[idx].sci);
|
||||
break;
|
||||
|
||||
@ -111,6 +111,7 @@ enum
|
||||
GEANY_KEYS_EDIT_AUTOCOMPLETE,
|
||||
GEANY_KEYS_EDIT_CALLTIP,
|
||||
GEANY_KEYS_EDIT_MACROLIST,
|
||||
GEANY_KEYS_EDIT_COMPLETECONSTRUCT,
|
||||
GEANY_KEYS_EDIT_SUPPRESSCOMPLETION,
|
||||
GEANY_KEYS_EDIT_SELECTWORD,
|
||||
GEANY_KEYS_EDIT_INSERTALTWHITESPACE,
|
||||
|
||||
220
src/sci_cb.c
220
src/sci_cb.c
@ -215,12 +215,6 @@ static void on_char_added(gint idx, SCNotification *nt)
|
||||
calltip.set = FALSE;
|
||||
break;
|
||||
}
|
||||
case ' ':
|
||||
{ // if and for autocompletion
|
||||
if (app->pref_editor_auto_complete_constructs)
|
||||
sci_cb_auto_forif(idx, pos);
|
||||
break;
|
||||
}
|
||||
case '[':
|
||||
case '{':
|
||||
{ // Tex auto-closing
|
||||
@ -948,101 +942,36 @@ void sci_cb_auto_latex(gint idx, gint pos)
|
||||
}
|
||||
|
||||
|
||||
static gboolean at_eol(ScintillaObject *sci, gint pos)
|
||||
/* This should use a string with the current word instead of buf, but we will replace this
|
||||
* code with user-defined construct completion. */
|
||||
static gboolean complete_constructs(gint idx, gint pos, const gchar *buf, const gchar *space,
|
||||
const gchar *eol)
|
||||
{
|
||||
gint line = sci_get_line_from_position(sci, pos);
|
||||
gboolean result;
|
||||
gchar *construct = NULL;
|
||||
gint space_len = strlen(space);
|
||||
ScintillaObject *sci = doc_list[idx].sci;
|
||||
|
||||
return (pos == sci_get_line_end_position(sci, line));
|
||||
}
|
||||
|
||||
|
||||
void sci_cb_auto_forif(gint idx, gint pos)
|
||||
{
|
||||
static gchar buf[16];
|
||||
gchar *eol;
|
||||
gchar *space;
|
||||
gchar *construct;
|
||||
gint lexer, style;
|
||||
gint i;
|
||||
gint space_len;
|
||||
ScintillaObject *sci;
|
||||
|
||||
if (idx == -1 || ! doc_list[idx].is_valid || doc_list[idx].file_type == NULL) return;
|
||||
|
||||
// only for C, C++, D, Ferite, Java, JavaScript, Perl and PHP
|
||||
if (doc_list[idx].file_type->id != GEANY_FILETYPES_PHP &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_C &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_D &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_CPP &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_PERL &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_JAVA &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_JS &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_FERITE)
|
||||
return;
|
||||
|
||||
sci = doc_list[idx].sci;
|
||||
// return if we are editing an existing line (chars on right of cursor)
|
||||
if (! at_eol(sci, pos))
|
||||
return;
|
||||
|
||||
lexer = SSM(sci, SCI_GETLEXER, 0, 0);
|
||||
style = SSM(sci, SCI_GETSTYLEAT, pos - 2, 0);
|
||||
// return, if we are in a comment
|
||||
if (is_comment(lexer, style))
|
||||
return;
|
||||
// never auto complete in a PHP file outside of the <? ?> tags
|
||||
if (lexer == SCLEX_HTML && ! (style >= SCE_HPHP_DEFAULT && style <= SCE_HPHP_OPERATOR))
|
||||
return;
|
||||
|
||||
// get the indentation
|
||||
if (doc_list[idx].use_auto_indention) get_indent(sci, pos, TRUE);
|
||||
eol = g_strconcat(utils_get_eol_char(idx), indent, NULL);
|
||||
sci_get_text_range(sci, pos - 16, pos - 1, buf);
|
||||
// check the first 8 characters of buf for whitespace, but only in this line
|
||||
i = 14;
|
||||
while (i >= 0 && isalpha(buf[i])) i--; // find pos before keyword
|
||||
while (i >= 0 && buf[i] != '\n' && buf[i] != '\r') // we want to stay in this line('\n' check)
|
||||
{
|
||||
if (! isspace(buf[i]))
|
||||
{
|
||||
g_free(eol);
|
||||
return;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
|
||||
// get the whitespace for additional indentation
|
||||
space = utils_get_whitespace(app->pref_editor_tab_width, FALSE);
|
||||
space_len = strlen(space);
|
||||
|
||||
// "pattern", buf + x, y -> x + y = 15, because buf is (pos - 16)...(pos - 1) = 15
|
||||
// "pattern", buf + x, y -> x + y = 15, because buf is (pos - 15)...(pos) = 15
|
||||
if (! strncmp("if", buf + 13, 2))
|
||||
{
|
||||
if (! isspace(*(buf + 12)))
|
||||
{
|
||||
utils_free_pointers(eol, space, NULL);
|
||||
return;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
construct = g_strdup_printf("()%s{%s%s%s}%s", eol, eol, space, eol, eol);
|
||||
|
||||
SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
|
||||
sci_goto_pos(sci, pos + 1, TRUE);
|
||||
g_free(construct);
|
||||
}
|
||||
else if (! strncmp("else", buf + 11, 4))
|
||||
{
|
||||
if (! isspace(*(buf + 10)))
|
||||
{
|
||||
utils_free_pointers(eol, space, NULL);
|
||||
return;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
construct = g_strdup_printf("%s{%s%s%s}%s", eol, eol, space, eol, eol);
|
||||
|
||||
SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
|
||||
sci_goto_pos(sci, pos + 3 + space_len + (2 * strlen(indent)), TRUE);
|
||||
g_free(construct);
|
||||
}
|
||||
else if (! strncmp("for", buf + 12, 3))
|
||||
{
|
||||
@ -1050,10 +979,7 @@ void sci_cb_auto_forif(gint idx, gint pos)
|
||||
gint contruct_len;
|
||||
|
||||
if (! isspace(*(buf + 11)))
|
||||
{
|
||||
utils_free_pointers(eol, space, NULL);
|
||||
return;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
if (doc_list[idx].file_type->id == GEANY_FILETYPES_PHP)
|
||||
{
|
||||
@ -1075,99 +1001,153 @@ void sci_cb_auto_forif(gint idx, gint pos)
|
||||
SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
|
||||
sci_goto_pos(sci, pos + contruct_len, TRUE);
|
||||
g_free(var);
|
||||
g_free(construct);
|
||||
}
|
||||
else if (! strncmp("while", buf + 10, 5))
|
||||
{
|
||||
if (! isspace(*(buf + 9)))
|
||||
{
|
||||
utils_free_pointers(eol, space, NULL);
|
||||
return;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
construct = g_strdup_printf("()%s{%s%s%s}%s", eol, eol, space, eol, eol);
|
||||
|
||||
SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
|
||||
sci_goto_pos(sci, pos + 1, TRUE);
|
||||
g_free(construct);
|
||||
}
|
||||
else if (! strncmp("do", buf + 13, 2))
|
||||
{
|
||||
if (! isspace(*(buf + 12)))
|
||||
{
|
||||
utils_free_pointers(eol, space, NULL);
|
||||
return;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
construct = g_strdup_printf("%s{%s%s%s}%swhile ();%s", eol, eol, space, eol, eol, eol);
|
||||
|
||||
SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
|
||||
sci_goto_pos(sci, pos + 3 + space_len + (2 * strlen(indent)), TRUE);
|
||||
g_free(construct);
|
||||
}
|
||||
else if (! strncmp("try", buf + 12, 3))
|
||||
{
|
||||
if (! isspace(*(buf + 11)))
|
||||
{
|
||||
utils_free_pointers(eol, space, NULL);
|
||||
return;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
construct = g_strdup_printf("%s{%s%s%s}%scatch ()%s{%s%s%s}%s",
|
||||
eol, eol, space, eol, eol, eol, eol, space, eol, eol);
|
||||
|
||||
SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
|
||||
sci_goto_pos(sci, pos + 3 + space_len + (2 * strlen(indent)), TRUE);
|
||||
g_free(construct);
|
||||
}
|
||||
else if (! strncmp("switch", buf + 9, 6))
|
||||
{
|
||||
if (! isspace(*(buf + 8)))
|
||||
{
|
||||
utils_free_pointers(eol, space, NULL);
|
||||
return;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
construct = g_strdup_printf("()%s{%s%scase : break;%s%sdefault: %s}%s",
|
||||
eol, eol, space, eol, space, eol, eol);
|
||||
|
||||
SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
|
||||
sci_goto_pos(sci, pos + 1, TRUE);
|
||||
g_free(construct);
|
||||
}
|
||||
else if (doc_list[idx].file_type->id == GEANY_FILETYPES_FERITE && ! strncmp("iferr", buf + 10, 5))
|
||||
{
|
||||
if (doc_list[idx].file_type->id != GEANY_FILETYPES_FERITE ||
|
||||
! isspace(*(buf + 9)))
|
||||
{
|
||||
utils_free_pointers(eol, space, NULL);
|
||||
return;
|
||||
}
|
||||
if (! isspace(*(buf + 9)))
|
||||
return FALSE;
|
||||
|
||||
construct = g_strdup_printf("%s{%s%s%s}%sfix%s{%s%s%s}%s",
|
||||
eol, eol, space, eol, eol, eol, eol, space, eol, eol);
|
||||
|
||||
SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
|
||||
sci_goto_pos(sci, pos + 3 + space_len + (2 * strlen(indent)), TRUE);
|
||||
g_free(construct);
|
||||
}
|
||||
else if (doc_list[idx].file_type->id == GEANY_FILETYPES_FERITE && ! strncmp("monitor", buf + 8, 7))
|
||||
{
|
||||
if (! isspace(*(buf + 7)))
|
||||
{
|
||||
utils_free_pointers(eol, space, NULL);
|
||||
return;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
construct = g_strdup_printf("%s{%s%s%s}%shandle%s{%s%s%s}%s",
|
||||
eol, eol, space, eol, eol, eol, eol, space, eol, eol);
|
||||
|
||||
SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
|
||||
sci_goto_pos(sci, pos + 3 + space_len + (2 * strlen(indent)), TRUE);
|
||||
g_free(construct);
|
||||
}
|
||||
result = (construct != NULL);
|
||||
g_free(construct);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static gboolean at_eol(ScintillaObject *sci, gint pos)
|
||||
{
|
||||
gint line = sci_get_line_from_position(sci, pos);
|
||||
|
||||
return (pos == sci_get_line_end_position(sci, line));
|
||||
}
|
||||
|
||||
|
||||
gboolean sci_cb_auto_forif(gint idx, gint pos)
|
||||
{
|
||||
gboolean result;
|
||||
static gchar buf[16];
|
||||
gchar *eol;
|
||||
gchar *space;
|
||||
gint lexer, style;
|
||||
gint i;
|
||||
ScintillaObject *sci;
|
||||
|
||||
if (idx == -1 || ! doc_list[idx].is_valid || doc_list[idx].file_type == NULL) return FALSE;
|
||||
|
||||
// only for C, C++, D, Ferite, Java, JavaScript, Perl and PHP
|
||||
if (doc_list[idx].file_type->id != GEANY_FILETYPES_PHP &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_C &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_D &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_CPP &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_PERL &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_JAVA &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_JS &&
|
||||
doc_list[idx].file_type->id != GEANY_FILETYPES_FERITE)
|
||||
return FALSE;
|
||||
|
||||
sci = doc_list[idx].sci;
|
||||
// return if we are editing an existing line (chars on right of cursor)
|
||||
if (! at_eol(sci, pos))
|
||||
return FALSE;
|
||||
|
||||
lexer = SSM(sci, SCI_GETLEXER, 0, 0);
|
||||
style = SSM(sci, SCI_GETSTYLEAT, pos - 2, 0);
|
||||
// return, if we are in a comment
|
||||
if (is_comment(lexer, style))
|
||||
return FALSE;
|
||||
// never auto complete in a PHP file outside of the <? ?> tags
|
||||
if (lexer == SCLEX_HTML && ! (style >= SCE_HPHP_DEFAULT && style <= SCE_HPHP_OPERATOR))
|
||||
return FALSE;
|
||||
|
||||
sci_get_text_range(sci, pos - 15, pos, buf);
|
||||
|
||||
/* check that the chars before the current word are only whitespace (on this line).
|
||||
* this prevents completion of '} while ' */
|
||||
i = MIN(strlen(buf) - 1, 15); // index before \0 char
|
||||
while (i >= 0 && isalpha(buf[i])) i--; // find pos before keyword
|
||||
while (i >= 0 && buf[i] != '\n' && buf[i] != '\r') // we want to stay in this line('\n' check)
|
||||
{
|
||||
if (! isspace(buf[i]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
|
||||
// get the indentation
|
||||
if (doc_list[idx].use_auto_indention) get_indent(sci, pos, TRUE);
|
||||
eol = g_strconcat(utils_get_eol_char(idx), indent, NULL);
|
||||
|
||||
// get the whitespace for additional indentation
|
||||
space = utils_get_whitespace(app->pref_editor_tab_width, FALSE);
|
||||
|
||||
sci_insert_text(sci, pos++, " "); // the construct matching expects a space
|
||||
result = complete_constructs(idx, pos, buf, space, eol);
|
||||
if (! result)
|
||||
{
|
||||
sci_set_current_position(sci, pos, FALSE);
|
||||
SSM(sci, SCI_DELETEBACK, 0, 0); // cancel the space
|
||||
}
|
||||
utils_free_pointers(eol, space, NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -2196,3 +2176,5 @@ void sci_cb_select_word(ScintillaObject *sci)
|
||||
|
||||
SSM(sci, SCI_SETSEL, start, end);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -55,7 +55,7 @@ gboolean sci_cb_start_auto_complete(gint idx, gint pos, gboolean force);
|
||||
|
||||
void sci_cb_close_block(gint idx, gint pos);
|
||||
|
||||
void sci_cb_auto_forif(gint idx, gint pos);
|
||||
gboolean sci_cb_auto_forif(gint idx, gint pos);
|
||||
|
||||
void sci_cb_auto_latex(gint idx, gint pos);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user