Skip to content
This repository has been archived by the owner on Dec 23, 2018. It is now read-only.

Commit

Permalink
Use a Scintilla indicator to store navqueue positions
Browse files Browse the repository at this point in the history
Fixes geany#1480.
  • Loading branch information
vfaronov committed Apr 25, 2017
1 parent f500e6a commit ff1f28d
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 26 deletions.
5 changes: 4 additions & 1 deletion src/editor.h
Expand Up @@ -70,7 +70,10 @@ typedef enum
/** Indicator used to highlight search results in the document. This is a
* rounded box around the text. */
/* start container indicator outside of lexer indicators (0..7), see Scintilla docs */
GEANY_INDICATOR_SEARCH = 8
GEANY_INDICATOR_SEARCH = 8,
/* skip 9 which is used in PR #1470 */
/** Hidden indicator used to remember and recall navigation history (navqueue). */
GEANY_INDICATOR_NAVIGATION = 10
}
GeanyIndicator;

Expand Down
5 changes: 5 additions & 0 deletions src/highlighting.c
Expand Up @@ -660,6 +660,11 @@ static void styleset_common(ScintillaObject *sci, guint ft_id)
invert(common_style_set.styling[GCS_MARKER_SEARCH].background));
SSM(sci, SCI_INDICSETALPHA, GEANY_INDICATOR_SEARCH, 60);

/* The navigation indicator is used to store navqueue positions in a way that doesn't break
* whenever document is changed. We don't actually show it to the user. Although an option
* to draw it as INDIC_POINT might be useful in the future. */
SSM(sci, SCI_INDICSETSTYLE, GEANY_INDICATOR_NAVIGATION, INDIC_HIDDEN);

/* define marker symbols
* 0 -> line marker */
SSM(sci, SCI_MARKERDEFINE, 0, SC_MARK_SHORTARROW);
Expand Down
2 changes: 1 addition & 1 deletion src/keybindings.c
Expand Up @@ -2031,7 +2031,7 @@ static gboolean cb_func_goto_action(guint key_id)
return TRUE;
case GEANY_KEYS_GOTO_ADDPOSITION:
if (doc->file_name)
navqueue_add_position(doc->file_name, sci_get_current_position(doc->editor->sci));
navqueue_add_position(doc, sci_get_current_position(doc->editor->sci));
return TRUE;
case GEANY_KEYS_GOTO_LINE:
{
Expand Down
84 changes: 61 additions & 23 deletions src/navqueue.c
Expand Up @@ -42,12 +42,15 @@
/* for the navigation history queue */
typedef struct
{
const gchar *file; /* This is the document's filename, in UTF-8 */
gint pos;
} filepos;
/* The document's filename, in UTF-8 */
const gchar *file;
/* A unique ID that is associated with the navigation indicator in Scintilla. */
gint id;
} NavigationAnchor;

static GQueue *navigation_queue;
static guint nav_queue_pos;
static gint counter;

static GtkAction *navigation_buttons[2];

Expand All @@ -57,6 +60,7 @@ void navqueue_init(void)
{
navigation_queue = g_queue_new();
nav_queue_pos = 0;
counter = 0;

navigation_buttons[0] = toolbar_get_action_by_name("NavBack");
navigation_buttons[1] = toolbar_get_action_by_name("NavFor");
Expand Down Expand Up @@ -100,30 +104,59 @@ static void adjust_buttons(void)
}


static void set_id_on_position(GeanyDocument *doc, gint pos, gint id)
{
sci_indicator_set(doc->editor->sci, GEANY_INDICATOR_NAVIGATION);
sci_indicator_set_value(doc->editor->sci, id);
sci_indicator_fill(doc->editor->sci, pos, 1);
}


static gint get_position_for_id(GeanyDocument *doc, gint id)
{
gint pos = 0, prev;

do
{
/* Iterate over all ranges of the navigation indicator in this document. See, e.g.:
* https://groups.google.com/d/msg/scintilla-interest/TpBnulcikUo/ZAq9ol8eutMJ */
prev = pos;
pos = sci_indicator_end(doc->editor->sci, GEANY_INDICATOR_NAVIGATION, pos + 1);
if (sci_indicator_value_at(doc->editor->sci, GEANY_INDICATOR_NAVIGATION, pos) == id)
return pos;
} while (pos > prev);

return -1;
}


static gboolean
queue_pos_matches(guint queue_pos, const gchar *fname, gint pos)
queue_pos_matches(guint queue_pos, GeanyDocument *doc, gint pos)
{
if (queue_pos < g_queue_get_length(navigation_queue))
{
filepos *fpos = g_queue_peek_nth(navigation_queue, queue_pos);
NavigationAnchor *anchor = g_queue_peek_nth(navigation_queue, queue_pos);

return (utils_str_equal(fpos->file, fname) && fpos->pos == pos);
return utils_str_equal(anchor->file, doc->file_name)
&& get_position_for_id(doc, anchor->id) == pos;
}
return FALSE;
}


