geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

navqueue.c
Go to the documentation of this file.
1/*
2 * navqueue.c - this file is part of Geany, a fast and lightweight IDE
3 *
4 * Copyright 2007 The Geany contributors
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21/*
22 * Simple code navigation
23 */
24
25#ifdef HAVE_CONFIG_H
26# include "config.h"
27#endif
28
29#include "navqueue.h"
30
31#include "document.h"
32#include "geanyobject.h"
33#include "sciwrappers.h"
34#include "toolbar.h"
35#include "utils.h"
36
37#include <gtk/gtk.h>
38
39
40/* for the navigation history queue */
41typedef struct
42{
43 const gchar *file; /* This is the document's filename, in UTF-8 */
44 gint pos;
45} filepos;
46
47static GQueue *navigation_queue;
48static guint nav_queue_pos;
49
50static GtkAction *navigation_buttons[2];
51
52
53
54void navqueue_init(void)
55{
56 navigation_queue = g_queue_new();
57 nav_queue_pos = 0;
58
61
62 gtk_action_set_sensitive(navigation_buttons[0], FALSE);
63 gtk_action_set_sensitive(navigation_buttons[1], FALSE);
64}
65
66
67void navqueue_free(void)
68{
69 while (! g_queue_is_empty(navigation_queue))
70 {
71 g_free(g_queue_pop_tail(navigation_queue));
72 }
73 g_queue_free(navigation_queue);
74}
75
76
77static void adjust_buttons(void)
78{
79 if (g_queue_get_length(navigation_queue) < 2)
80 {
81 gtk_action_set_sensitive(navigation_buttons[0], FALSE);
82 gtk_action_set_sensitive(navigation_buttons[1], FALSE);
83 return;
84 }
85 if (nav_queue_pos == 0)
86 {
87 gtk_action_set_sensitive(navigation_buttons[0], TRUE);
88 gtk_action_set_sensitive(navigation_buttons[1], FALSE);
89 return;
90 }
91 /* forward should be sensitive since where not at the start */
92 gtk_action_set_sensitive(navigation_buttons[1], TRUE);
93
94 /* back should be sensitive if there's a place to go back to */
95 (nav_queue_pos < g_queue_get_length(navigation_queue) - 1) ?
96 gtk_action_set_sensitive(navigation_buttons[0], TRUE) :
97 gtk_action_set_sensitive(navigation_buttons[0], FALSE);
98}
99
100
101static gboolean
102queue_pos_matches(guint queue_pos, const gchar *fname, gint pos)
103{
104 if (queue_pos < g_queue_get_length(navigation_queue))
105 {
106 filepos *fpos = g_queue_peek_nth(navigation_queue, queue_pos);
107
108 return (utils_str_equal(fpos->file, fname) && fpos->pos == pos);
109 }
110 return FALSE;
111}
112
113
114static void add_new_position(const gchar *utf8_filename, gint pos)
115{
116 filepos *npos;
117 guint i;
118
119 if (queue_pos_matches(nav_queue_pos, utf8_filename, pos))
120 return; /* prevent duplicates */
121
122 npos = g_new0(filepos, 1);
123 npos->file = utf8_filename;
124 npos->pos = pos;
125
126 /* if we've jumped to a new position from inside the queue rather than going forward */
127 if (nav_queue_pos > 0)
128 {
129 for (i = 0; i < nav_queue_pos; i++)
130 {
131 g_free(g_queue_pop_head(navigation_queue));
132 }
133 nav_queue_pos = 0;
134 }
135 g_queue_push_head(navigation_queue, npos);
137}
138
139
140/**
141 * Adds old file position and new file position to the navqueue, then goes to the new position.
142 *
143 * @param old_doc The document of the previous position, if set as invalid (@c NULL) then no old
144 * position is set
145 * @param new_doc The document of the new position, must be valid.
146 * @param line the line number of the new position. It is counted with 1 as the first line, not 0.
147 *
148 * @return @c TRUE if the cursor has changed the position to @a line or @c FALSE otherwise.
149 **/
150GEANY_API_SYMBOL
151gboolean navqueue_goto_line(GeanyDocument *old_doc, GeanyDocument *new_doc, gint line)
152{
153 gint pos;
154
155 g_return_val_if_fail(old_doc == NULL || old_doc->is_valid, FALSE);
156 g_return_val_if_fail(DOC_VALID(new_doc), FALSE);
157 g_return_val_if_fail(line >= 1, FALSE);
158
159 pos = sci_get_position_from_line(new_doc->editor->sci, line - 1);
160
161 /* first add old file position */
162 if (old_doc != NULL && old_doc->file_name)
163 {
164 gint cur_pos = sci_get_current_position(old_doc->editor->sci);
165
166 add_new_position(old_doc->file_name, cur_pos);
167 }
168
169 /* now add new file position */
170 if (new_doc->file_name)
171 {
172 add_new_position(new_doc->file_name, pos);
173 }
174
175 return editor_goto_pos(new_doc->editor, pos, TRUE);
176}
177
178
179static gboolean goto_file_pos(const gchar *file, gint pos)
180{
182
183 if (doc == NULL)
184 return FALSE;
185
186 return editor_goto_pos(doc->editor, pos, TRUE);
187}
188
189
191{
192 filepos *fprev;
194
195 /* If the navqueue is currently at some position A, but the actual cursor is at some other
196 * place B, we should add B to the navqueue, so that (1) we go back to A, not to the next
197 * item in the queue; and (2) we can later restore B by going forward.
198 * (If A = B, add_new_position will ignore it.) */
199 if (doc)
200 {
201 if (doc->file_name)
203 }
204 else
205 /* see also https://github.com/geany/geany/pull/1537 */
206 g_warning("Attempted navigation when nothing is open");
207
208 /* return if theres no place to go back to */
209 if (g_queue_is_empty(navigation_queue) ||
210 nav_queue_pos >= g_queue_get_length(navigation_queue) - 1)
211 return;
212
213 /* jump back */
214 fprev = g_queue_peek_nth(navigation_queue, nav_queue_pos + 1);
215 if (goto_file_pos(fprev->file, fprev->pos))
216 {
218 }
219 else
220 {
221 /** TODO: add option to re open the file */
222 g_free(g_queue_pop_nth(navigation_queue, nav_queue_pos + 1));
223 }
225}
226
227
229{
230 filepos *fnext;
231
232 if (nav_queue_pos < 1 ||
233 nav_queue_pos >= g_queue_get_length(navigation_queue))
234 return;
235
236 /* jump forward */
237 fnext = g_queue_peek_nth(navigation_queue, nav_queue_pos - 1);
238 if (goto_file_pos(fnext->file, fnext->pos))
239 {
241 }
242 else
243 {
244 /** TODO: add option to re open the file */
245 g_free(g_queue_pop_nth(navigation_queue, nav_queue_pos - 1));
246 }
247
249}
250
251
252static gint find_by_filename(gconstpointer a, gconstpointer b)
253{
254 if (utils_str_equal(((const filepos*)a)->file, (const gchar*) b))
255 return 0;
256 else
257 return 1;
258}
259
260
261/* Remove all elements with the given filename */
263{
264 GList *match;
265
266 if (filename == NULL)
267 return;
268
269 while ((match = g_queue_find_custom(navigation_queue, filename, find_by_filename)))
270 {
271 g_free(match->data);
272 g_queue_delete_link(navigation_queue, match);
273 }
274
276}
GeanyDocument * document_get_current(void)
Finds the current document.
Definition: document.c:371
GeanyDocument * document_find_by_filename(const gchar *utf8_filename)
Finds a document with the given filename.
Definition: document.c:183
Document related actions: new, save, open, etc.
#define DOC_VALID(doc_ptr)
Null-safe way to check GeanyDocument::is_valid.
Definition: document.h:162
gint pos
Definition: editor.c:87
gboolean editor_goto_pos(GeanyEditor *editor, gint pos, gboolean mark)
Moves to position pos, switching to the document if necessary, setting a marker if mark is set.
Definition: editor.c:4732
vString * line
Definition: geany_cobol.c:133
static bool match(const unsigned char *line, const char *word)
Definition: geany_tcl.c:55
static GQueue * navigation_queue
Definition: navqueue.c:47
void navqueue_go_forward(void)
Definition: navqueue.c:228
static void adjust_buttons(void)
Definition: navqueue.c:77
static guint nav_queue_pos
Definition: navqueue.c:48
void navqueue_go_back(void)
Definition: navqueue.c:190
static gint find_by_filename(gconstpointer a, gconstpointer b)
Definition: navqueue.c:252
gboolean navqueue_goto_line(GeanyDocument *old_doc, GeanyDocument *new_doc, gint line)
Adds old file position and new file position to the navqueue, then goes to the new position.
Definition: navqueue.c:151
static void add_new_position(const gchar *utf8_filename, gint pos)
Definition: navqueue.c:114
static gboolean queue_pos_matches(guint queue_pos, const gchar *fname, gint pos)
Definition: navqueue.c:102
static gboolean goto_file_pos(const gchar *file, gint pos)
Definition: navqueue.c:179
static GtkAction * navigation_buttons[2]
Definition: navqueue.c:50
void navqueue_remove_file(const gchar *filename)
Definition: navqueue.c:262
void navqueue_free(void)
Definition: navqueue.c:67
void navqueue_init(void)
Definition: navqueue.c:54
Simple code navigation.
#define NULL
Definition: rbtree.h:150
gint sci_get_current_position(ScintillaObject *sci)
Gets the cursor position.
Definition: sciwrappers.c:507
gint sci_get_position_from_line(ScintillaObject *sci, gint line)
Gets the position for the start of line.
Definition: sciwrappers.c:497
Wrapper functions for the Scintilla editor widget SCI_* messages.
const gchar filename[]
Definition: stash-example.c:4
Structure for representing an open tab with all its properties.
Definition: document.h:81
gchar * file_name
The UTF-8 encoded file name.
Definition: document.h:92
gboolean is_valid
Flag used to check if this document is valid when iterating GeanyData::documents_array.
Definition: document.h:83
GeanyEditor * editor
The editor associated with the document.
Definition: document.h:98
ScintillaObject * sci
The Scintilla editor GtkWidget.
Definition: editor.h:152
const gchar * file
Definition: navqueue.c:43
gint pos
Definition: navqueue.c:44
GtkAction * toolbar_get_action_by_name(const gchar *name)
Definition: toolbar.c:152
Toolbar (prefs).
gboolean utils_str_equal(const gchar *a, const gchar *b)
NULL-safe string comparison.
Definition: utils.c:599
General utility functions, non-GTK related.