;; Major mode for editing SLI programs.
;;
;; Modified from postscript.el without permission form the author. Do not distribute.
;; Does also include some non-authorized ideas from idlwave.el.
;; Editors: M.-O. Gewaltig, R. Kupper
;;
;; The following two statements, placed in your init.el file or site-init.el,
;; will cause this file to be autoloaded, and PS/SLI-mode invoked, when
;; visiting .sli files:]
;; (setq load-path (cons (concat (getenv "SLIHOME") "/extras/emacs") load-path))
;; (load-library "sli")
;; NOTE:
;; This file generated from postscript.el, by replacing all occurences of "ps-" by "ps-sli",
;; "postscript" by "postscript-sli" (apart from "ps-postscript-command", which was replaced
;; by "ps-sli-sli-command").
;; Then some SLI-specific changes.
;; Header of the original postscript.el follows:
;; Major mode for editing postscript programs.
;;
;; Author: Chris Maio
;; Last edit: 4 Sep 1988
;;
;; LCD Archive Entry:
;; postscript|Chris Maio|chris@cs.columbia.edu|
;; Major mode for editing PostScript programs.|
;; 4-Sep-1988||~/modes/postscript.el.Z|
;;
;; The following two statements, placed in your .emacs file or site-init.el,
;; will cause this file to be autoloaded, and postscript-mode invoked, when
;; visiting .ps or .cps files:
;;
;; (autoload 'postscript-mode "postscript.el" "" t)
;; (setq auto-mode-alist
;; (cons '("\\.c?ps$".postscript-mode) auto-mode-alist))
;;
(provide 'postscript-sli)
(require 'font-lock)
(require 'custom)
;; NOTE: all functions defined in this file start with "ps-sli-".
(defconst ps-sli-indent-level 2
"*Indentation to be used inside of Postscript-Sli blocks or arrays")
(defconst ps-sli-tab-width 2
"*Tab stop width for Postscript-Sli mode")
(defun ps-sli-make-tabs (stop)
(and (< stop 132) (cons stop (ps-sli-make-tabs (+ stop ps-sli-tab-width)))))
(defconst ps-sli-tab-stop-list (ps-sli-make-tabs ps-sli-tab-width)
"*Tab stop list for Postscript-Sli mode")
;;(defconst ps-sli-sli-command (list (concat (getenv "SLIHOME") "/nest/nest") "-")
;; "*Command used to invoke a SLI shell.")
;;(defvar ps-sli-sli-command (list (concat (getenv "SLIHOME") "/nest/nest") "-")
;; "*Command used to invoke a SLI shell.")
;; create the ps-sli-mode-map:
(defvar ps-sli-mode-map (make-sparse-keymap)
"Keymap used in Postscript-SLI mode buffers")
(defvar ps-sli-mode-syntax-table nil
"Postscript-Sli mode syntax table")
(defun postscript-sli-mode nil
"Major mode for editing Postscript-Sli files.
\\[ps-sli-execute-buffer] will send the contents of the buffer to the NeWS
server using psh(1). \\[ps-sli-execute-region] sends the current region.
\\[ps-sli-shell] starts an interactive psh(1) window which will be used for
subsequent \\[ps-sli-execute-buffer] or \\[ps-sli-execute-region] commands.
In this mode, TAB and \\[indent-region] attempt to indent code
based on the position of {}, [], and begin/end pairs. The variable
ps-sli-indent-level controls the amount of indentation used inside
arrays and begin/end pairs.
\\{ps-sli-mode-map}
\\[postscript-sli-mode] calls the value of the variable ps-sli-mode-hook with no args,
if that value is non-nil."
(interactive)
(kill-all-local-variables)
(use-local-map ps-sli-mode-map)
(if ps-sli-mode-syntax-table
(set-syntax-table ps-sli-mode-syntax-table)
(progn
(setq ps-sli-mode-syntax-table (make-syntax-table))
(set-syntax-table ps-sli-mode-syntax-table)
(modify-syntax-entry ?\( "<")
(modify-syntax-entry ?\) ">")
(modify-syntax-entry ?\[ "(\]")
(modify-syntax-entry ?\] ")\[")
(modify-syntax-entry ?\% "<")
(modify-syntax-entry ?\n ">")))
(make-local-variable 'comment-start)
(make-local-variable 'comment-start-skip)
(make-local-variable 'comment-column)
(make-local-variable 'indent-line-function)
(make-local-variable 'tab-stop-list)
(setq comment-start "%"
comment-start-skip "% *"
comment-column 40
indent-line-function 'ps-sli-indent-line
tab-stop-list ps-sli-tab-stop-list)
(setq mode-name "PS/SLI")
(setq major-mode 'postscript-sli-mode)
(run-hooks 'ps-sli-mode-hook))
(defun ps-sli-tab nil
"Command assigned to the TAB key in Postscript-Sli mode."
(interactive)
; This is a new version which does a fancy indentation from anywhere within
; a line. save-excursion saves the postion of the cursor
; Kupper & Gewaltig Nov. 2000
(save-excursion
(ps-sli-indent-line)
nil))
(defun ps-sli-indent-line nil
"Indents a line of Postscript-Sli code."
(interactive)
(beginning-of-line)
(delete-horizontal-space)
(if (not (or (looking-at "%%") ; "%%" comments stay at left margin
(ps-sli-top-level-p)))
(if (and (< (point) (point-max))
(eq ?\) (char-syntax (char-after (point)))))
(ps-sli-indent-close) ; indent close-delimiter
(if (looking-at "end\\(using\\)?\\|cdef")
(ps-sli-indent-end) ; indent end token
(ps-sli-indent-in-block))))) ; indent line after open delimiter
(defun ps-sli-open nil
(interactive)
(insert last-command-char))
(defun ps-sli-insert-d-char (arg)
"Awful hack to make \"end\" and \"cdef\" keywords indent themselves."
(interactive "p")
(insert-char last-command-char arg)
(save-excursion
(beginning-of-line)
(if (looking-at "^[ \t]*\\(end\\(using\\)?\\|cdef\\)")
(progn
(delete-horizontal-space)
(ps-sli-indent-end)))))
(defun ps-sli-close nil
"Inserts and indents a close delimiter."
(interactive)
(insert last-command-char)
(backward-char 1)
(ps-sli-indent-close)
(forward-char 1)
(blink-matching-open))
(defun ps-sli-indent-close nil
"Internal function to indent a line containing a an array close delimiter."
(if (save-excursion (skip-chars-backward " \t") (bolp))
(let (x (oldpoint (point)))
(forward-char) (backward-sexp) ;XXX
(if (and (eq 1 (count-lines (point) oldpoint))
(> 1 (- oldpoint (point))))
(goto-char oldpoint)
(beginning-of-line)
(skip-chars-forward " \t")
(setq x (current-column))
(goto-char oldpoint)
(delete-horizontal-space)
(indent-to x)))))
(defun ps-sli-indent-end nil
"Indent an \"end\" token or array close delimiter."
(let ((goal (ps-sli-block-start)))
(if (not goal)
(indent-relative)
(setq goal (save-excursion
(goto-char goal) (back-to-indentation) (current-column)))
(indent-to goal))))
(defun ps-sli-indent-in-block nil
"Indent a line which does not open or close a block."
(let ((goal (ps-sli-block-start)))
(setq goal (save-excursion
(goto-char goal)
(back-to-indentation)
(if (bolp)
ps-sli-indent-level
(back-to-indentation)
(+ (current-column) ps-sli-indent-level))))
(indent-to goal)))
;;; returns nil if at top-level, or char pos of beginning of current block
(defun ps-sli-block-start nil
"Returns the character position of the character following the nearest
enclosing `[' `{' or `begin' keyword."
(save-excursion
(let (open (skip 0))
(setq open (condition-case nil
(save-excursion
(backward-up-list 1)
(1+ (point)))
(error nil)))
(ps-sli-begin-end-hack open))))
(defun ps-sli-begin-end-hack (start)
"Search backwards from point to START for enclosing `begin' or 'namespace' and returns the
character number of the character following `begin' or START if not found.
Added search for 'namespace', Kupper, 21-jul-2003.
Added search for 'using/endusing', Kupper, 6-aug-2003."
;;Added search for 'namespace', Kupper, 21-jul-2003.
;;Added search for 'using/endusing', Kupper, 6-aug-2003.
(save-excursion
(let ((depth 1) match)
(while (and (> depth 0)
(or (re-search-backward
"\\(\\(^[ \t]*\\(end\\(using\\)?\\)\\)\\|^[ \ta-z0-9\\/_-]*\\(begin\\|namespace\\|using\\)\\)[ \t]*\\(%.*\\)*$" start t)
(re-search-backward "^[ \t]*cdef.*$" start t)))
(setq depth (if (looking-at "[ \t]*\\(end\\(using\\)?\\|end\\)")
(1+ depth) (1- depth))))
(if (not (eq 0 depth))
start
(forward-word 1)
(point)))))
(defun ps-sli-top-level-p nil
"Awful test to see whether we are inside some sort of Postscript-Sli block."
(and (condition-case nil
(not (scan-lists (point) -1 1))
(error t))
(not (ps-sli-begin-end-hack nil))))
;;; initialize the keymap if it doesn't already exist
;(if (null ps-sli-mode-map)
; (progn
; (setq ps-sli-mode-map (make-sparse-keymap))
;; add to keymap:
(define-key ps-sli-mode-map "d" 'ps-sli-insert-d-char)
(define-key ps-sli-mode-map "f" 'ps-sli-insert-d-char)
(define-key ps-sli-mode-map "{" 'ps-sli-open)
(define-key ps-sli-mode-map "}" 'ps-sli-close)
(define-key ps-sli-mode-map "[" 'ps-sli-open)
(define-key ps-sli-mode-map "]" 'ps-sli-close)
(define-key ps-sli-mode-map "\t" 'ps-sli-tab)
;;; (define-key ps-sli-mode-map "\C-c\C-c" 'ps-sli-execute-buffer)
;;; (define-key ps-sli-mode-map "\C-c|" 'ps-sli-execute-region)
;;; (define-key ps-sli-mode-map "\C-c!" 'ps-sli-shell)
; ))
;(defun ps-sli-execute-buffer nil
; "Send contents of the buffer for execution to the SLI shell.
;If no SLI shell process is running, a SLI new shell is started."
; (interactive)
; (save-excursion
; (mark-whole-buffer)
; (ps-sli-execute-region (point-min) (point-max))))
;(defun ps-sli-execute-region (start end)
; "Send the region between START and END for execution to the SLI shell.
;If no SLI shell process is running, a SLI new shell is started."
; (interactive "r")
; (let ((start (min (point) (mark)))
; (end (max (point) (mark))))
; (condition-case nil
; (process-send-string "Postscript-Sli" (buffer-substring start end))
; (error (shell-command-on-region start end ps-sli-sli-command nil)))))
;(defun ps-sli-shell nil
; "Start a shell communicating with a Postscript-Sli printer or NeWS server."
; (interactive)
; (require 'shell)
; (switch-to-buffer-other-window
; (make-shell "Postscript-Sli" ps-sli-sli-command))
; (make-local-variable 'shell-prompt-pattern)
; (setq shell-prompt-pattern "^SLI .*\\] ")
; (process-send-string "Postscript-Sli" "executive\n"))
(defvar ps-sli-font-lock-keywords
'(
("%.*$" . font-lock-comment-face) ; PS Style comments
("\\/\\*.*$" . font-lock-comment-face) ; This is a hack for c-style comments
("^.*\\*\\/" . font-lock-comment-face) ; it fontifies the lines containing /* and */
("\\([A-Za-z]\\)+:" . font-lock-doc-keyword-face) ; This fontifies documentation keywords
("\\<\\(def\\|for\\|repeat\\|loop\\|bind\\|SLIFunctionWrapper\\)\\>" . font-lock-keyword-face)
("\\<\\(if\\|ifelse\\|exit\\)\\>" . font-lock-keyword-face)
("\\<\\(forall\\|forallindexed\\)\\>" . font-lock-keyword-face)
("\\<\\(Map\\|MapIndexed\\|MapThread\\)\\>" . font-lock-keyword-face)
("\\<\\(begin\\|end\\|namespace\\|using\\|endusing\\)\\>" . font-lock-keyword-face)
("\\<\\(provide\\|provide-component\\|require\\|require-component\\)\\>" . font-lock-keyword-face)
("\\<\\(stop\\|stopped\\|raiseerror\\|raiseagain\\)\\>" . font-lock-keyword-face)
;; ("[{}]" . font-lock-keyword-face) ; fontify braces
("\\/\\([:.?A-Za-z0-9_]\\)+\\b" . font-lock-function-name-face) ; literal names
("([^()]*\\(([^()]*)\\)*[^()]*)" . font-lock-string-face) ; hack for nested strings
)
"Default expressions to highlight in PS mode.")
;; Example how to add faces
;; First define a variable
(defvar font-lock-doc-keyword-face 'font-lock-doc-keyword-face
"Face name to use for documentation keywords.")
;; then use it to define a new face.
(defface font-lock-doc-keyword-face
'((((class grayscale) (background light)) (:foreground "LightGray" :bold t))
(((class grayscale) (background dark)) (:foreground "DimGray" :bold t))
(((class color) (background light)) (:foreground "Black" :underline t))
(((class color) (background dark)) (:foreground "LightSteelBlue":underline t))
(t (:bold t)))
"Font Lock mode face used to highlight documentation keywords"
:group 'font-lock-highlighting-faces)
(add-hook 'ps-sli-mode-hook
(function (lambda ()
(make-local-variable 'font-lock-defaults)
(setq font-lock-defaults '(ps-sli-font-lock-keywords t))
(font-lock-mode 1)
)))