1 ;;; pspp-mode-el -- Major mode for editing PSPP files
3 ;; Copyright (C) 2005 Free Software Foundation
4 ;; Author: John Darrington <john@darrington.wattle.id.au>
5 ;; Created: 05 March 2005
6 ;; Keywords: PSPP major-mode
10 ;; Based on the example wpdl-mode.el by Scott Borton
11 ;; Author: Scott Andrew Borton <scott@pp.htv.fi>
13 ;; Copyright (C) 2000, 2003 Scott Andrew Borton <scott@pp.htv.fi>
15 ;; This program is free software; you can redistribute it and/or
16 ;; modify it under the terms of the GNU General Public License as
17 ;; published by the Free Software Foundation; either version 2 of
18 ;; the License, or (at your option) any later version.
20 ;; This program is distributed in the hope that it will be
21 ;; useful, but WITHOUT ANY WARRANTY; without even the implied
22 ;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
23 ;; PURPOSE. See the GNU General Public License for more details.
25 ;; You should have received a copy of the GNU General Public
26 ;; License along with this program; if not, write to the Free
27 ;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
31 (defvar pspp-mode-hook nil)
33 (let ((pspp-mode-map (make-keymap)))
34 (define-key pspp-mode-map "\C-j" 'newline-and-indent)
36 "Keymap for PSPP major mode")
38 (add-to-list 'auto-mode-alist '("\\.sps\\'" . pspp-mode))
41 (defun pspp-data-block-p ()
42 "Returns t if current line is inside a data block."
45 (pspp-end-of-block-found nil)
46 (pspp-start-of-block-found nil)
50 (or (bobp) pspp-end-of-block-found )
51 pspp-start-of-block-found
54 (set 'pspp-end-of-block-found (looking-at "^[ \t]*END[\t ]+DATA\."))
55 (set 'pspp-start-of-block-found (looking-at "^[ \t]*BEGIN[\t ]+DATA"))
59 (and pspp-start-of-block-found (not pspp-end-of-block-found))
64 (defconst pspp-indent-width
70 (defconst pspp-indenters
77 "constructs which cause indentation"
81 (defconst pspp-unindenters
82 (concat "^[\t ]*END[\t ]+"
90 ;; Note that "END CASE" and "END FILE" do not unindent.
92 "constructs which cause end of indentation"
97 (defun pspp-indent-line ()
98 "Indent current line as PSPP code."
103 (the-indent 0) ; Default indent to column 0
108 (setq the-indent 0) ; First line is always non-indented
117 ;; If the most recent non blank line ended with a `.' then
118 ;; we're at the start of a new command.
121 (while (and blank-line (not (bobp)))
124 (if (and (not (pspp-data-block-p)) (not (looking-at "^[ \t]*$")))
126 (setq blank-line nil)
128 (if (not (looking-at ".*\\.[ \t]*$"))
129 (setq within-command t)
137 ;; If we're not at the start of a new command, then add an indent.
139 (set 'the-indent (+ 1 the-indent))
144 ;; Set the indentation according to the DO - END blocks
149 (if (not (pspp-comment-p))
154 (looking-at pspp-indenters)
156 (set 'the-indent (+ the-indent 1) )
159 ( (looking-at pspp-unindenters)
160 (set 'the-indent (- the-indent 1) )
170 (if (looking-at "^[\t ]*ELSE")
171 (set 'the-indent (- the-indent 1)))
174 ;; Stuff in the data-blocks should be untouched
175 (if (not (pspp-data-block-p)) (indent-line-to (* pspp-indent-width the-indent)))
180 (defun pspp-comment-start-line-p ()
181 "Returns t if the current line is the first line of a comment, nil otherwise"
183 (or (looking-at "^\*")
184 (looking-at "^[\t ]*COMMENT[\t ]")
189 (defun pspp-comment-end-line-p ()
190 "Returns t if the current line is the candidate for the last line of a comment, nil otherwise"
192 (looking-at ".*\\.[\t ]*$")
197 (defun pspp-comment-p ()
198 "Returns t if point is in a comment. Nil otherwise."
199 (if (pspp-data-block-p)
202 (pspp-comment-start-found nil)
203 (pspp-comment-end-found nil)
204 (pspp-single-line-comment nil)
209 (while (and (>= lines 0)
210 (not pspp-comment-start-found)
211 (not pspp-comment-end-found)
214 (if (pspp-comment-start-line-p) (set 'pspp-comment-start-found t))
216 (set 'pspp-comment-end-found nil)
219 (if (pspp-comment-end-line-p) (set 'pspp-comment-end-found t))
222 (set 'lines (forward-line -1))
227 (set 'pspp-single-line-comment (and
228 (pspp-comment-start-line-p)
229 (pspp-comment-end-line-p)))
233 (or pspp-single-line-comment
234 (and pspp-comment-start-found (not pspp-comment-end-found)))
239 (defvar pspp-mode-syntax-table
241 (x-pspp-mode-syntax-table (make-syntax-table))
244 ;; Special chars allowed in variables
245 (modify-syntax-entry ?# "w" x-pspp-mode-syntax-table)
246 (modify-syntax-entry ?@ "w" x-pspp-mode-syntax-table)
247 (modify-syntax-entry ?$ "w" x-pspp-mode-syntax-table)
250 ;; This is incomplete, because:
251 ;; a) Comments can also be given by COMMENT
252 ;; b) The sequence .\n* is interpreted incorrectly.
254 (modify-syntax-entry ?* ". 2" x-pspp-mode-syntax-table)
255 (modify-syntax-entry ?. ". 3" x-pspp-mode-syntax-table)
256 (modify-syntax-entry ?\n "- 41" x-pspp-mode-syntax-table)
260 (modify-syntax-entry ?' "\"" x-pspp-mode-syntax-table)
261 (modify-syntax-entry ?" "\"" x-pspp-mode-syntax-table)
263 x-pspp-mode-syntax-table)
265 "Syntax table for pspp-mode")
268 (defconst pspp-font-lock-keywords
288 "CLEAR TRANSFORMATIONS"
356 "LOGISITIC REGRESSION"
380 "PEARSON CORRELATIONS"
446 'font-lock-builtin-face)
449 (concat "\\<" (regexp-opt '(
450 "ALL" "AND" "BY" "EQ" "GE" "GT" "LE" "LT"
451 "NE" "NOT" "OR" "TO" "WITH"
452 ) t ) "\\>") 'font-lock-keyword-face)
673 t) "\\>" ) 'font-lock-function-name-face)
675 '( "\\<[#$@a-zA-Z][a-zA-Z0-9_]*\\>" . font-lock-variable-name-face)
680 "Highlighting expressions for PSPP mode.")
685 (kill-all-local-variables)
686 (use-local-map pspp-mode-map)
687 (set-syntax-table pspp-mode-syntax-table)
689 (set (make-local-variable 'font-lock-keywords-case-fold-search) t)
690 (set (make-local-variable 'font-lock-defaults) '(pspp-font-lock-keywords))
692 (set (make-local-variable 'indent-line-function) 'pspp-indent-line)
693 (set (make-local-variable 'comment-start ) "* ")
694 (set (make-local-variable 'compile-command)
699 (setq major-mode 'pspp-mode)
700 (setq mode-name "PSPP")
701 (run-hooks 'pspp-mode-hook))
705 ;;; pspp-mode.el ends here