Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit; currently fairly hackish, but functional for browsing…

… with optional context for etags only. Still to come of course, support for gtags, and manipulation of the tags structure. Also, autodetection of which we should be using.
  • Loading branch information...
commit 9cf92b46478f220636c893ecdb0ee3cc65c1198f 0 parents
Mark Hepburn authored
Showing with 186 additions and 0 deletions.
  1. +186 −0 tags-view.el
186 tags-view.el
@@ -0,0 +1,186 @@
+;;; tags-view.el --- Display and navigate tags browsing history.
+
+;; Copyright (C) 2009 Mark Hepburn
+
+;; Author: Mark Hepburn <Mark.Hepburn@gmail.com>
+;; Keywords: extensions, tools, convenience, files
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Functionality to supplement the different tags operations, usually
+;;; bound to M-./M-* Currently supports etags.el and gtags.el; any
+;;; others?
+
+;;; As you navigate through a source tree it can become easy to forget
+;;; how you got to your current location -- you could call M-*
+;;; repeatedly to pop back up the stack, but this would lose your
+;;; current location. This module allows you to view the path taken,
+;;; and if desired to jump immediately back to any intermediate
+;;; location.
+
+;;; I don't think this exists, but I haven't looked too hard -- I'd
+;;; like the practice of writing something to completion for emacs for
+;;; once!
+
+;;; Code:
+
+;;; etags.el. Locations are in global variable `tags-location-ring',
+;;; a ring data structure.
+
+(require 'cl)
+
+(defvar tv-separator-string "----"
+ "Text used to separate entries in the browser window. May be nil.")
+
+(defvar tv-context-lines 0
+ "The number of preceding and following lines to include around
+ each location displayed.")
+
+(defface tv-header-face
+ '((t (:foreground "gray" :weight 'light)))
+ "Face used to display the header of each tag entry.")
+
+(defun tv-view-history ()
+ (interactive)
+ (let ((buf (get-buffer-create "*tags history*")))
+ (pop-to-buffer buf)
+ (setq buffer-read-only nil)
+ (let ((inhibit-read-only t))
+ (erase-buffer))
+ (tags-history-mode)
+ (let ((tag-items (copy-list (ring-elements tags-location-ring))))
+ (tv-insert-items tag-items))
+ (setq buffer-read-only t)
+ (goto-char 0)))
+
+(defun tv-what-line (marker)
+ "Return the line number of a marker"
+ (save-current-buffer
+ (set-buffer (marker-buffer marker))
+ (line-number-at-pos (marker-position marker))))
+
+(defun tv-insert-items (items)
+ "Insert the formatted list of tags with context"
+ (if items
+ (progn
+ (tv-insert-single-item (car items))
+ (if (cdr items)
+ (progn
+ (if tv-separator-string
+ (progn
+ (insert tv-separator-string)
+ (insert "\n")))
+ (tv-insert-items (cdr items)))))))
+
+(defun tv-insert-single-item (marker)
+ "Insert a single formatted item, including overlays etc.
+Argument is a marker that will be displayed, along with
+`tv-context-lines' of context, if non-zero."
+ (let ((beg (point)))
+ (insert (propertize (format "Buffer %s, line %d:\n"
+ (buffer-name (marker-buffer marker))
+ (tv-what-line marker))
+ 'face 'tv-header-face))
+ (insert (tv-get-lines-with-context marker tv-context-lines))
+ (insert "\n")
+ (let* ((o (make-overlay beg (point))))
+ (overlay-put o 'mouse-face 'highlight))))
+
+(defun tv-get-lines-with-context (marker &optional num-context)
+ "Grabs the line at the specified marker; if optional
+ num-context is specified, it will also grab that number of
+ preceding and following lines, assuming sufficient lines exist.
+ For example, if 2 context lines are specified, a total of 5
+ lines wil lbe returned: 2 preceding, the line the marker is
+ located on, and 2 following lines. If not enough context lines
+ exist in either direction, as many as possible will be used."
+ (unless num-context (setq num-context 0))
+ (if (< num-context 0) (setq (num-context (- num-context))))
+ (save-current-buffer
+ (set-buffer (marker-buffer marker))
+ (let (start end)
+ (goto-char (marker-position marker))
+ (forward-line (- num-context))
+ (setq start (point))
+ (goto-char (marker-position marker))
+ (forward-line num-context)
+ (end-of-line)
+ (setq end (point))
+ (buffer-substring start end))))
+
+;;; to implement; different methods of operating on the current selection:
+(defun tv-display-tag-other-window ())
+(defun tv-jump-to-tag-and-quit ())
+(defun tv-clear-tag-at-point ())
+
+;;; Navigation:
+(defun tv-next-tag (&optional arg)
+ "Move point forward to the next tag. Optional numeric argument
+ moves forward that many tags."
+ (interactive "p")
+ (beginning-of-line)
+ (while (not (zerop arg))
+ (if (> arg 0)
+ (progn
+ (decf arg)
+ (if (overlays-at (point))
+ (progn
+ (goto-char (overlay-end (car (overlays-at (point)))))
+ (goto-char (next-overlay-change (point))))
+ (goto-char (next-overlay-change (point)))
+ (unless (eobp)
+ (goto-char (overlay-start (car (overlays-at (point))))))))
+ (progn
+ (incf arg)
+ (if (overlays-at (point))
+ (progn
+ (goto-char (overlay-start (car (overlays-at (point)))))
+ (goto-char (previous-overlay-change (point)))
+ (goto-char (previous-overlay-change (point))))
+ (progn
+ (goto-char (previous-overlay-change (point)))
+ (unless (bobp)
+ (goto-char (overlay-start (car (overlays-at (point))))))))))))
+
+(defun tv-previous-tag (&optional arg)
+ "Move point backwards to the previous tag. Optional numeric
+ argument moves backwards that many tags."
+ (interactive "p")
+ (tv-next-tag (- arg)))
+
+;;; major mode for displaying the history:
+(define-derived-mode tags-history-mode
+ nil "Tags-History"
+ "View history of tags locations, with the most recent on the top.
+
+\\{tags-history-mode-map}"
+ (let ((km tags-history-mode-map))
+ ;; first, clear all other bindings:
+ (suppress-keymap km)
+
+ ;; navigation:
+ (define-key km "n" 'tv-next-tag)
+ (define-key km "\C-n" 'tv-next-tag)
+ (define-key km "j" 'tv-next-tag)
+
+ (define-key km "p" 'tv-previous-tag)
+ (define-key km "\C-p" 'tv-previous-tag)
+ (define-key km "k" 'tv-previous-tag)
+
+ ;; cleanup:
+ (define-key km "q" 'delete-window)))
+
+(provide 'tags-view)
Please sign in to comment.
Something went wrong with that request. Please try again.