;;; corewars-mode.el --- Major mode for Corewars source code

;; Time-stamp: <00/04/02 17:00:01 airborne>
;; Copyright (C) Kris Verbeeck
;; License: GPL

;; Author: <kris.verbeeck@advalvas.be>
;; Created: 2000/03/31
;; Version: 0.0.1
;; Keywords: corewars, mode, syntax highlighting, indentation

;; This file is not part of GNU Emacs

;;; Description:
;;; ------------

;; A mojor mode for editing Corewars code files.  It provides
;; syntax highlighting and indentation.  This move has only been
;; tested with XEmacs 21.1.  Let me know if you have any 
;; difficulties using it with Emacs or an other version of XEmacs.

;;; Installation instructions:
;;; --------------------------

;; To install the corewars-mode put the following lines into your 
;; ~/.emacs file:
;;
;;   ;; Corewars mode
;;   ;; =============
;;   (setq load-path (cons "<path>" load-path))
;;   (autoload 'corewars-mode "corewars-mode" 
;;     "Major mode to edit CoreWars source files." t)
;;   (setq auto-mode-alist
;;         (append '(("\\.cw$" . corewars-mode)) 
;;                 auto-mode-alist))
;;
;; In this piece of code <path> has to be set to the correct path.  
;; If you install this file in "/home/user1/elisp/" then that path 
;; has to be stated.
;; The last line enables corewars-mode whenever a file with extension
;; ".cw" is opened.

;;; Configuration instructions:
;;; ---------------------------

;; You can change the two values for the indentation columns below.
;; Lateron this will be changed to some appropriate customization
;; definitions.

;;; Usage instructions:
;;; -------------------

;; Just enter your code, turn on syntax highlighting and use tab
;; to indent the lines.

;;; Change Log:
;;; -----------

;; v0.0.1 2000/04/02 First public release

;;; To do:
;;; ------

;; - Test with Emacs (only tested with XEmacs now)
;; - A syntax table
;; - Redcode features
;; - Menus
;; - Other fancy stuff

;;; Known bugs:
;;; -----------

;; none

;;; Code:
;;; -----

;; Required/provided features

(provide 'corewars-mode)

;;
;; -=[ Indentation columns ]=-
;;

; A corewars line:
; <label>: <keyword> <operand1>[,<operand2>] [# <comment>]
(defvar corewars-keyword-column 15
  "Indentation column for the keyword.")
(defvar corewars-comment-column 40
  "Indentation column for the comment.")

;;
;; -=[ Fontification definitions for Corewars code ]=-
;;
(defvar corewars-font-lock-keywords
  (list
   ;; Comments
   '("#.*" (0 font-lock-comment-face))

   ;; Strings
   '("\".*\"" (0 font-lock-doc-string-face))
                                        
   ;; Labels
   '("^\\(.*\\):" (1 font-lock-function-name-face))
   
   ;; Keywords
   '("[^a-zA-Z0-9]\\(title\\|author\\|data\\|movei\\|move\\|add\\|neg\\|mul\\|div\\|mod\\|and\\|not\\|equal\\|less\\|jump\\|fork\\|info\\|system\\|own\\|loop\\)[^a-zA-Z0-9]"
     (0 font-lock-keyword-face))

   ;; Label references
   '("[a-zA-Z][a-zA-Z0-9]*" (0 font-lock-reference-face))
   )
  "Default Corewars mode expression highlighting.")

;;
;; -=[ Set up keymap ]=-
;;
(defvar corewars-mode-map (make-sparse-keymap)
  "Keymap used in Corewars mode.")

(define-key corewars-mode-map "\t" 'corewars-indent-command)

;;
;; -=[ Corewars Editing Mode ]=-
;;
(defun corewars-mode ()
  "Major mode for editing Corewars code."
  (interactive)
  (kill-all-local-variables)

  ;; Become the current major mode
  (setq mode-name "Corewars")
  (setq major-mode 'corewars-mode)

  ;; Activate keymap
  (use-local-map corewars-mode-map)

  ;; Set up comments
  (make-local-variable 'comment-start)
  (setq comment-start "# ")
  (make-local-variable 'comment-start-skip)
  (setq comment-start-skip "#+ *")
  (make-local-variable 'comment-column)
  (setq comment-column corewars-comment-column)

  ;; Set up indentation
  (make-local-variable 'indent-line-function)
  (setq indent-line-function 'corewars-indent-line)

  ;; Font Lock
  (make-local-variable 'font-lock-defaults)
  (setq font-lock-defaults (list 'corewars-font-lock-keywords nil t))

  ;; Miscellaneous customization
  (make-local-variable 'require-final-newline)
  (setq require-final-newline t))

;;
;; -=[ Indentation Setup ]=-
;;

(defun corewars-indent-line ()
  "Indent current line as Corewars code."
  (let (beg end)
    (beginning-of-line)
    ;; indent label
    (setq beg (point))
    (skip-chars-forward " \t")
    (delete-region beg (point))
    (if (not (looking-at "[#\n]"))
        ;; line does not start with a comment or is empty
        (progn
          (if (looking-at "^[a-zA-Z0-9]+:")
              (goto-char (match-end 0)))
          ;; indent keyword
          (setq beg (point))
          (skip-chars-forward " \t")
          (delete-region beg (point))
          (if (not (= (char-after) ?\#))
                (indent-to corewars-keyword-column))
          ;; indent comment
          (setq end (save-excursion
                      (end-of-line)
                      (point)))
          (if (re-search-forward "\\([ \t]*\\)#" end t)
              (progn
                (delete-region (match-beginning 1) (match-end 1))
                (goto-char (match-beginning 1))
                (indent-to corewars-comment-column)))))))

(defun corewars-indent-command ()
  "Indent current line as Corewars code, or sometimes insert a TAB.
If point is in the indentation, reindent this line.
If point is not in the indentation or this command is run twice in a
row, insert a TAB."
  (interactive)
;  (if (or (eq last-command 'corewars-indent-command)
;          (save-excursion
;            (skip-chars-backward " \t")
;            (not (bolp))))
;      (insert-tab)
    (corewars-indent-line))


;; corewars-mode.el ends here