;;; mudela-mode.el --- Major mode for editing Mudela programs


;; Copyright (C) 1992,1993,1994  Tim Peters

;; Author: 1997: Han-Wen Nienhuys
;; Author: 1995-1996 Barry A. Warsaw
;;         1992-1994 Tim Peters
;; Created:       Feb 1992
;; Version:       0.0
;; Last Modified: 12SEP97
;; Keywords: mudela languages music

;; This software is provided as-is, without express or implied
;; warranty.  Permission to use, copy, modify, distribute or sell this
;; software, without fee, for any purpose and by any individual or
;; organization, is hereby granted, provided that the above copyright
;; notice and this paragraph appear in all copies.



;; Kyrie Eleison; it is my first real Elisp file
;; This is a cannabalised version of python-mode.el (HWN)
;;
;; TODO: 
;; * should handle block comments too.
;; * handle lexer modes (\header, \melodic, \lyric) etc.
;; * indentation
;; * notenames?
;; * fontlock: \melodic \melodic
;; 

(defconst mudela-font-lock-keywords
  (let* ((keywords '("spanrequest" "simultaneous" "sequential" "accepts"
		     "alternative" "bar" "breathe"
		     "cadenza" "chordmodifiers" "chords" "clef" "cm" "consists"
		     "consistsend" "context"
		     "duration" "font" "grace" "header" "in" "lyrics"
		     "key" "keysignature" "mark" "musicalpitch"
		     "time" "times" "midi" "mm" "name" "notenames"
		     "notes" "partial" "paper" "penalty" "property" "pt"
		     "relative" "remove" "repeat" "repetitions" "addlyrics"
		     "scm" "scmfile" "score" "script"
		     "shape" "skip" "textscript" "tempo" "translator" "transpose"
		     "type" "version" 
		     ))
       (kwregex (mapconcat (lambda (x) (concat "\\\\" x))  keywords "\\|")))

    (list 
      (concat ".\\(" kwregex "\\)[^a-zA-Z]")
      (concat "^\\(" kwregex "\\)[^a-zA-Z]")
      '(".\\(\\\\[a-zA-Z][a-zA-Z]*\\)" 1 font-lock-variable-name-face)
      '("^[\t ]*\\([a-zA-Z][_a-zA-Z]*\\) *=" 1 font-lock-variable-name-face)     
    ))
  "Additional expressions to highlight in Mudela mode.")

;; define a mode-specific abbrev table for those who use such things
(defvar mudela-mode-abbrev-table nil
  "Abbrev table in use in `mudela-mode' buffers.")

