1 ;;; ecb-navigate.el --- Browser-navigation for ECB
3 ;; Copyright (C) 2000 - 2005 Jesper Nordenberg,
6 ;; Free Software Foundation, Inc.
8 ;; Author: Jesper Nordenberg <mayhem@home.se>
9 ;; Klaus Berndl <klaus.berndl@sdm.de>
10 ;; Kevin A. Burton <burton@openprivacy.org>
11 ;; Maintainer: Klaus Berndl <klaus.berndl@sdm.de>
12 ;; Kevin A. Burton <burton@openprivacy.org>
13 ;; Keywords: browser, code, programming, tools
16 ;; This program is free software; you can redistribute it and/or modify it under
17 ;; the terms of the GNU General Public License as published by the Free Software
18 ;; Foundation; either version 2, or (at your option) any later version.
20 ;; This program is distributed in the hope that it will be useful, but WITHOUT
21 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22 ;; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
25 ;; You should have received a copy of the GNU General Public License along with
26 ;; GNU Emacs; see the file COPYING. If not, write to the Free Software
27 ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 ;; $Id: ecb-navigate.el,v 1.22 2005/02/28 11:31:55 berndl Exp $
35 ;; For the ChangeLog of this file see the CVS-repository. For a complete
36 ;; history of the ECB-package see the file NEWS.
42 (require 'silentcomp
))
47 ;;====================================================
49 ;;====================================================
51 (defclass ecb-dlist-node
()
52 ((previous :initform nil
); :protection :private)
53 (next :initform nil
); :protection :private)
54 (data :initarg
:data
:initform nil
); :protection :private)
56 "A node in a double linked list."
59 (defun ecb-dlist-node-new (data)
60 (ecb-dlist-node "node" :data data
))
62 (defmethod ecb-get-data ((node ecb-dlist-node
))
65 (defmethod ecb-get-next ((node ecb-dlist-node
))
68 (defmethod ecb-get-previous ((node ecb-dlist-node
))
71 (defmethod ecb-set-data ((node ecb-dlist-node
) data
)
72 (oset node data data
))
74 (defmethod ecb-set-next ((node ecb-dlist-node
) next
)
75 (let ((old-next (ecb-get-next node
)))
77 (oset old-next previous nil
))
80 (ecb-set-previous next nil
)
81 (oset next previous node
))))
83 (defmethod ecb-set-previous ((node ecb-dlist-node
) previous
)
84 (let ((old-previous (ecb-get-previous node
)))
86 (oset old-previous next nil
))
87 (oset node previous previous
)
89 (ecb-set-next previous nil
)
90 (oset previous next node
))))
93 ;;====================================================
95 ;;====================================================
97 (defclass ecb-nav-history-item
()
98 ((pos :initarg
:pos
:initform
0); :protection :private)
99 (window-start :initarg
:window-start
:initform
0); :protection :private)
103 (defmethod ecb-nav-set-pos ((item ecb-nav-history-item
) pos
)
106 (defmethod ecb-nav-set-window-start ((item ecb-nav-history-item
) point
)
107 (oset item window-start point
))
109 (defmethod ecb-nav-get-pos ((item ecb-nav-history-item
))
112 (defmethod ecb-nav-get-window-start ((item ecb-nav-history-item
))
113 (oref item window-start
))
115 (defmethod ecb-nav-to-string ((item ecb-nav-history-item
))
116 (concat (int-to-string (ecb-nav-get-pos item
)) ":"
117 (int-to-string (ecb-nav-get-window-start item
))))
119 ;; This method must return nil if saving can not be performed and otherwise
121 (defmethod ecb-nav-save ((item ecb-nav-history-item
))
124 (defmethod ecb-nav-is-valid ((item ecb-nav-history-item
))
128 ;;====================================================
130 ;;====================================================
132 ;; Klaus Berndl <klaus.berndl@sdm.de>: Changed this class from storing the
133 ;; whole tag to storing explicitly the tag-buffer, the marker of the
134 ;; tag-start, the marker of the tag-end. This prevents the stored
135 ;; navigation-items from getting invalid and unusable after a full
136 ;; semantic-reparse because such a reparse makes the overlays contained in the
137 ;; stored tags invalid so we can not uses their informations.
138 (defclass ecb-nav-tag-history-item
(ecb-nav-history-item)
139 ((tag-buffer :initarg
:tag-buffer
:initform nil
); :protection :private)
140 (tag-start :initarg
:tag-start
:initform nil
) ; :protection :private)
141 (tag-end :initarg
:tag-end
:initform nil
) ; :protection :private)
142 (tag-name :initarg
:tag-name
:initform nil
) ; :protection :private)
143 (narrow :initarg
:narrow
:initform nil
); :protection :private)
147 (defun ecb-nav-tag-history-item-new (tag-name tag-buffer tag-start
148 tag-end
&optional narrow
)
149 (ecb-nav-tag-history-item tag-name
150 :tag-buffer tag-buffer
156 (defmethod ecb-nav-get-tag-buffer ((item ecb-nav-tag-history-item
))
157 (oref item tag-buffer
))
159 (defmethod ecb-nav-get-tag-start ((item ecb-nav-tag-history-item
))
160 (oref item tag-start
))
162 (defmethod ecb-nav-get-tag-end ((item ecb-nav-tag-history-item
))
165 (defmethod ecb-nav-get-tag-name ((item ecb-nav-tag-history-item
))
166 (oref item tag-name
))
168 (defmethod ecb-nav-get-narrow ((item ecb-nav-tag-history-item
))
171 (defmethod ecb-nav-goto ((item ecb-nav-tag-history-item
))
172 (let ((tag-buffer (ecb-nav-get-tag-buffer item
))
173 (tag-start (ecb-nav-get-tag-start item
))
174 (tag-end (ecb-nav-get-tag-end item
)))
175 (set-window-buffer (selected-window) tag-buffer
)
177 (goto-char tag-start
)
178 (when (ecb-nav-get-narrow item
)
179 (narrow-to-region (ecb-line-beginning-pos) tag-end
))
180 (goto-char (+ tag-start
(ecb-nav-get-pos item
)))
181 (set-window-start (selected-window)
182 (+ tag-start
(ecb-nav-get-window-start item
)))))
184 (defmethod ecb-nav-save ((item ecb-nav-tag-history-item
))
185 "Return only nil if tag-start of ITEM points into a dead buffer. In this
186 case no position saving is done."
187 (let ((tag-start (ecb-nav-get-tag-start item
)))
188 (if (and tag-start
(marker-buffer tag-start
))
190 (ecb-nav-set-pos item
(- (point) tag-start
))
191 (ecb-nav-set-window-start item
(- (window-start) tag-start
))
195 (defmethod ecb-nav-to-string ((item ecb-nav-tag-history-item
))
196 (concat (ecb-nav-get-tag-name item
) ":" (call-next-method)))
198 (defmethod ecb-nav-is-valid ((item ecb-nav-tag-history-item
))
199 (let ((tag-start (ecb-nav-get-tag-start item
))
200 (tag-buf (ecb-nav-get-tag-buffer item
))
201 (tag-end (ecb-nav-get-tag-end item
)))
202 (if (and tag-start
(marker-buffer tag-start
)
203 tag-end
(marker-buffer tag-end
)
204 tag-buf
(buffer-live-p tag-buf
))
208 ;;====================================================
210 ;;====================================================
212 (defclass ecb-nav-file-history-item
(ecb-nav-history-item)
213 ((file :initarg
:file
:initform
""); :protection :private)
217 (defun ecb-nav-file-history-item-new ()
218 (let ((item (ecb-nav-file-history-item (buffer-file-name)
219 :file
(buffer-file-name))))
220 (ecb-nav-set-pos item
(point))
221 (ecb-nav-set-window-start item
222 (window-start (get-buffer-window (current-buffer))))
225 (defmethod ecb-nav-get-file ((item ecb-nav-file-history-item
))
228 (defmethod ecb-nav-set-file ((item ecb-nav-file-history-item
) file
)
229 (oset item file file
))
231 (defmethod ecb-nav-save ((item ecb-nav-file-history-item
))
232 (ecb-nav-set-pos item
(point))
233 (ecb-nav-set-window-start item
(window-start))
234 (ecb-nav-set-file item
(buffer-file-name))
237 (defmethod ecb-nav-goto ((item ecb-nav-file-history-item
))
238 (find-file (ecb-nav-get-file item
))
240 (goto-char (ecb-nav-get-pos item
))
241 (set-window-start (selected-window) (ecb-nav-get-window-start item
)))
243 (defmethod ecb-nav-to-string ((item ecb-nav-file-history-item
))
244 (concat (ecb-nav-get-file item
) ":" (call-next-method)))
246 (defmethod ecb-nav-is-valid ((item ecb-nav-file-history-item
))
249 ;;====================================================
251 ;;====================================================
253 (defvar ecb-nav-first-node nil
)
254 (setq ecb-nav-first-node
(ecb-dlist-node-new (ecb-nav-history-item "First item")))
256 (defvar ecb-nav-current-node nil
)
257 (setq ecb-nav-current-node ecb-nav-first-node
)
260 (defun ecb-nav-initialize ()
261 (setq ecb-nav-first-node
262 (ecb-dlist-node-new (ecb-nav-history-item "First item")))
263 (setq ecb-nav-current-node ecb-nav-first-node
))
266 (defun ecb-nav-jump-to-tag (file tag
&optional narrow
)
267 (ecb-nav-save-current)
269 (ecb-nav-add-item (ecb-nav-tag-history-item tag narrow
)))
271 (defun ecb-nav-jump-to-file (file)
272 (ecb-nav-save-current)
274 (ecb-nav-add-item (ecb-nav-file-history-item file
)))
276 (defun ecb-nav-add-item (item)
277 (let ((node (ecb-dlist-node-new item
)))
278 (ecb-set-next node
(ecb-get-next ecb-nav-current-node
))
279 (ecb-set-next ecb-nav-current-node node
)
280 (setq ecb-nav-current-node node
)))
282 (defun ecb-nav-remove-current-node ()
283 (ecb-nav-remove-node ecb-nav-current-node
))
285 (defun ecb-nav-remove-node (node)
286 "Remove NODE and set `ecb-nav-first-node' and `ecb-nav-current-node' if
288 (let ((prev (ecb-get-previous node
))
289 (next (ecb-get-next node
)))
291 (ecb-set-next prev
(ecb-get-next node
)))
293 (ecb-set-previous next
(ecb-get-previous node
)))
294 (if (eq node ecb-nav-current-node
)
295 (setq ecb-nav-current-node
(or prev
297 ecb-nav-first-node
)))
298 (if (eq node ecb-nav-first-node
)
300 (setq ecb-nav-first-node next
)
301 (ecb-nav-initialize)))))
303 (defun ecb-nav-remove-invalid-nodes ()
304 (let ((node ecb-nav-first-node
)
307 (setq next-node
(ecb-get-next node
))
308 (if (not (ecb-nav-is-valid (ecb-get-data node
)))
309 (ecb-nav-remove-node node
))
310 (setq node next-node
))))
312 (defun ecb-nav-save-current ()
313 (while (not (ecb-nav-save (ecb-get-data ecb-nav-current-node
)))
314 (ecb-nav-remove-current-node)))
316 (defun ecb-nav-goto-next ()
317 "Go forward in the navigation history list."
319 (ecb-nav-goto--internal (ecb-get-next ecb-nav-current-node
)))
321 (defun ecb-nav-goto-previous ()
322 "Go back in the navigation history list."
324 (ecb-nav-goto--internal (ecb-get-previous ecb-nav-current-node
)))
326 (defun ecb-nav-dump-history ()
328 (ecb-nav-remove-invalid-nodes)
329 (ecb-nav-dump-history--internal ecb-nav-first-node
))
331 (defun ecb-nav-dump-history--internal (node)
333 (insert (ecb-nav-to-string (ecb-get-data node
)) "\n")
334 (ecb-nav-dump-history--internal (ecb-get-next node
))))
336 (defun ecb-nav-goto--internal (node)
337 (if (or (not node
) (eq ecb-nav-first-node node
))
338 (message "No more valid history items!")
339 ;; before doing something we have to clear the history from now invalid
340 ;; nodes means removing nodes which does not point into a live buffer
341 (ecb-nav-remove-invalid-nodes)
342 (ecb-nav-save-current)
343 (setq ecb-nav-current-node node
)
344 (ecb-nav-goto (ecb-get-data node
))))
347 (silentcomp-provide 'ecb-navigate
)
349 ;;; ecb-navigate.el ends here