Real-time type keyword highlighting
* Add new function: document_update_tags(). * Refactor the various tag update functions into document_update_tags(). * Remove extra call to update the tags in document_new_file().
This commit is contained in:
parent
8bf9a7cb0c
commit
9bffb94cc4
2
HACKING
2
HACKING
@ -486,7 +486,7 @@ For brace indentation, update lexer_has_braces() in editor.c;
|
||||
indentation after ':' is done from on_new_line_added().
|
||||
|
||||
If the Scintilla lexer supports user type keyword highlighting (e.g.
|
||||
SCLEX_CPP), update document_update_type_keywords() in document.c.
|
||||
SCLEX_CPP), update document_update_tags() in document.c.
|
||||
|
||||
Adding a TagManager parser
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@ -621,7 +621,6 @@ void on_notebook1_switch_page_after(GtkNotebook *notebook, GtkNotebookPage *page
|
||||
ui_document_show_hide(doc); /* update the document menu */
|
||||
build_menu_update(doc);
|
||||
sidebar_update_tag_list(doc, FALSE);
|
||||
document_update_type_keywords(doc);
|
||||
|
||||
/* We delay the check to avoid weird fast, unintended switching of notebook pages when
|
||||
* the 'file has changed' dialog is shown while the switch event is not yet completely
|
||||
|
||||
176
src/document.c
176
src/document.c
@ -103,7 +103,6 @@ typedef struct
|
||||
|
||||
static void document_undo_clear(GeanyDocument *doc);
|
||||
static void document_redo_add(GeanyDocument *doc, guint type, gpointer data);
|
||||
static gboolean update_tags_from_buffer(GeanyDocument *doc);
|
||||
static gboolean remove_page(guint page_num);
|
||||
|
||||
|
||||
@ -718,11 +717,10 @@ GeanyDocument *document_new_file(const gchar *utf8_filename, GeanyFiletype *ft,
|
||||
if (ft == NULL && utf8_filename != NULL) /* guess the filetype from the filename if one is given */
|
||||
ft = filetypes_detect_from_document(doc);
|
||||
|
||||
document_set_filetype(doc, ft); /* also clears taglist */
|
||||
document_set_filetype(doc, ft); /* also re-parses tags */
|
||||
|
||||
ui_set_window_title(doc);
|
||||
build_menu_update(doc);
|
||||
document_update_tag_list(doc, FALSE);
|
||||
document_set_text_changed(doc, FALSE);
|
||||
ui_document_show_hide(doc); /* update the document menu */
|
||||
|
||||
@ -2207,41 +2205,35 @@ gint document_replace_all(GeanyDocument *doc, const gchar *find_text, const gcha
|
||||
}
|
||||
|
||||
|
||||
static gboolean update_tags_from_buffer(GeanyDocument *doc)
|
||||
/*
|
||||
* Parses or re-parses the document's buffer and updates the type
|
||||
* keywords and symbol list.
|
||||
*
|
||||
* @param doc The document.
|
||||
*/
|
||||
void document_update_tags(GeanyDocument *doc)
|
||||
{
|
||||
guchar *buffer_ptr;
|
||||
gsize len;
|
||||
GString *keywords_str;
|
||||
gchar *keywords;
|
||||
gint keyword_idx;
|
||||
|
||||
len = sci_get_length(doc->editor->sci);
|
||||
g_return_if_fail(DOC_VALID(doc));
|
||||
g_return_if_fail(app->tm_workspace != NULL);
|
||||
|
||||
/* gets a direct character pointer from Scintilla.
|
||||
* this is OK because tm_source_file_buffer_update() does not modify the
|
||||
* buffer, it only requires that buffer doesn't change while it's running,
|
||||
* which it won't since it runs in this thread (ie. synchronously).
|
||||
* see tagmanager/read.c:bufferOpen */
|
||||
buffer_ptr = (guchar *) scintilla_send_message(doc->editor->sci, SCI_GETCHARACTERPOINTER, 0, 0);
|
||||
|
||||
return tm_source_file_buffer_update(doc->tm_file, buffer_ptr, len, TRUE);
|
||||
}
|
||||
|
||||
|
||||
void document_update_tag_list(GeanyDocument *doc, gboolean update)
|
||||
{
|
||||
/* We must call sidebar_update_tag_list() before returning,
|
||||
* to ensure that the symbol list is always updated properly (e.g.
|
||||
* when creating a new document with a partial filename set. */
|
||||
gboolean success = FALSE;
|
||||
|
||||
/* if the filetype doesn't have a tag parser or it is a new file */
|
||||
if (doc == NULL || doc->file_type == NULL || app->tm_workspace == NULL ||
|
||||
! filetype_has_tags(doc->file_type) || ! doc->file_name)
|
||||
/* early out if it's a new file or doesn't support tags */
|
||||
if (! doc->file_name || ! doc->file_type || !filetype_has_tags(doc->file_type))
|
||||
{
|
||||
/* set the default (empty) tag list */
|
||||
/* We must call sidebar_update_tag_list() before returning,
|
||||
* to ensure that the symbol list is always updated properly (e.g.
|
||||
* when creating a new document with a partial filename set. */
|
||||
sidebar_update_tag_list(doc, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (doc->tm_file == NULL)
|
||||
/* create a new TM file if there isn't one yet */
|
||||
if (! doc->tm_file)
|
||||
{
|
||||
gchar *locale_filename = utils_get_locale_from_utf8(doc->file_name);
|
||||
const gchar *name;
|
||||
@ -2251,28 +2243,65 @@ void document_update_tag_list(GeanyDocument *doc, gboolean update)
|
||||
doc->tm_file = tm_source_file_new(locale_filename, FALSE, name);
|
||||
g_free(locale_filename);
|
||||
|
||||
if (doc->tm_file)
|
||||
if (doc->tm_file && !tm_workspace_add_object(doc->tm_file))
|
||||
{
|
||||
if (!tm_workspace_add_object(doc->tm_file))
|
||||
{
|
||||
tm_work_object_free(doc->tm_file);
|
||||
doc->tm_file = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (update)
|
||||
update_tags_from_buffer(doc);
|
||||
success = TRUE;
|
||||
}
|
||||
tm_work_object_free(doc->tm_file);
|
||||
doc->tm_file = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
/* early out if there's no work object and we couldn't create one */
|
||||
if (doc->tm_file == NULL)
|
||||
{
|
||||
success = update_tags_from_buffer(doc);
|
||||
if (G_UNLIKELY(! success))
|
||||
geany_debug("tag list updating failed");
|
||||
/* We must call sidebar_update_tag_list() before returning,
|
||||
* to ensure that the symbol list is always updated properly (e.g.
|
||||
* when creating a new document with a partial filename set. */
|
||||
sidebar_update_tag_list(doc, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parse Scintilla's buffer directly using TagManager
|
||||
* Note: this buffer *MUST NOT* be modified */
|
||||
len = sci_get_length(doc->editor->sci);
|
||||
buffer_ptr = (guchar *) scintilla_send_message(doc->editor->sci, SCI_GETCHARACTERPOINTER, 0, 0);
|
||||
tm_source_file_buffer_update(doc->tm_file, buffer_ptr, len, TRUE);
|
||||
|
||||
sidebar_update_tag_list(doc, TRUE);
|
||||
|
||||
/* some filetypes support type keywords (such as struct names), but not
|
||||
* necessarily all filetypes for a particular scintilla lexer. this
|
||||
* tells us whether the filetype supports keywords, and if so
|
||||
* which index to use for the scintilla keywords set. */
|
||||
switch (doc->file_type->id)
|
||||
{
|
||||
case GEANY_FILETYPES_C:
|
||||
case GEANY_FILETYPES_CPP:
|
||||
case GEANY_FILETYPES_CS:
|
||||
case GEANY_FILETYPES_D:
|
||||
case GEANY_FILETYPES_JAVA:
|
||||
case GEANY_FILETYPES_VALA:
|
||||
{
|
||||
|
||||
/* index of the keyword set in the Scintilla lexer, for
|
||||
* example in LexCPP.cxx, see "cppWordLists" global array.
|
||||
* TODO: this magic number should be a member of the filetype */
|
||||
keyword_idx = 3;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return; /* early out if type keywords are not supported */
|
||||
}
|
||||
|
||||
/* get any type keywords and tell scintilla about them
|
||||
* this will cause the type keywords to be colourized in scintilla */
|
||||
keywords_str = symbols_find_tags_as_string(app->tm_workspace->work_object.tags_array,
|
||||
TM_GLOBAL_TYPE_MASK, doc->file_type->lang);
|
||||
if (keywords_str)
|
||||
{
|
||||
keywords = g_string_free(keywords_str, FALSE);
|
||||
sci_set_keywords(doc->editor->sci, keyword_idx, keywords);
|
||||
g_free(keywords);
|
||||
}
|
||||
sidebar_update_tag_list(doc, success);
|
||||
}
|
||||
|
||||
|
||||
@ -2284,9 +2313,11 @@ static gboolean on_document_update_tag_list_idle(gpointer data)
|
||||
return FALSE;
|
||||
|
||||
if (! main_status.quitting)
|
||||
document_update_tag_list(doc, TRUE);
|
||||
document_update_tags(doc);
|
||||
|
||||
doc->priv->tag_list_update_source = 0;
|
||||
|
||||
/* don't update the tags until another modification of the buffer */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -2296,59 +2327,15 @@ void document_update_tag_list_in_idle(GeanyDocument *doc)
|
||||
if (editor_prefs.autocompletion_update_freq <= 0 || ! filetype_has_tags(doc->file_type))
|
||||
return;
|
||||
|
||||
/* prevent "stacking up" callback handlers, we only need one to run soon */
|
||||
if (doc->priv->tag_list_update_source != 0)
|
||||
g_source_remove(doc->priv->tag_list_update_source);
|
||||
|
||||
doc->priv->tag_list_update_source = g_timeout_add_full(G_PRIORITY_LOW,
|
||||
editor_prefs.autocompletion_update_freq, on_document_update_tag_list_idle, doc, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Updates the type keywords in the document's Scintilla widget.
|
||||
*
|
||||
* @param doc The document
|
||||
*/
|
||||
void document_update_type_keywords(GeanyDocument *doc)
|
||||
{
|
||||
guint keyword_idx;
|
||||
gchar *keywords;
|
||||
GString *str;
|
||||
GPtrArray *tags_array;
|
||||
|
||||
g_return_if_fail(DOC_VALID(doc));
|
||||
g_return_if_fail(app->tm_workspace != NULL);
|
||||
|
||||
switch (doc->file_type->id)
|
||||
{
|
||||
case GEANY_FILETYPES_C:
|
||||
case GEANY_FILETYPES_CPP:
|
||||
case GEANY_FILETYPES_CS:
|
||||
case GEANY_FILETYPES_D:
|
||||
case GEANY_FILETYPES_JAVA:
|
||||
case GEANY_FILETYPES_VALA:
|
||||
/* index of the keyword set in the Scintilla lexer, for
|
||||
* example in LexCPP.cxx, see "cppWordLists" global array. */
|
||||
keyword_idx = 3;
|
||||
break;
|
||||
/* early out if user type keywords are not supported */
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
tags_array = app->tm_workspace->work_object.tags_array;
|
||||
if (tags_array)
|
||||
{
|
||||
str = symbols_find_tags_as_string(tags_array, TM_GLOBAL_TYPE_MASK, doc->file_type->lang);
|
||||
if (str)
|
||||
{
|
||||
keywords = g_string_free(str, FALSE);
|
||||
sci_set_keywords(doc->editor->sci, keyword_idx, keywords);
|
||||
g_free(keywords);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void document_load_config(GeanyDocument *doc, GeanyFiletype *type,
|
||||
gboolean filetype_changed)
|
||||
{
|
||||
@ -2377,10 +2364,7 @@ static void document_load_config(GeanyDocument *doc, GeanyFiletype *type,
|
||||
doc->priv->symbol_list_sort_mode = type->priv->symbol_list_sort_mode;
|
||||
}
|
||||
|
||||
document_update_tag_list(doc, TRUE);
|
||||
|
||||
/* Update session typename keywords. */
|
||||
document_update_type_keywords(doc);
|
||||
document_update_tags(doc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -232,12 +232,10 @@ gint document_replace_all(GeanyDocument *doc, const gchar *find_text, const gcha
|
||||
void document_replace_sel(GeanyDocument *doc, const gchar *find_text, const gchar *replace_text,
|
||||
const gchar *original_find_text, const gchar *original_replace_text, gint flags);
|
||||
|
||||
void document_update_tag_list(GeanyDocument *doc, gboolean update);
|
||||
void document_update_tags(GeanyDocument *doc);
|
||||
|
||||
void document_update_tag_list_in_idle(GeanyDocument *doc);
|
||||
|
||||
void document_update_type_keywords(GeanyDocument *doc);
|
||||
|
||||
void document_set_encoding(GeanyDocument *doc, const gchar *new_encoding);
|
||||
|
||||
gboolean document_check_disk_status(GeanyDocument *doc, gboolean force);
|
||||
|
||||
@ -2544,7 +2544,7 @@ static gboolean cb_func_document_action(guint key_id)
|
||||
ui_document_show_hide(doc);
|
||||
break;
|
||||
case GEANY_KEYS_DOCUMENT_RELOADTAGLIST:
|
||||
document_update_tag_list(doc, TRUE);
|
||||
document_update_tags(doc);
|
||||
break;
|
||||
case GEANY_KEYS_DOCUMENT_FOLDALL:
|
||||
editor_fold_all(doc->editor);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user