(define-abbrev-table 'mudela-mode-abbrev-table nil)

(defvar mudela-mode-hook nil
  "*Hook called by `mudela-mode'.")

(defvar mu-mode-map ()
  "Keymap used in `mudela-mode' buffers.")

(defun mu-newline-and-indent ()
  (interactive)
  (newline)
  (indent-relative-maybe)
  "Newline and copy previous indentation")

(if mu-mode-map
    ()
  (setq mu-mode-map (make-sparse-keymap))

  (mapcar (function (lambda (key)
		      (define-key
			mu-mode-map key 'mu-newline-and-indent)))
   (where-is-internal 'newline-and-indent))

  (mapcar (function
	   (lambda (x)
	     (define-key mu-mode-map (car x) (cdr x))))
	  '(("\C-c\C-c"  . mu-foo-bar)
	    ))
  ;; should do all keybindings this way
  (define-key mu-mode-map [RET] 'mu-newline-and-indent)
  ) 

(defvar mu-mode-syntax-table nil
  "Syntax table used in `mudela-mode' buffers.")

;;
(if mu-mode-syntax-table
    ()
  (setq mu-mode-syntax-table (make-syntax-table))
  (mapcar (function
	   (lambda (x) (modify-syntax-entry
			(car x) (cdr x) mu-mode-syntax-table)))
	  '(( ?\( . "." ) ( ?\) . "." )
	    ( ?\[ . "." ) ( ?\] . "." )
	    ( ?\{ . "(}" ) ( ?\} . "){" )
	    ( ?\< . "(>" )( ?\> . ")>") 
	    ( ?\$ . "." ) ( ?\% . "." ) ( ?\& . "." )
	    ( ?\* . "." ) ( ?\+ . "." ) ( ?\- . "." )
	    ( ?\/ . "." )  ( ?\= . "." )
	    ( ?\| . "." ) (?\\ . "\\" )
	    ( ?\_ . "." )	
	    ( ?\' . "w")	
	    ( ?\" . "\"" )
	    ( ?\% . "<")
	    ( ?\n . ">")

; FIXME
;	    ( ?%  .  ". 124b" )
;	    ( ?{  .  ". 23" )
	    ))

  )	

(defconst mu-blank-or-comment-re "[ \t]*\\($\\|%\\)"
  "Regexp matching blank or comment lines.")

(defconst mu-imenu-generic-re "^\\([a-zA-Z_][a-zA-Z0-9_]*\\) *="
  "Regexp matching Identifier definitions.")

;; Sadly we need this for a macro in Emacs 19.
(eval-when-compile
  ;; Imenu isn't used in XEmacs, so just ignore load errors.
  (condition-case ()
      (require 'imenu)
    (error nil)))

(defvar mu-imenu-generic-expression
  (list (list nil mu-imenu-generic-re 1))
  "Expression for imenu")

(defun mudela-mode ()
  "Major mode for editing Mudela files."

  (interactive)
  ;; set up local variables
  (kill-all-local-variables)
  (make-local-variable 'font-lock-defaults)
  (make-local-variable 'paragraph-separate)
  (make-local-variable 'paragraph-start)
  (make-local-variable 'require-final-newline)
  (make-local-variable 'comment-start)
  (make-local-variable 'block-comment-start)
  (make-local-variable 'block-comment-end)  

  (setq comment-end "\n"
	comment-start          "%"
	comment-start-skip     "%{? *"
	block-comment-start	"%{"
	block-comment-end	"%}"	
	)
  (make-local-variable 'comment-end)
  (make-local-variable 'comment-start-skip)
  (setq comment-start-skip "%{")	;??
  (make-local-variable 'comment-column)
  (make-local-variable 'imenu-generic-expression)
  (setq imenu-generic-expression mu-imenu-generic-expression)
  (make-local-variable 'indent-line-function)
 
  ;;
  (set-syntax-table mu-mode-syntax-table)
  (setq major-mode             'mudela-mode
	mode-name              "Mudela"
	local-abbrev-table     mudela-mode-abbrev-table
	font-lock-defaults     '(mudela-font-lock-keywords)
	paragraph-separate     "^[ \t]*$"
	paragraph-start        "^[ \t]*$"
	require-final-newline  t
	comment-column         40
	indent-line-function	'indent-relative-maybe
	)
  (use-local-map mu-mode-map)

  ;; run the mode hook. mu-mode-hook use is deprecated
  (run-hooks 'mudela-mode-hook)
)


(defun mu-keep-region-active ()
  ;; do whatever is necessary to keep the region active in XEmacs.
  ;; Ignore byte-compiler warnings you might see.  Also note that
  ;; FSF's Emacs 19 does it differently and doesn't its policy doesn't
  ;; require us to take explicit action.
  (and (boundp 'zmacs-region-stays)
       (setq zmacs-region-stays t)))


(defun mu-comment-region (beg end &optional arg)
  "Like `comment-region' but uses double hash (`#') comment starter."
  (interactive "r\nP")
  (let ((comment-start mu-block-comment-prefix))
    (comment-region beg end arg)))

(defconst mu-version "0.0.1"
  "`mudela-mode' version number.")
(defconst mu-help-address "hanwen@cs.uu.nl"
  "Address accepting submission of bug reports.")

(defun mu-version ()
  "Echo the current version of `mudela-mode' in the minibuffer."
  (interactive)
  (message "Using `mudela-mode' version %s" mu-version)
  (mu-keep-region-active))

(provide 'mu-mode)
;;; mudela-mode.el ends here
