806
826
/* the following code surely can be improved, at the moment it collects some iters
807
827
* for removal and after that the actual removal is done. I didn't find a way to find and remove
808
828
* an empty row in one loop (next iter fails then) */
809
static void hide_empty_rows(GtkTreeModel *model, GtkTreeStore *store)
829
static void hide_empty_rows(GtkTreeStore *store)
811
831
GtkTreeIter iter, *iters[MAX_SYMBOL_TYPES] = { NULL };
814
if (! gtk_tree_model_get_iter_first(model, &iter))
834
if (! gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
815
835
return; /* stop when first iter is invalid, i.e. no elements */
817
837
do /* first collect the iters we need to delete empty rows */
819
if (! gtk_tree_model_iter_has_child(model, &iter))
839
if (! gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), &iter))
820
840
iters[i++] = gtk_tree_iter_copy(&iter);
821
} while (gtk_tree_model_iter_next(model, &iter));
841
} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
823
843
/* now actually delete the collected iters */
824
844
for (i = 0; i < MAX_SYMBOL_TYPES; i++)
834
gboolean symbols_recreate_tag_list(gint idx, gint sort_mode)
854
gboolean symbols_recreate_tag_list(GeanyDocument *doc, gint sort_mode)
837
857
const GList *tags;
838
858
GtkTreeIter iter;
840
859
static gint prev_sort_mode = SYMBOLS_SORT_BY_NAME;
841
filetype_id ft_id = FILETYPE_ID(doc_list[idx].file_type);
843
g_return_val_if_fail(DOC_IDX_VALID(idx), FALSE);
862
g_return_val_if_fail(doc != NULL, FALSE);
864
ft_id = FILETYPE_ID(doc->file_type);
845
866
if (sort_mode == SYMBOLS_SORT_USE_PREVIOUS)
846
867
sort_mode = prev_sort_mode;
848
869
prev_sort_mode = sort_mode;
850
tags = get_tag_list(idx, tm_tag_max_t, sort_mode);
851
if (doc_list[idx].tm_file == NULL || tags == NULL)
871
tags = get_tag_list(doc, tm_tag_max_t, sort_mode);
872
if (doc->tm_file == NULL || tags == NULL)
854
gtk_tree_store_clear(doc_list[idx].tag_store);
855
/* unref the store to speed up the filling(from TreeView Tutorial) */
856
model = gtk_tree_view_get_model(GTK_TREE_VIEW(doc_list[idx].tag_tree));
857
875
/* Make sure the model stays with us after the tree view unrefs it */
876
g_object_ref(GTK_TREE_MODEL(doc->priv->tag_store));
859
877
/* Detach model from view */
860
gtk_tree_view_set_model(GTK_TREE_VIEW(doc_list[idx].tag_tree), NULL);
878
gtk_tree_view_set_model(GTK_TREE_VIEW(doc->priv->tag_tree), NULL);
879
/* Clear all contents */
880
gtk_tree_store_clear(doc->priv->tag_store);
863
883
for (tmp = (GList*)tags; tmp; tmp = g_list_next(tmp))
1245
/* This could perhaps be improved to check for #if, class etc. */
1246
static gint get_function_fold_number(GeanyDocument *doc)
1248
/* for Java the functions are always one fold level above the class scope */
1249
if (FILETYPE_ID(doc->file_type) == GEANY_FILETYPES_JAVA)
1250
return SC_FOLDLEVELBASE + 1;
1252
return SC_FOLDLEVELBASE;
1256
/* Should be used only with symbols_get_current_function. */
1257
static gboolean current_function_changed(GeanyDocument *doc, gint cur_line, gint fold_level)
1259
static gint old_line = -2;
1260
static GeanyDocument *old_doc = NULL;
1261
static gint old_fold_num = -1;
1262
const gint fold_num = fold_level & SC_FOLDLEVELNUMBERMASK;
1265
/* check if the cached line and file index have changed since last time: */
1266
if (doc == NULL || doc != old_doc)
1269
if (cur_line == old_line)
1273
/* if the line has only changed by 1 */
1274
if (abs(cur_line - old_line) == 1)
1276
const gint fn_fold =
1277
get_function_fold_number(doc);
1278
/* It's the same function if the fold number hasn't changed, or both the new
1279
* and old fold numbers are above the function fold number. */
1281
fold_num == old_fold_num ||
1282
(old_fold_num > fn_fold && fold_num > fn_fold);
1289
/* record current line and file index for next time */
1290
old_line = cur_line;
1292
old_fold_num = fold_num;
1297
/* Parse the function name up to 2 lines before tag_line.
1298
* C++ like syntax should be parsed by parse_cpp_function_at_line, otherwise the return
1299
* type or argument names can be confused with the function name. */
1300
static gchar *parse_function_at_line(ScintillaObject *sci, gint tag_line)
1302
gint start, end, max_pos;
1306
switch (sci_get_lexer(sci))
1308
case SCLEX_RUBY: fn_style = SCE_RB_DEFNAME; break;
1309
case SCLEX_PYTHON: fn_style = SCE_P_DEFNAME; break;
1310
default: fn_style = SCE_C_IDENTIFIER; /* several lexers use SCE_C_IDENTIFIER */
1312
start = sci_get_position_from_line(sci, tag_line - 2);
1313
max_pos = sci_get_position_from_line(sci, tag_line + 1);
1314
while (sci_get_style_at(sci, start) != fn_style
1315
&& start < max_pos) start++;
1318
while (sci_get_style_at(sci, end) == fn_style
1319
&& end < max_pos) end++;
1321
if (start == end) return NULL;
1322
cur_tag = g_malloc(end - start + 1);
1323
sci_get_text_range(sci, start, end, cur_tag);
1328
/* Parse the function name */
1329
static gchar *parse_cpp_function_at_line(ScintillaObject *sci, gint tag_line)
1331
gint start, end, first_pos, max_pos;
1336
first_pos = end = sci_get_position_from_line(sci, tag_line);
1337
max_pos = sci_get_position_from_line(sci, tag_line + 1);
1339
/* goto the begin of function body */
1340
while (end < max_pos &&
1341
(tmp = sci_get_char_at(sci, end)) != '{' &&
1343
if (tmp == 0) end --;
1345
/* go back to the end of function identifier */
1346
while (end > 0 && end > first_pos - 500 &&
1347
(tmp = sci_get_char_at(sci, end)) != '(' &&
1350
if (end < 0) end = 0;
1352
/* skip whitespaces between identifier and ( */
1353
while (end > 0 && isspace(sci_get_char_at(sci, end))) end--;
1357
/* Use tmp to find SCE_C_IDENTIFIER or SCE_C_GLOBALCLASS chars */
1358
while (start >= 0 && ((tmp = sci_get_style_at(sci, start)) == SCE_C_IDENTIFIER
1359
|| tmp == SCE_C_GLOBALCLASS
1360
|| (c = sci_get_char_at(sci, start)) == '~'
1363
if (start != 0 && start < end) start++; /* correct for last non-matching char */
1365
if (start == end) return NULL;
1366
cur_tag = g_malloc(end - start + 2);
1367
sci_get_text_range(sci, start, end + 1, cur_tag);
1372
/* Sets *tagname to point at the current function or tag name.
1373
* If doc is NULL, reset the cached current tag data to ensure it will be reparsed on the next
1374
* call to this function.
1375
* Returns: line number of the current tag, or -1 if unknown. */
1376
gint symbols_get_current_function(GeanyDocument *doc, const gchar **tagname)
1378
static gint tag_line = -1;
1379
static gchar *cur_tag = NULL;
1382
TMWorkObject *tm_file;
1384
if (doc == NULL) /* reset current function */
1386
current_function_changed(NULL, -1, -1);
1388
cur_tag = g_strdup(_("unknown"));
1389
if (tagname != NULL)
1395
line = sci_get_current_line(doc->editor->sci);
1396
fold_level = sci_get_fold_level(doc->editor->sci, line);
1397
/* check if the cached line and file index have changed since last time: */
1398
if (! current_function_changed(doc, line, fold_level))
1400
/* we can assume same current function as before */
1404
g_free(cur_tag); /* free the old tag, it will be replaced. */
1406
/* if line is at base fold level, we're not in a function */
1407
if ((fold_level & SC_FOLDLEVELNUMBERMASK) == SC_FOLDLEVELBASE)
1409
cur_tag = g_strdup(_("unknown"));
1414
tm_file = doc->tm_file;
1416
/* if the document has no changes, get the previous function name from TM */
1417
if(! doc->changed && tm_file != NULL && tm_file->tags_array != NULL)
1419
const TMTag *tag = (const TMTag*) tm_get_current_function(tm_file->tags_array, line);
1424
tmp = tag->atts.entry.scope;
1425
cur_tag = tmp ? g_strconcat(tmp, "::", tag->name, NULL) : g_strdup(tag->name);
1427
tag_line = tag->atts.entry.line;
1432
/* parse the current function name here because TM line numbers may have changed,
1433
* and it would take too long to reparse the whole file. */
1434
if (doc->file_type != NULL && doc->file_type->id != GEANY_FILETYPES_NONE)
1436
const gint fn_fold = get_function_fold_number(doc);
1439
do /* find the top level fold point */
1441
tag_line = sci_get_fold_parent(doc->editor->sci, tag_line);
1442
fold_level = sci_get_fold_level(doc->editor->sci, tag_line);
1443
} while (tag_line >= 0 &&
1444
(fold_level & SC_FOLDLEVELNUMBERMASK) != fn_fold);
1448
if (sci_get_lexer(doc->editor->sci) == SCLEX_CPP)
1449
cur_tag = parse_cpp_function_at_line(doc->editor->sci, tag_line);
1451
cur_tag = parse_function_at_line(doc->editor->sci, tag_line);
1453
if (cur_tag != NULL)
1461
cur_tag = g_strdup(_("unknown"));