Various small fixes and clean-ups for the 0.4.2 release.
[shapes.git] / edit / emacs / shapes-mode.el
blobd86be808428827dd2fdcc2561b7bd8e2eecdab95
1 ;;; shapes-mode.el --- Emacs major mode for editing Shapes programs
3 ;; Copyright (C) 2008 Tobias Gerdin
5 ;; This file is part of Shapes.
7 ;; Shapes is free software: you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation, either version 3 of the License, or
10 ;; any later version.
12 ;; Shapes is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with Shapes. If not, see <http://www.gnu.org/licenses/>.
20 ;;; Commentary:
22 ;; This mode is very much work in progress. It does not handle automatic
23 ;; indentation of Shapes programs nor does it offer any motion commands adapted
24 ;; to such. That said, it does support compilation-mode, comment-dwim, Imenu and
25 ;; viewing output through doc-view.
27 ;; TODO
28 ;; - Syntax highlighting (first: comment and string faces)
29 ;; - motion commands
30 ;; - automatic indentation
31 ;; - Hide compilation buffer if a doc-view buffer is visible and there are no
32 ;;errors when recompiling.
33 ;; - PDF sync between source and output (path control points etc).
34 ;; - Automatically pretty-print #, \, ->
36 ;; BUGS
37 ;; - Investigate mismatch between Shapes and Emacs column numbers.
38 ;; Note: Emacs column 0 means that *point* is before the first char. Column 1
39 ;; * point is after first char (and the cursor is ON char 2).
41 ;;; Installation
43 ;; To install, put this file somewhere in your load path and just require
44 ;; 'shapes-mode from your ~/.emacs or equivalent, like so:
46 ;; (require 'shapes-mode)
48 ;; Code tested only on GNU Emacs 22.
50 (defcustom shapes-compile-command "~/shapes/source/shapes"
51 "Name of the Shapes compiler executable, and any options to pass to it."
52 :type 'string)
54 (defconst shapes-file-regex "\\.sh\\(ape\\|ext\\)$"
55 "Regular expression matching Shapes source files.")
57 (add-to-list 'auto-mode-alist (cons shapes-file-regex 'shapes-mode))
59 ;; The Shapes compiler wants its input utf-8, LF line-endings (for now).
60 (modify-coding-system-alist 'file shapes-file-regex 'utf-8-unix)
62 ;; Example data:
63 ;; /Users/tger/stroke.shape:1(8-10): The unit b is unbound
64 (eval-after-load 'compile
65 '(add-to-list 'compilation-error-regexp-alist
66 '("\\(.*\\):\\([0-9]+\\)(\\([0-9]+\\)-\\([0-9]+\\)):"
67 1 2 (3 . 4) nil 1)))
69 ;;; TBD
70 ;; (defvar shapes-mode-syntax-table
71 ;; (let ((st (make-syntax-table)))
72 ;; (modify-syntax-entry ?\" ". " st)
73 ;; (modify-syntax-entry ?\\ ". " st)
74 ;; ;; Add `p' so M-c on `hello' leads to `Hello', not `hello'.
75 ;; (modify-syntax-entry ?' "w p" st)
76 ;; st)
77 ;; "Syntax table used while in `text-mode'.")
79 (defvar shapes-mode-map
80 (let ((map (make-sparse-keymap)))
81 (define-key map "\C-c\C-c" 'shapes-compile)
82 (when (featurep 'doc-view) ; Emacs 22 and lower does not ship with
83 ; doc-view
84 (define-key map "\C-c\C-v" 'shapes-view))
85 map))
87 (defun shapes-compile ()
88 "Compiles the source file."
89 (interactive)
90 (compile (concat shapes-compile-command " " (buffer-file-name))))
92 (defun shapes-view ()
93 "Compiles the source file and, if compilation is successful, views it using
94 doc-view."
95 (interactive)
96 ;; Here we basically pass the code to view the output as a continuation to the
97 ;; compile function since compilation is performed asynchronously in Emacs.
98 (add-to-list
99 'compilation-finish-functions
100 (lambda (comp-buf exit-msg)
101 ;; I am confused as to which buffer is really active when we are
102 ;; applied. (buffer-name) reports *compilation* but (window-buffer) reports
103 ;; the Shapes program buffer.
104 (setq compilation-finish-functions (cdr compilation-finish-functions))
105 (when (equal exit-msg "finished\n")
106 (let ((output (concat (file-name-sans-extension
107 (buffer-file-name (window-buffer)))
108 ".pdf")))
109 (with-selected-window
110 (next-window) ; This way image will hopefully reuse
111 ; the compilation buffer.
112 (doc-view t output))))))
113 (shapes-compile))
115 (defun shapes-mode ()
116 "Major mode for editing Shapes programs.
117 \\{shapes-mode-map}"
118 (interactive)
119 (kill-all-local-variables)
120 (setq major-mode 'shapes-mode)
121 (setq mode-name "Shapes")
122 (use-local-map shapes-mode-map)
123 ;(set-syntax-table shapes-mode-syntax-table)
125 (setq comment-start-skip "/\\*\\*+ *\\||\\*\\*+ *")
126 (setq comment-start "|**")
128 ;; The Shapes compiler tabs philosophy is different from that of Emacs, so for
129 ;; now we do this.
130 (setq indent-tabs-mode nil)
132 ;; Simplified recognition of a top-level Shapes identifier. Probably needs
133 ;; more work.
134 (setq imenu-generic-expression '((nil "^\\([a-zA-Z0-9_?]+\\):" 1)
135 (nil "^dynamic\\s-+\\(@[a-zA-Z0-9_?]+\\)" 1)))
137 (unless (or (file-exists-p "makefile")
138 (file-exists-p "Makefile"))
139 (set (make-local-variable 'compile-command)
140 (concat shapes-compile-command " "
141 (file-name-sans-extension buffer-file-name)))))
143 (provide 'shapes-mode)