;; LPC mode ;; ;; Emacs Lisp Archive Entry ;; Package: lpc-mode ;; Filename: lpc-mode.el ;; Version: 0.12 ;; Keywords: languages, LPC ;; Author: Vivek Dasmohapatra ;; Maintainer: Vivek Dasmohapatra ;; Created: 2002-08-31 ;; Description: syntax highlighting/indentation for LPC ;; URL: http://rtfm.etla.org/emacs/lpc-mode/ ;; Compatibility: Emacs21 ;; Last-Updated: Tue 2002-09-17 23:59:51 +0100 ;; This file is NOT part of GNU Emacs ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;; Copyright (C) 2002 Vivek Dasmohapatra ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; OK Nick: first stab at LPC mode: ;; 0.01: 'foo and 'C' should be handled correctly. ;; 0.02 ... 0.06: intermediates. ;; 0.07: ultra-hairy ({#'[][,&] syntax now scanned for. Bleurgh. ;; 0.08: ({ ... }) syntax added as brace-list ;; 0.09: rip up and rewrite as a proper cc-mode based mode ;; 0.10: miscellaneous bugfixes. ;; 0.11: should compile cleanly now _and_ work as well (I hope) ;; 0.12: bug in `lpc-font-lock-map' keyword/function definition highlighting ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; HOW TO INSTALL: ;; ;; ;; either put lpc-mode.el in your load path and use: ;; (autoload 'lpc-mode "lpc-mode" t) ;; ;; ;; or have: ;; (autoload 'lpc-mode "/path/to/lpc-mode.el" t) ;; ;; ;; then: ;; (setq auto-mode-alist ;; (append '(("\\.lpc$" . lpc-mode)) auto-mode-alist)) ) ;; ;; Nick: You'll have to do similar things to handler.el to get that to ;; work, let me know if you need this done. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; elisp-dep-block >> (require 'custom );(defface) (require 'cc-mode );(c-electric-brace) (require 'regexp-opt);(regexp-opt-depth regexp-opt) (require 'font-lock ) ;;(font-lock-add-keywords font-lock-fontify-region font-lock-mode) ;; elisp-dep-block << (defconst lpc-mode-version "0.12") (eval-and-compile (defmacro lpc-defsyntax (name doc klist) "Declare a cc-mode syntax variable of lpc-N-keywords and a regex lpc-N-regex to go along with it, based on the keyword list K." (let* ((n name ) (d doc ) (k klist) (ln (format "lpc-%s-keywords" n)) (ld (format "%s (list)" d)) (ls (intern ln)) (rn (format "lpc-%s-regex" n)) (rd (format "%s (regex)" d)) (rs (intern rn)) (kwds nil)) (setq kwds (if (stringp (car k)) k (eval k))) ;;(message "%s" (format "%S" kwds)) `(progn (defconst ,ls ',kwds ,ld) (defconst ,rs (regexp-opt ',kwds) ,rd)) )) (lpc-defsyntax type "LPC primitive type keywords." ("int" "mapping" "mixed" "object" "status" "string" "void")) (lpc-defsyntax specifier "LPC declaration specifier keywords." ("nomask" "private" "public" "static" "varargs")) (lpc-defsyntax other-decl "LPC keywords starting other decl-level constructs." ("inherit")) (lpc-defsyntax block-stmt-1 "LPC keywords followed directly by a block." ("do" "else")) (lpc-defsyntax block-stmt-2 "LPC keywords followed by a paren sexp and then by a block." ("for" "if" "switch" "while" "foreach")) (lpc-defsyntax simple-stmt "LPC statement keywords followed by an expression or nothing." ("break" "continue" "return")) (lpc-defsyntax label "LPC keywords introducing labels in blocks." ("case" "default")) (lpc-defsyntax all "LPC keywords." (append lpc-type-keywords lpc-specifier-keywords lpc-other-decl-keywords lpc-block-stmt-1-keywords lpc-block-stmt-2-keywords lpc-simple-stmt-keywords lpc-label-keywords )) (lpc-defsyntax default-highlight "LPC keywords (for default highlighting)" (append lpc-specifier-keywords lpc-block-stmt-1-keywords lpc-block-stmt-2-keywords lpc-simple-stmt-keywords )) (lpc-defsyntax conditional "LPC conditional keywords" (append lpc-block-stmt-1-keywords lpc-block-stmt-2-keywords)) ) (defconst lpc-comment-start-regex c-C++-comment-start-regexp) (defconst lpc-special-brace-lists '((?{ . ?})) ) (defconst lpc-magic-quote-comma '(9)) (defconst lpc-magic-symbol-name '(3)) (defvar lpc-mode-syntax-table nil) (if lpc-mode-syntax-table nil (setq lpc-mode-syntax-table (make-syntax-table)) (c-populate-syntax-table lpc-mode-syntax-table) (modify-syntax-entry ?\' "'" lpc-mode-syntax-table) ) (defun lpc-modify-syntax-at (beg end syntax) "Apply a syntax-property value syntax from beg to end." (if (<= (point-max) end) nil; noop (progn ;;(message "(%d x %d) => %S" beg end syntax) (put-text-property beg end 'syntax-table syntax) (put-text-property (1- end) end 'rear-nonsticky t )))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Code by Seth Golub , 1996-02-01, ;; no licence. ;; ;; modified slightly to bring this up to date, didn't work quite right ;; out of the box: (defun lpc-maybe-electric-brace (arg) "Insert character and maybe correct line's indentation." (interactive "P") (if (= last-command-char ?{) (if (= (preceding-char) ?\() (self-insert-command (prefix-numeric-value arg)) (c-electric-brace arg)) ;; (= last-command-char ?}) (let (start-point state containing-sexp) (save-excursion (beginning-of-defun) (setq start-point (point))) (save-excursion (setq state (parse-partial-sexp (point) start-point 0))) (setq containing-sexp (car (cdr state))) (if (and containing-sexp (save-excursion (goto-char (1- containing-sexp)) (looking-at "("))) (progn (self-insert-command (prefix-numeric-value arg)) (lpc-scan-magic-quote)) (c-electric-brace arg))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defconst lpc-magic-quote-regex "({\\s-*#'\\([^\\s-\n,}]+\\|,\\)\\s-*[,}]") (defun lpc-magic-comma-p (pt) (let ((bol nil) (eol nil) (pos nil) (ret nil)) (save-excursion (goto-char pt) (end-of-line) (setq eol (point)) (beginning-of-line) (setq bol (point)) (while (and (not ret) (setq pos (re-search-forward lpc-magic-quote-regex eol t))) ;;(message "magic pattern at %d/%d" (1- pos) pt) (if (/= (1- pos) pt) nil (setq ret (list (- (match-beginning 1) 1) (match-beginning 1) (match-end 1) bol)) ) )) ret)) (defun lpc-scan-magic-quotes () (save-excursion (let ((qpos nil) (wbeg nil) (wend nil)) (while (re-search-forward lpc-magic-quote-regex nil t) (setq qpos (+ (match-beginning 0) 3) wbeg (match-beginning 1) wend (match-end 1)) (lpc-modify-syntax-at qpos (1+ qpos) lpc-magic-quote-comma) (lpc-modify-syntax-at wbeg wend lpc-magic-symbol-name) ) ) ) ) (defun lpc-scan-magic-quote () (save-excursion (let ((coord nil) (qpos nil) (wbeg nil) (wend nil) (bol nil)) (if (setq coord (lpc-magic-comma-p (1- (point)))) (progn (setq qpos (car coord) wbeg (cadr coord) wend (car (cddr coord)) bol (cadr (cddr coord))) ;;(message "magic pattern at (%d %d %d)" qpos wbeg wend) (lpc-modify-syntax-at qpos (1+ qpos) lpc-magic-quote-comma) (lpc-modify-syntax-at wbeg wend lpc-magic-symbol-name) (font-lock-fontify-region bol wend) ) ) ) ) ) (defun lpc-maybe-quote-ref (arg) "Kludge to work around multiple syntactic meanings of `,' `[' et al in LPC." (interactive "P") (self-insert-command (prefix-numeric-value arg)) (lpc-scan-magic-quote) ) (defvar lpc-mode-map nil "Keymap for LPC mode buffers.") (if lpc-mode-map nil (setq lpc-mode-map (c-make-inherited-keymap)) (define-key lpc-mode-map "\C-c:" 'c-scope-operator) (define-key lpc-mode-map "{" 'lpc-maybe-electric-brace) (define-key lpc-mode-map "}" 'lpc-maybe-electric-brace) (define-key lpc-mode-map "," 'lpc-maybe-quote-ref) (define-key lpc-mode-map "\C-c\C-e" 'c-macro-expand) ) (defvar lpc-mode-hook nil) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; font-lock support: (defvar lpc-reference-face 'lpc-reference-face) (defface lpc-reference-face '((((class color) (background dark)) (:foreground "bisque" )) (((class color) (background light)) (:foreground "dark blue"))) "LPC mode face for quoted symbols") (defconst lpc-type-depth (regexp-opt-depth lpc-type-regex)) (defconst lpc-font-lock-map (append c-font-lock-keywords-1 (list ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; what follows is mostly ripped from font-lock.el, mostly... `(eval . (cons (concat "\\<\\(" ,lpc-type-regex "\\)\\>") 'font-lock-type-face)) (concat "\\<\\(" lpc-default-highlight-regex "\\)\\>") '("\\<\\(case\\)\\>" (1 font-lock-keyword-face) ("\\(-[0-9]+\\|\\sw+\\)" ;; Return limit of search. (save-excursion (skip-chars-forward "^:\n") (point)) nil (1 font-lock-constant-face nil t))) '(":" ("^[ \t]*\\(\\sw+\\)[ \t]*:[ \t]*$" (beginning-of-line) (end-of-line) (1 font-lock-constant-face))) `(eval . (list (concat "\\<\\(" ,lpc-type-regex "\\)\\>" "\\([ \t*&]+\\sw+\\>\\)*") ;; Fontify each declaration item. (list 'font-lock-match-c-style-declaration-item-and-skip-to-next ;; Start with point after all type specifiers. (list 'goto-char (list 'or (list 'match-beginning (+ ,lpc-type-depth 2)) '(match-end 1))) ;; Finish with point after first type specifier. '(goto-char (match-end 1)) ;; Fontify as a variable or function name. '(1 (if (match-beginning 2) font-lock-function-name-face font-lock-variable-name-face))))) ;; Fontify anything at beginning of line as a declaration or definition. '("^\\(\\sw+\\)\\>\\([ \t*]+\\sw+\\>\\)*" (1 font-lock-type-face) (font-lock-match-c-style-declaration-item-and-skip-to-next (goto-char (or (match-beginning 2) (match-end 1))) nil (1 (if (match-beginning 2) font-lock-function-name-face font-lock-variable-name-face)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; and now native LPC highlighting: '("\\('.'\\|'\\\\.'\\)" 1 font-lock-string-face keep) ;; lambda thingies '("{\\s-*\\(#\\)" 1 font-lock-builtin-face keep) '("'\\([^}, \t;]+\\)" 1 lpc-reference-face keep) '("'\\(,\\)[,} \t\n]" 1 lpc-reference-face keep) ;; '("\\(\\binherit\\)\\s-+\\s\".+\";" 1 font-lock-builtin-face t) ) ) ) (defun lpc-set-font-lock-defaults () "Set up LPC mode font-lock stuff." (let ((font-lock-defaults '(lpc-font-lock-map nil nil ((?_ . "w") (?\' . "'")) beginning-of-defun (font-lock-mark-block-function . mark-defun)))) (font-lock-set-defaults))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; bring it all together: (defun lpc-mode () (interactive) (c-initialize-cc-mode) (kill-all-local-variables) (set-syntax-table lpc-mode-syntax-table) (make-variable-buffer-local 'parse-sexp-lookup-properties) (set 'parse-sexp-lookup-properties t) (setq major-mode 'lpc-mode mode-name "LPC") (use-local-map lpc-mode-map) (c-common-init) (setq c-keywords (c-identifier-re lpc-all-regex) c-special-brace-lists lpc-special-brace-lists comment-start "// " comment-end "" c-conditional-key lpc-conditional-regex c-comment-start-regexp lpc-comment-start-regex c-extra-toplevel-key lpc-other-decl-regex ;; c-class-key nil ;; cannot set this to nil or "" c-method-key nil c-baseclass-key nil c-recognize-knr-p nil c-lambda-key nil c-inexpr-block-key nil c-inexpr-class-key nil) (lpc-set-font-lock-defaults) (lpc-scan-magic-quotes) (if (not noninteractive) (turn-on-font-lock) (let ((font-lock-mode t) (noninteractive nil)) (turn-on-font-lock))) (run-hooks 'c-mode-common-hook) (run-hooks 'lpc-mode-hook) (c-update-modeline) ) (provide 'lpc-mode) ;; lpc-mode.el ends here