void navqueue_add_position(const gchar *utf8_filename, gint pos)
void navqueue_add_position(GeanyDocument *doc, gint pos)
{
filepos *npos;
NavigationAnchor *anchor;
guint i;

if (queue_pos_matches(nav_queue_pos, utf8_filename, pos))
if (queue_pos_matches(nav_queue_pos, doc, pos))
return; /* prevent duplicates */

npos = g_new0(filepos, 1);
npos->file = utf8_filename;
npos->pos = pos;
counter += 1;
anchor = g_new0(NavigationAnchor, 1);
anchor->file = doc->file_name;
anchor->id = counter;
set_id_on_position(doc, pos, anchor->id);

/* if we've jumped to a new position from inside the queue rather than going forward */
if (nav_queue_pos > 0)
Expand All @@ -134,7 +167,7 @@ void navqueue_add_position(const gchar *utf8_filename, gint pos)
}
nav_queue_pos = 0;
}
g_queue_push_head(navigation_queue, npos);
g_queue_push_head(navigation_queue, anchor);
adjust_buttons();
}

Expand Down Expand Up @@ -165,42 +198,47 @@ gboolean navqueue_goto_line(GeanyDocument *old_doc, GeanyDocument *new_doc, gint
{
gint cur_pos = sci_get_current_position(old_doc->editor->sci);

navqueue_add_position(old_doc->file_name, cur_pos);
navqueue_add_position(old_doc, cur_pos);
}

/* now add new file position */
if (new_doc->file_name)
{
navqueue_add_position(new_doc->file_name, pos);
navqueue_add_position(new_doc, pos);
}

return editor_goto_pos(new_doc->editor, pos, TRUE);
}


static gboolean goto_file_pos(const gchar *file, gint pos)
static gboolean goto_file_id(const gchar *file, gint id)
{
GeanyDocument *doc = document_find_by_filename(file);
gint pos;

if (doc == NULL)
return FALSE;

pos = get_position_for_id(doc, id);
if (pos < 0)
return FALSE;

return editor_goto_pos(doc->editor, pos, TRUE);
}


void navqueue_go_back(void)
{
filepos *fprev;
NavigationAnchor *prev;

/* return if theres no place to go back to */
if (g_queue_is_empty(navigation_queue) ||
nav_queue_pos >= g_queue_get_length(navigation_queue) - 1)
return;

/* jump back */
fprev = g_queue_peek_nth(navigation_queue, nav_queue_pos + 1);
if (goto_file_pos(fprev->file, fprev->pos))
prev = g_queue_peek_nth(navigation_queue, nav_queue_pos + 1);
if (goto_file_id(prev->file, prev->id))
{
nav_queue_pos++;
}
Expand All @@ -215,15 +253,15 @@ void navqueue_go_back(void)

void navqueue_go_forward(void)
{
filepos *fnext;
NavigationAnchor *next;

if (nav_queue_pos < 1 ||
nav_queue_pos >= g_queue_get_length(navigation_queue))
return;

/* jump forward */
fnext = g_queue_peek_nth(navigation_queue, nav_queue_pos - 1);
if (goto_file_pos(fnext->file, fnext->pos))
next = g_queue_peek_nth(navigation_queue, nav_queue_pos - 1);
if (goto_file_id(next->file, next->id))
{
nav_queue_pos--;
}
Expand All @@ -239,7 +277,7 @@ void navqueue_go_forward(void)

static gint find_by_filename(gconstpointer a, gconstpointer b)
{
if (utils_str_equal(((const filepos*)a)->file, (const gchar*) b))
if (utils_str_equal(((const NavigationAnchor*)a)->file, (const gchar*) b))
return 0;
else
return 1;
Expand Down
2 changes: 1 addition & 1 deletion src/navqueue.h
Expand Up @@ -44,7 +44,7 @@ void navqueue_init(void);

void navqueue_free(void);

void navqueue_add_position(const gchar *utf8_filename, gint pos);
void navqueue_add_position(GeanyDocument *doc, gint pos);

void navqueue_remove_file(const gchar *filename);

Expand Down
18 changes: 18 additions & 0 deletions src/sciwrappers.c
Expand Up @@ -1119,12 +1119,30 @@ void sci_indicator_set(ScintillaObject *sci, gint indic)
}


void sci_indicator_set_value(ScintillaObject *sci, gint value)
{
SSM(sci, SCI_SETINDICATORVALUE, (uptr_t) value, 0);
}


void sci_indicator_fill(ScintillaObject *sci, gint pos, gint len)
{
SSM(sci, SCI_INDICATORFILLRANGE, (uptr_t) pos, len);
}


gint sci_indicator_end(ScintillaObject *sci, gint indic, gint pos)
{
return (gint) SSM(sci, SCI_INDICATOREND, (uptr_t) indic, (uptr_t) pos);
}


gint sci_indicator_value_at(ScintillaObject *sci, gint indic, gint pos)
{
return (gint) SSM(sci, SCI_INDICATORVALUEAT, (uptr_t) indic, (uptr_t) pos);
}


/**
* Clears the currently set indicator from a range of text.
* Starting at @a pos, @a len characters long.
Expand Down
3 changes: 3 additions & 0 deletions src/sciwrappers.h
Expand Up @@ -179,7 +179,10 @@ void sci_set_readonly (ScintillaObject *sci, gboolean readonly);
gint sci_get_lines_selected (ScintillaObject *sci);
gint sci_get_first_visible_line (ScintillaObject *sci);

void sci_indicator_set_value (ScintillaObject *sci, gint value);
void sci_indicator_fill (ScintillaObject *sci, gint pos, gint len);
gint sci_indicator_end (ScintillaObject *sci, gint indic, gint pos);
gint sci_indicator_value_at (ScintillaObject *sci, gint indic, gint pos);

void sci_select_all (ScintillaObject *sci);
gint sci_get_line_indent_position(ScintillaObject *sci, gint line);
Expand Down

0 comments on commit ff1f28d

Please sign in to comment.