adamc@350: ;;; urweb-util.el --- Utility functions for urweb-mode
adamc@350: 
adamc@350: ;; Based on sml-mode:
adamc@350: ;; Copyright (C) 1999-2000  Stefan Monnier <monnier@cs.yale.edu>
adamc@350: ;;
adamc@350: ;; Modified for urweb-mode:
adamc@350: ;; Copyright (C) 2008  Adam Chlipala <adamc@hcoop.net>
adamc@350: ;;
adamc@350: ;; This program is free software; you can redistribute it and/or modify
adamc@350: ;; it under the terms of the GNU General Public License as published by
adamc@350: ;; the Free Software Foundation; either version 2 of the License, or
adamc@350: ;; (at your option) any later version.
adamc@350: ;;
adamc@350: ;; This program is distributed in the hope that it will be useful,
adamc@350: ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
adamc@350: ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
adamc@350: ;; GNU General Public License for more details.
adamc@350: ;;
adamc@350: ;; You should have received a copy of the GNU General Public License
adamc@350: ;; along with this program; if not, write to the Free Software
adamc@350: ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
adamc@350: 
adamc@350: 
adamc@350: ;;; Commentary:
adamc@350: 
adamc@350: ;;; Code:
adamc@350: 
adamc@350: (require 'cl)				;for `reduce'
adamc@350: (require 'urweb-compat)
adamc@350: 
adamc@350: ;;
adamc@350: 
adamc@350: (defun flatten (ls &optional acc)
adamc@350:   (if (null ls) acc
adamc@350:     (let ((rest (flatten (cdr ls) acc))
adamc@350: 	  (head (car ls)))
adamc@350:       (if (listp head)
adamc@350: 	  (flatten head rest)
adamc@350: 	(cons head rest)))))
adamc@350: 
adamc@350: (defun urweb-preproc-alist (al)
adamc@350:   "Expand an alist AL where keys can be lists of keys into a normal one."
adamc@350:   (reduce (lambda (x al)
adamc@350: 	    (let ((k (car x))
adamc@350: 		  (v (cdr x)))
adamc@350: 	      (if (consp k)
adamc@350: 		  (append (mapcar (lambda (y) (cons y v)) k) al)
adamc@350: 		(cons x al))))
adamc@350: 	  al
adamc@350: 	  :initial-value nil
adamc@350: 	  :from-end t))
adamc@350: 
adamc@350: ;;; 
adamc@350: ;;; defmap
adamc@350: ;;; 
adamc@350: 
adamc@350: (defun custom-create-map (m bs args)
adamc@350:   (let (inherit dense suppress)
adamc@350:     (while args
adamc@350:       (let ((key (first args))
adamc@350: 	    (val (second args)))
adamc@350: 	(cond
adamc@350: 	 ((eq key :dense) (setq dense val))
adamc@350: 	 ((eq key :inherit) (setq inherit val))
adamc@350: 	 ((eq key :group) )
adamc@350: 	 ;;((eq key :suppress) (setq suppress val))
adamc@350: 	 (t (message "Uknown argument %s in defmap" key))))
adamc@350:       (setq args (cddr args)))
adamc@350:     (unless (keymapp m)
adamc@350:       (setq bs (append m bs))
adamc@350:       (setq m (if dense (make-keymap) (make-sparse-keymap))))
adamc@350:     (dolist (b bs)
adamc@350:       (let ((keys (car b))
adamc@350: 	    (binding (cdr b)))
adamc@350: 	(dolist (key (if (consp keys) keys (list keys)))
adamc@350: 	  (cond
adamc@350: 	   ((symbolp key)
adamc@350: 	    (substitute-key-definition key binding m global-map))
adamc@350: 	   ((null binding)
adamc@350: 	    (unless (keymapp (lookup-key m key)) (define-key m key binding)))
adamc@350: 	   ((let ((o (lookup-key m key)))
adamc@350: 	      (or (null o) (numberp o) (eq o 'undefined)))
adamc@350: 	    (define-key m key binding))))))
adamc@350:     (cond
adamc@350:      ((keymapp inherit) (set-keymap-parent m inherit))
adamc@350:      ((consp inherit) (set-keymap-parents m inherit)))
adamc@350:     m))
adamc@350: 
adamc@350: (defmacro defmap (m bs doc &rest args)
adamc@350:   `(defconst ,m
adamc@350:      (custom-create-map (if (boundp ',m) ,m) ,bs ,(cons 'list args))
adamc@350:      ,doc))
adamc@350: 
adamc@350: ;; defsyntax ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
adamc@350: 
adamc@350: (defun custom-create-syntax (css args)
adamc@350:   (let ((st (make-syntax-table (cadr (memq :copy args)))))
adamc@350:     (dolist (cs css)
adamc@350:       (let ((char (car cs))
adamc@350: 	    (syntax (cdr cs)))
adamc@350: 	(if (sequencep char)
adamc@350: 	    (mapcar* (lambda (c) (modify-syntax-entry c syntax st)) char)
adamc@350: 	  (modify-syntax-entry char syntax st))))
adamc@350:     st))
adamc@350: 
adamc@350: (defmacro defsyntax (st css doc &rest args)
adamc@350:   `(defconst ,st (custom-create-syntax ,css ,(cons 'list args)) ,doc))
adamc@350: 
adamc@350: ;;;; 
adamc@350: ;;;; Compatibility info
adamc@350: ;;;; 
adamc@350: 
adamc@350: (defvar urweb-builtin-nested-comments-flag
adamc@350:   (ignore-errors
adamc@350:     (not (equal (let ((st (make-syntax-table)))
adamc@350: 		  (modify-syntax-entry ?\* ". 23n" st) st)
adamc@350: 		(let ((st (make-syntax-table)))
adamc@350: 		  (modify-syntax-entry ?\* ". 23" st) st))))
adamc@350:   "Non-nil means this Emacs understands the `n' in syntax entries.")
adamc@350: 
adamc@350: (provide 'urweb-util)
adamc@350: 
adamc@350: ;;; urweb-util.el ends here