5ad4029
;;; A major mode for editing IRSIM netlists. Public domain. Created by
5ad4029
;;; Peter Scott <pjscott@iastate.edu> in 2008. To install, put
5ad4029
;;; irsim-mode.el somewhere that emacs will see it like you site-lisp/
5ad4029
;;; sirectory and stick something like this in your .emacs file:
5ad4029
;;;
5ad4029
;;; (autoload 'irsim-mode "irsim-mode" nil t)
5ad4029
;;; (setq auto-mode-alist
5ad4029
;;;       (cons '("\\.sim$" . irsim-mode) auto-mode-alist))
5ad4029
;;;
5ad4029
;;; Note that this will override the default behavior for opening .sim
5ad4029
;;; files, which is to go into simula-mode. This might be a problem if
5ad4029
;;; you use both.
5ad4029
;;;
5ad4029
;;; Note also that this mode is opinionated. It has a very specific
5ad4029
;;; idea of how IRSIM code ought to be indented, and if you don't like
5ad4029
;;; it then just set irsim-use-fancy-indent to nil. I think that the
5ad4029
;;; default indentation method leads to very pretty files and easy
5ad4029
;;; typing, but YMMV.
5ad4029
5ad4029
(require 'font-lock)
5ad4029
(require 'cl)
5ad4029
5ad4029
;; Customizable variables:
5ad4029
;;;;;;;;;;;;;;;;;;;;;;;;;;
5ad4029
5ad4029
(defvar irsim-use-fancy-indent t
5ad4029
  "Specifies whether irsim-mode should use fancy indentation or
5ad4029
  plain. Default is fancy, but set it to nil for plan.")
5ad4029
5ad4029
(defvar irsim-tab-stops '(0 3 16 32 48 51)
5ad4029
  "The starting column positions for each entry in a transistor
5ad4029
  line using the fancy indent function. Change if you like.")
5ad4029
5ad4029
5ad4029
;; Some global variables
5ad4029
5ad4029
(defvar irsim-mode-version "0.1"
5ad4029
  "The current version number of irsim-mode.")
5ad4029
5ad4029
(defvar irsim-mode-hook nil)
5ad4029
5ad4029
(defconst irsim-font-lock-keywords
5ad4029
  (list
5ad4029
   '("^[\t ]*[np]" . font-lock-builtin-face)
5ad4029
   '("[a-zA-Z_][_-a-zA-Z0-9.]*" . font-lock-variable-name-face))
5ad4029
  "Minimal highlighting expressions for IRSIM mode")
5ad4029
5ad4029
;; Define comment behavior and make underscores act as normal
5ad4029
;; characters for forward-word and backward-word behavior. This makes
5ad4029
;; a lot more sense than the default.
5ad4029
(defvar irsim-mode-syntax-table
5ad4029
  (let ((irsim-mode-syntax-table (make-syntax-table)))
5ad4029
    (modify-syntax-entry ?| "<   " irsim-mode-syntax-table)
5ad4029
    (modify-syntax-entry ?\n ">   " irsim-mode-syntax-table)
5ad4029
    (modify-syntax-entry ?\^m ">   " irsim-mode-syntax-table)
5ad4029
    (modify-syntax-entry ?_ "w" irsim-mode-syntax-table)
5ad4029
    irsim-mode-syntax-table))
5ad4029
5ad4029
5ad4029
;; Indentation
5ad4029
;;;;;;;;;;;;;;
5ad4029
5ad4029
(defun irsim-line-type ()
5ad4029
  "Returns the type of line in IRSIM code that the point is
5ad4029
  on. Valid return values are 'transistor-line, 'comment-line, or
5ad4029
  nil"
5ad4029
  (save-excursion
5ad4029
    (move-beginning-of-line nil)
5ad4029
    (if (looking-at "^[\t ]*[np]")
5ad4029
	'transistor-line
5ad4029
	(if (looking-at "^[\t ]*\\|")
5ad4029
	    'comment-line))))
5ad4029
5ad4029
;; To indent a transistor line, just move the columns into place and
5ad4029
;; put the cursor at the last empty column. Or don't move it if there
5ad4029
;; are no more empty columns. Comment lines should not be indented.
5ad4029
(defun irsim-indent-line ()
5ad4029
  "Indent the current line of IRSIM code properly"
5ad4029
  (interactive)
5ad4029
  (let ((at-end nil))
5ad4029
    (if (looking-at "[\t ]*$")
5ad4029
	(setq at-end t))
5ad4029
    (if (eql (irsim-line-type) 'transistor-line)
5ad4029
	(progn
5ad4029
	  (save-excursion
5ad4029
	    (save-restriction
5ad4029
	      ;; Narrow to just this line
5ad4029
	      (narrow-to-region (line-beginning-position) (line-end-position))
5ad4029
	      (beginning-of-line)
5ad4029
	      (indent-line-to 0)
5ad4029
	      (let ((tab-stops (copy-seq irsim-tab-stops)))
5ad4029
		(while (and tab-stops (not (looking-at "[\t ]*$")))
5ad4029
		  (while (looking-at "[\t ]")
5ad4029
		    (delete-char 1))
5ad4029
		  (indent-to-column (car tab-stops))
5ad4029
		  (setq tab-stops (cdr tab-stops))
5ad4029
		  (forward-word))
5ad4029
		(when (and at-end tab-stops)
5ad4029
		  (message "yarr")
5ad4029
		  (end-of-line)
5ad4029
		  (indent-to-column (car tab-stops))))))
5ad4029
	  (if at-end (end-of-line)))
5ad4029
	(if (eql (irsim-line-type) 'comment-line)
5ad4029
	    (save-excursion
5ad4029
	      (beginning-of-line)
5ad4029
	      (indent-line-to 0))))))
5ad4029
5ad4029
5ad4029
5ad4029
(defun irsim-mode ()
5ad4029
  "Major mode for editing IRSIM netlists."
5ad4029
  (interactive)
5ad4029
  (kill-all-local-variables)
5ad4029
  (make-local-variable 'font-lock-defaults)
5ad4029
  (setq font-lock-defaults '(irsim-font-lock-keywords))
5ad4029
  (set-syntax-table irsim-mode-syntax-table)
5ad4029
  (set (make-local-variable 'comment-start) "| ")
5ad4029
5ad4029
  (when irsim-use-fancy-indent
5ad4029
    (set (make-local-variable 'indent-line-function) 'irsim-indent-line))
5ad4029
5ad4029
  (setq mode-name "IRSIM"
5ad4029
	major-mode 'irsim-mode)
5ad4029
  (run-hooks 'irsim-mode-hook))
5ad4029
5ad4029
(provide 'irsim-mode)