;; 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) )))