Path: lib/frontends/augment.el
Last Update: Sat Nov 03 15:29:52 -0400 2007

;;; augment.el — Display metadata about code

;; Copyright (C) 2007 Phil Hagelberg

;; Author: Phil Hagelberg <> ;; Created: 16 Oct 2007 ;; Version: 0.1 ;; Keywords: augment testing metadata

;; This file is NOT part of GNU Emacs.

;; This 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, or (at your option) any later ;; version.

;; This file 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 Emacs; see the file COPYING, or type `C-h C-c’. If not, ;; write to the Free Software Foundation at this address:

;; Free Software Foundation ;; 51 Franklin Street, Fifth Floor ;; Boston, MA 02110-1301 ;; USA

;;; Commentary:

;; augment.el is a frontend for augment, a system for gathering and ;; displaying metadata about code. It‘s a minor mode for displaying ;; data that‘s been gathered and for initiating new augmentations.

;; Tests are present in spec/emacs-frontend-test.el

;;; Installation:

;; Put this file on your load-path and add "(require ‘augment)" to ;; your .emacs file.

;;; Todo:

;; * Support overlapping layers

;;; Code:

(require ‘cl) (require ‘json) ;; See hober‘s

(defstruct layer begin end color message backend)

(setq augment-debug t)


(defun augment-layer-from-plist (plist)

  "Make a layers struct from a plist."
  (make-layer :begin (string-to-number (first (split-string (getf plist :range) "\\.")))
              :end (string-to-number (cadddr (split-string (getf plist :range) "\\.")))
              :color (getf plist :color)
              :message (getf plist :message)))

(defun augment-render-layer (layer)

  "Create an overlay for a layer." ;; needs to be reimplemented for xemacs
  (overlay-put (make-overlay (layer-begin layer) (layer-end layer))
               'face (layer-face layer)))

(defun layer-face (layer)

  ;; could do some kind of transformation here for color themes.
  (cons 'background-color (layer-color layer)))

(defun augment-file-path (file)

   (file-name-directory file) ".augment/"
   (file-name-nondirectory file)))

(defun augment-show-message (&optional point)

  ;; find the first layer that the point is between begin and end
  (layer-message (find (or point (point)) layers :test
                       (lambda (p l) (and (> p (layer-begin l))
                                     (< p (layer-end l)))))))


(define-minor-mode augment-mode

  "Major mode for showing code metadata.


  :keymap (setq augment-mode-map (make-sparse-keymap))

  (define-key augment-mode-map (kbd "C-c C-s") 'augment-initiate)
  (define-key augment-mode-map (kbd "C-c C-k") 'augment-clear)
  (define-key augment-mode-map (kbd "C-c C-i") 'augment-show-message)

  (make-local-variable 'layers)

  (make-local-variable 'after-save-hook)
  (add-hook 'after-save-hook 'augment-initiate)

  (augment-initiate (buffer-file-name)))

(defun augment-initiate (&optional file)

  (setq layers nil)
  (setq in (concat (or file
                       (expand-file-name (buffer-file-name)))

  (process-send-string "augment" (concat (or file
                                             (expand-file-name (buffer-file-name)))

(defun augment-start-process ()

  (unless (get-process "augment") ;; only one should be running at a time
     (start-process "augment" "*augment-out*"
                    "augment" "--interactive")

(defun augment-filter (process output)

  (setq out output)

;; (if augment-debug (with-current-buffer "*augment-debug*" ;; (insert output)))

  (if (string-match "^Error augmenting \\(.*\\)\\." output)
      (error "Error augmenting %s." (match-string 1 output))
    ;; layers need to be cached in local var for messages
    (let* ((json-object-type 'plist)
           (json-array-type 'list)
           (all-layers (json-read-from-string output)))
      (while all-layers
        ;; gotta remove the colon from the plisted filename
        (let ((filename (substring (symbol-name (pop all-layers)) 1 nil))
              (layer-plists (pop all-layers)))
          (with-current-buffer (file-name-nondirectory filename)
            (setq layers (mapcar #'augment-layer-from-plist layer-plists))
            (augment-buffer layers)))))))

(defun augment-buffer (layers)

  (dolist (layer layers)
    (augment-render-layer layer)))

(defun augment-clear ()


(defun augment-reset ()

  (if (get-process "augment")
    (kill-process "augment"))

(provide ‘augment) ;;; augment.el ends here