1 ;; copyright 2003-2005 stefan kersten <steve@k-hornz.de>
3 ;; This program is free software; you can redistribute it and/or
4 ;; modify it under the terms of the GNU General Public License as
5 ;; published by the Free Software Foundation; either version 2 of the
6 ;; License, or (at your option) any later version.
8 ;; This program is distributed in the hope that it will be useful, but
9 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
10 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 ;; General Public License for more details.
13 ;; You should have received a copy of the GNU General Public License
14 ;; along with this program; if not, write to the Free Software
15 ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 (require 'sclang-util
))
24 (require 'sclang-interp
)
25 (require 'sclang-language
)
28 (defun sclang-fill-syntax-table (table)
30 (modify-syntax-entry ?
\" "\"" table
)
31 (modify-syntax-entry ?
\' "\"" table
) ; no string syntax class for single quotes
33 (modify-syntax-entry ?~
"'" table
)
35 (modify-syntax-entry ?
\\ "\\" table
)
37 (modify-syntax-entry ?$
"/" table
)
39 (modify-syntax-entry ?_
"_" table
)
41 (modify-syntax-entry ?
! "." table
)
42 (modify-syntax-entry ?%
"." table
)
43 (modify-syntax-entry ?
& "." table
)
44 (modify-syntax-entry ?
* ". 23n" table
)
45 (modify-syntax-entry ?
+ "." table
)
46 (modify-syntax-entry ?-
"." table
)
47 (modify-syntax-entry ?
/ ". 124b" table
)
48 (modify-syntax-entry ?
< "." table
)
49 (modify-syntax-entry ?
= "." table
)
50 (modify-syntax-entry ?
> "." table
)
51 (modify-syntax-entry ??
"." table
)
52 (modify-syntax-entry ?
@ "." table
)
53 (modify-syntax-entry ?|
"." table
)
55 (modify-syntax-entry ?
: "." table
)
56 (modify-syntax-entry ?\
; "." table)
57 (modify-syntax-entry ?^
"." table
)
59 (modify-syntax-entry ?\
( "()" table
)
60 (modify-syntax-entry ?\
) ")(" table
)
61 (modify-syntax-entry ?\
[ "(]" table
)
62 (modify-syntax-entry ?\
] ")[" table
)
63 (modify-syntax-entry ?\
{ "(}" table
)
64 (modify-syntax-entry ?\
} "){" table
)
66 (modify-syntax-entry ?
\n "> b" table
)
67 ;; Give CR the same syntax as newline, for selective-display
68 (modify-syntax-entry ?\^m
"> b" table
)
72 (defun sclang-mode-make-menu (title)
73 (easy-menu-create-menu
76 ["Start Interpreter" sclang-start
:included
(not (sclang-library-initialized-p))]
77 ["Restart Interpreter" sclang-start
:included
(sclang-library-initialized-p)]
78 ["Recompile Class Library" sclang-recompile
:included
(sclang-library-initialized-p)]
79 ["Stop Interpreter" sclang-stop
:included
(sclang-get-process)]
80 ["Kill Interpreter" sclang-kill
:included
(sclang-get-process)]
82 ["Show Post Buffer" sclang-show-post-buffer
]
83 ["Clear Post Buffer" sclang-clear-post-buffer
]
85 ["Switch To Workspace" sclang-switch-to-workspace
]
87 ["Evaluate Region" sclang-eval-region
]
88 ["Evaluate Line" sclang-eval-region-or-line
]
89 ["Evaluate Defun" sclang-eval-defun
]
90 ["Evaluate Expression ..." sclang-eval-expression
]
91 ["Evaluate Document" sclang-eval-document
]
93 ["Find Definitions ..." sclang-find-definitions
]
94 ["Find References ..." sclang-find-references
]
95 ["Pop Mark" sclang-pop-definition-mark
]
96 ["Show Method Arguments" sclang-show-method-args
]
97 ["Complete keyword" sclang-complete-symbol
]
98 ["Dump Interface" sclang-dump-interface
]
99 ["Dump Full Interface" sclang-dump-full-interface
]
101 ["Index Help Topics" sclang-index-help-topics
]
102 ["Find Help ..." sclang-find-help
]
103 ["Switch to Help Browser" sclang-goto-help-browser
]
104 ["Open Help GUI" sclang-open-help-gui
]
106 ["Run Main" sclang-main-run
]
107 ["Stop Main" sclang-main-stop
]
108 ["Show Server Panels" sclang-show-server-panel
]
111 (defun sclang-fill-mode-map (map)
113 (define-key map
"\C-c\C-l" 'sclang-recompile
)
114 (define-key map
"\C-c\C-o" 'sclang-start
)
115 ;; post buffer control
116 (define-key map
"\C-c<" 'sclang-clear-post-buffer
)
117 (define-key map
"\C-c>" 'sclang-show-post-buffer
)
119 (define-key map
"\C-c\C-w" 'sclang-switch-to-workspace
)
121 (define-key map
"\C-c\C-c" 'sclang-eval-region-or-line
)
122 (define-key map
"\C-c\C-d" 'sclang-eval-region
)
123 (define-key map
"\C-\M-x" 'sclang-eval-defun
)
124 (define-key map
"\C-c\C-e" 'sclang-eval-expression
)
125 (define-key map
"\C-c\C-f" 'sclang-eval-document
)
126 ;; language information
127 (define-key map
"\C-c\C-n" 'sclang-complete-symbol
)
128 (define-key map
"\M-\t" 'sclang-complete-symbol
)
129 (define-key map
"\C-c:" 'sclang-find-definitions
)
130 (define-key map
"\C-c;" 'sclang-find-references
)
131 (define-key map
"\C-c}" 'sclang-pop-definition-mark
)
132 (define-key map
"\C-c\C-m" 'sclang-show-method-args
)
133 (define-key map
"\C-c{" 'sclang-dump-full-interface
)
134 (define-key map
"\C-c[" 'sclang-dump-interface
)
135 ;; documentation access
136 (define-key map
"\C-c\C-h" 'sclang-find-help
)
137 (define-key map
"\C-\M-h" 'sclang-goto-help-browser
)
138 (define-key map
"\C-c\C-y" 'sclang-open-help-gui
)
139 (define-key map
"\C-ch" 'sclang-find-help-in-gui
)
141 (define-key map
"\C-c\C-r" 'sclang-main-run
)
142 (define-key map
"\C-c\C-s" 'sclang-main-stop
)
143 (define-key map
"\C-c\C-p" 'sclang-show-server-panel
)
144 (define-key map
"\C-c\C-k" 'sclang-edit-dev-source
)
145 ;; electric characters
146 (define-key map
"}" 'sclang-electric-brace
)
147 (define-key map
")" 'sclang-electric-brace
)
148 (define-key map
"]" 'sclang-electric-brace
)
149 (define-key map
"/" 'sclang-electric-slash
)
150 (define-key map
"*" 'sclang-electric-star
)
152 (let ((title "SCLang"))
153 (define-key map
[menu-bar sclang
] (cons title
(sclang-mode-make-menu title
))))
157 ;; =====================================================================
159 ;; =====================================================================
161 (defconst sclang-font-lock-keyword-list
175 "*List of keywords to highlight in SCLang mode.")
177 (defconst sclang-font-lock-builtin-list
184 "*List of builtins to highlight in SCLang mode.")
186 (defconst sclang-font-lock-method-list
198 "*List of methods to highlight in SCLang mode.")
200 (defconst sclang-font-lock-error-list
209 "*List of methods signalling errors or warnings.")
211 (defvar sclang-font-lock-class-keywords nil
)
213 (defvar sclang-font-lock-keywords-1 nil
214 "Subdued level highlighting for SCLang mode.")
216 (defvar sclang-font-lock-keywords-2 nil
217 "Medium level highlighting for SCLang mode.")
219 (defvar sclang-font-lock-keywords-3 nil
220 "Gaudy level highlighting for SCLang mode.")
222 (defvar sclang-font-lock-keywords nil
223 "Default expressions to highlight in SCLang mode.")
225 (defconst sclang-font-lock-defaults
'((sclang-font-lock-keywords
226 sclang-font-lock-keywords-1
227 sclang-font-lock-keywords-2
228 sclang-font-lock-keywords-3
235 (defun sclang-font-lock-syntactic-face (state)
236 (cond ((eq (nth 3 state
) ?
')
238 'font-lock-constant-face
)
241 'font-lock-string-face
)
244 'font-lock-comment-face
)))
246 (defun sclang-font-lock-class-keyword-matcher (limit)
247 (let ((regexp (or sclang-font-lock-class-keywords
248 (concat "\\<" sclang-class-name-regexp
"\\>")))
249 (case-fold-search nil
))
250 (re-search-forward regexp limit t
)))
252 (defun sclang-set-font-lock-keywords ()
255 sclang-font-lock-keywords-1
258 (cons (regexp-opt sclang-font-lock-keyword-list
'words
)
259 'font-lock-keyword-face
)
261 (cons (regexp-opt sclang-font-lock-builtin-list
'words
)
262 'font-lock-builtin-face
)
263 ;; pi is a special case
264 (cons "\\<\\([0-9]+\\(\\.\\)\\)pi\\>" 'font-lock-builtin-face
)
266 (cons "\\s/\\s\\?." 'font-lock-constant-face
) ; characters
267 (cons (concat "\\\\\\(" sclang-symbol-regexp
"\\)")
268 'font-lock-constant-face
) ; symbols
271 sclang-font-lock-keywords-2
273 sclang-font-lock-keywords-1
276 (cons (concat "\\s'\\(" sclang-identifier-regexp
"\\)")
277 'font-lock-variable-name-face
) ; environment variables
278 (cons (concat "\\<\\(" sclang-identifier-regexp
"\\)\\>:") ; keyword arguments
279 'font-lock-variable-name-face
)
280 ;; method definitions
281 (cons sclang-method-definition-regexp
282 (list 1 'font-lock-function-name-face
))
284 (cons (regexp-opt sclang-font-lock-method-list
'words
)
285 'font-lock-function-name-face
)
287 (cons (regexp-opt sclang-font-lock-error-list
'words
)
288 'font-lock-warning-face
)
291 sclang-font-lock-keywords-3
293 sclang-font-lock-keywords-2
296 (cons 'sclang-font-lock-class-keyword-matcher
'font-lock-type-face
)
297 ;; (cons (concat "\\<" sclang-class-name-regexp "\\>") 'font-lock-type-face)
300 sclang-font-lock-keywords sclang-font-lock-keywords-1
303 (defun sclang-update-font-lock ()
304 "Update font-lock information in all sclang-mode buffers."
305 (setq sclang-font-lock-class-keywords
306 (and sclang-symbol-table
307 (let* ((list (remove-if
308 (lambda (x) (or (not (sclang-class-name-p x
))
309 (sclang-string-match "^Meta_" x
)))
310 sclang-symbol-table
))
311 ;; need to set this for large numbers of classes
312 (max-specpdl-size (* (length list
) 2)))
314 (concat "\\<\\(?:Meta_\\)?\\(?:" (regexp-opt list
) "\\)\\>")
317 ;; (dolist (buffer (buffer-list))
318 ;; (with-current-buffer buffer
319 ;; (and (eq major-mode 'sclang-mode)
320 ;; (eq t (car font-lock-keywords))
321 ;; (setq font-lock-keywords (cdr font-lock-keywords)))))
322 (if (eq major-mode
'sclang-mode
)
323 (font-lock-fontify-buffer)))
325 ;; =====================================================================
327 ;; =====================================================================
329 (defcustom sclang-indent-level
4
330 "*Indentation offset for SCLang statements."
334 (defun sclang-indent-line ()
335 "Indent current line as sclang code.
336 Return the amount the indentation changed by."
337 (let ((indent (calculate-sclang-indent))
339 (case-fold-search nil
)
340 (pos (- (point-max) (point))))
343 (skip-chars-forward " \t")
344 (setq shift-amt
(- indent
(current-column)))
345 (if (zerop shift-amt
)
346 (if (> (- (point-max) pos
) (point))
347 (goto-char (- (point-max) pos
)))
348 (delete-region beg
(point))
350 ;; if initial point was within line's indentation, position
351 ;; after the indentation, else stay at same point in text.
352 (if (> (- (point-max) pos
) (point))
353 (goto-char (- (point-max) pos
))))
356 (defun calculate-sclang-indent (&optional parse-start
)
357 "Return appropriate indentation for current line as sclang code.
358 Returns the column to indent to."
361 (let ((indent-point (point))
362 (case-fold-search nil
)
365 (goto-char parse-start
)
366 (beginning-of-defun))
367 (while (< (point) indent-point
)
368 (setq state
(parse-partial-sexp (point) indent-point
0)))
369 (let* ((containing-sexp (nth 1 state
))
370 (inside-string-p (nth 3 state
))
371 (inside-comment-p (nth 4 state
)))
372 (cond (inside-string-p
373 ;; inside string: no change
374 (current-indentation))
375 ((integerp inside-comment-p
)
377 (let ((base (if containing-sexp
379 (goto-char containing-sexp
)
380 (+ (current-indentation) sclang-indent-level
))
382 (offset (* sclang-indent-level
385 (back-to-indentation)
389 ((null containing-sexp
)
390 ;; top-level: no indentation
393 (back-to-indentation)
394 (let ((open-paren (and (looking-at "\\s)")
395 (matching-paren (char-after))))
396 (indent (current-indentation)))
397 (goto-char containing-sexp
)
398 (if (or (not open-paren
) (eq open-paren
(char-after)))
399 (cond ((progn (beginning-of-line) (looking-at sclang-block-regexp
)) 0)
400 (open-paren (current-indentation))
401 (t (+ (current-indentation) sclang-indent-level
)))
402 ;; paren mismatch: do nothing
405 ;; =====================================================================
406 ;; electric character commands
407 ;; =====================================================================
409 (defun sclang-electric-brace (arg)
411 (self-insert-command (prefix-numeric-value arg
))
414 (looking-at "\\s *\\s)"))
415 (indent-according-to-mode)))
417 (defun sclang-electric-slash (arg)
419 (let* ((char (char-before))
420 (indent-p (or (eq char ?
/)
422 (self-insert-command (prefix-numeric-value arg
))
423 (if indent-p
(indent-according-to-mode))))
425 (defun sclang-electric-star (arg)
427 (let ((indent-p (eq (char-before) ?
/)))
428 (self-insert-command (prefix-numeric-value arg
))
429 (if indent-p
(indent-according-to-mode))))
431 ;; =====================================================================
432 ;; document interface
433 ;; =====================================================================
435 (defvar sclang-document-id nil
)
436 (defvar sclang-document-state nil
)
437 (defvar sclang-document-envir nil
)
439 (defvar sclang-document-counter
0)
440 (defvar sclang-document-list nil
)
441 (defvar sclang-current-document nil
442 "Currently active document.")
444 (defvar sclang-document-idle-timer nil
)
446 (defconst sclang-document-property-map
447 '((sclang-document-name .
(prSetTitle (buffer-name)))
448 (sclang-document-path .
(prSetFileName (buffer-file-name)))
449 (sclang-document-listener-p .
(prSetIsListener (eq (current-buffer) (sclang-get-post-buffer))))
450 (sclang-document-editable-p .
(prSetEditable (not buffer-read-only
)))
451 (sclang-document-edited-p .
(prSetEdited (buffer-modified-p)))))
453 (defmacro sclang-next-document-id
()
454 `(incf sclang-document-counter
))
456 (defun sclang-document-list ()
457 sclang-document-list
)
459 (defun sclang-document-id (buffer)
460 (cdr (assq 'sclang-document-id
(buffer-local-variables buffer
))))
462 (defun sclang-document-p (buffer)
463 (integerp (sclang-document-id buffer
)))
465 (defmacro with-sclang-document
(buffer &rest body
)
466 `(when (sclang-document-p buffer
)
467 (with-current-buffer buffer
470 (defun sclang-get-document (id)
471 (find-if (lambda (doc) (eq id
(sclang-document-id doc
)))
472 (sclang-document-list)))
474 (defun sclang-init-document ()
475 (set (make-local-variable 'sclang-document-id
) (sclang-next-document-id))
476 (set (make-local-variable 'sclang-document-envir
) nil
)
477 (dolist (assoc sclang-document-property-map
)
478 (set (make-local-variable (car assoc
)) nil
))
479 (pushnew (current-buffer) sclang-document-list
))
481 (defun sclang-document-update-property-1 (assoc &optional force
)
483 (let* ((key (car assoc
))
485 (prev-value (eval key
))
486 (cur-value (eval (cadr prop
))))
487 (when (or force
(not (equal prev-value cur-value
)))
489 (sclang-perform-command-no-result
490 'documentSetProperty sclang-document-id
491 (car prop
) cur-value
)))))
493 (defun sclang-document-update-property (key &optional force
)
494 (sclang-document-update-property-1 (assq key sclang-document-property-map
) force
))
496 (defun sclang-document-update-properties (&optional force
)
497 (dolist (assoc sclang-document-property-map
)
498 (sclang-document-update-property-1 assoc force
)))
500 (defun sclang-make-document ()
501 (sclang-perform-command-no-result 'documentNew sclang-document-id
)
502 (sclang-document-update-properties t
))
504 (defun sclang-close-document (buffer)
505 (with-sclang-document
507 (setq sclang-document-list
(delq buffer sclang-document-list
))
508 (sclang-perform-command-no-result
509 'documentClosed sclang-document-id
)))
511 (defun sclang-set-current-document (buffer &optional force
)
512 (when (or force
(not (eq buffer sclang-current-document
)))
513 (setq sclang-current-document buffer
)
514 (sclang-perform-command-no-result 'documentSetCurrent
(sclang-document-id buffer
))
517 (defun sclang-document-library-startup-hook-function ()
518 (dolist (buffer (sclang-document-list))
519 (with-current-buffer buffer
520 (sclang-make-document)))
521 (sclang-set-current-document (current-buffer) t
))
523 (defun sclang-document-kill-buffer-hook-function ()
524 (sclang-close-document (current-buffer)))
526 (defun sclang-document-post-command-hook-function ()
527 (when (and (sclang-library-initialized-p)
528 (sclang-document-p (current-buffer)))
529 (sclang-document-update-properties))
530 (sclang-set-current-document (current-buffer)))
532 (defun sclang-document-change-major-mode-hook-function ()
533 (sclang-close-document (current-buffer)))
535 ;; =====================================================================
537 ;; =====================================================================
539 (sclang-set-command-handler
542 (multiple-value-bind (file-name region-start region-length
) arg
543 (let ((buffer (get-file-buffer file-name
)))
545 (setf buffer
(find-file-noselect file-name
)))
547 (unless (sclang-document-p buffer
)
548 (with-current-buffer buffer
(sclang-mode)))
549 (goto-char (max (point-min) (min (point-max) region-start
)))
550 ;; TODO: how to activate region in transient-mark-mode?
551 (sclang-document-id buffer
))))))
553 (sclang-set-command-handler
556 (multiple-value-bind (name str make-listener
) arg
557 (let ((buffer (generate-new-buffer name
)))
558 (with-current-buffer buffer
560 (set-buffer-modified-p nil
)
562 (sclang-document-id buffer
)))))
564 (sclang-set-command-handler
567 (let ((doc (and (integerp arg
) (sclang-get-document arg
))))
568 (and doc
(kill-buffer doc
)))
571 (sclang-set-command-handler
574 (multiple-value-bind (id name
) arg
576 (let ((doc (and (integerp id
) (sclang-get-document id
))))
578 (with-current-buffer doc
579 (rename-buffer name t
)
580 (sclang-document-update-property 'sclang-document-name
))))))
583 (sclang-set-command-handler
584 '_documentSetEditable
586 (multiple-value-bind (id flag
) arg
587 (let ((doc (and (integerp id
) (sclang-get-document id
))))
589 (with-current-buffer doc
590 (setq buffer-read-only
(not flag
))
591 (sclang-document-update-property 'sclang-editable-p
)))))
594 (sclang-set-command-handler
597 (let ((doc (and (integerp arg
) (sclang-get-document arg
))))
598 (and doc
(switch-to-buffer doc
)))
601 (sclang-set-command-handler
604 (multiple-value-bind (id str
) arg
605 (let ((doc (and (integerp id
) (sclang-get-document id
))))
607 (with-current-buffer doc
612 (sclang-set-command-handler
615 (let ((doc (and (integerp arg
) (sclang-get-document arg
))))
616 (and doc
(display-buffer doc
)))
619 ;; =====================================================================
621 ;; =====================================================================
623 (defun sclang-mode-set-local-variables ()
624 (set (make-local-variable 'require-final-newline
) nil
)
626 (set (make-local-variable 'indent-line-function
)
628 (set (make-local-variable 'tab-width
) 4)
629 (set (make-local-variable 'indent-tabs-mode
) t
)
630 ;; comment formatting
631 (set (make-local-variable 'comment-start
) "// ")
632 (set (make-local-variable 'comment-end
) "")
633 (set (make-local-variable 'comment-column
) 40)
634 (set (make-local-variable 'comment-start-skip
) "/\\*+ *\\|//+ *")
635 ;; "\\(^\\|\\s-\\);?// *")
636 (set (make-local-variable 'comment-multi-line
) t
)
637 ;; parsing and movement
638 (set (make-local-variable 'parse-sexp-ignore-comments
) t
)
639 (set (make-local-variable 'beginning-of-defun-function
)
640 'sclang-beginning-of-defun
)
641 (set (make-local-variable 'end-of-defun-function
)
642 'sclang-end-of-defun
)
643 ;; paragraph formatting
644 ;; (set (make-local-variable 'paragraph-start) (concat "$\\|" page-delimiter))
645 ;; mostly copied from c++-mode, seems to work
646 (set (make-local-variable 'paragraph-start
)
647 "[ \t]*\\(//+\\|\\**\\)[ \t]*$\\|^\f")
648 (set (make-local-variable 'paragraph-separate
) paragraph-start
)
649 (set (make-local-variable 'paragraph-ignore-fill-prefix
) t
)
650 (set (make-local-variable 'adaptive-fill-mode
) t
)
651 (set (make-local-variable 'adaptive-fill-regexp
)
652 "[ \t]*\\(//+\\|\\**\\)[ \t]*\\([ \t]*\\([-|#;>*]+[ \t]*\\|(?[0-9]+[.)][ \t]*\\)*\\)")
654 (set (make-local-variable 'font-lock-syntactic-face-function
)
655 'sclang-font-lock-syntactic-face
)
656 (set (make-local-variable 'font-lock-defaults
)
657 sclang-font-lock-defaults
)
661 (defvar sclang-mode-map
(sclang-fill-mode-map (make-sparse-keymap))
662 "Keymap used in SuperCollider mode.")
664 (defvar sclang-mode-syntax-table
(sclang-fill-syntax-table (make-syntax-table))
665 "Syntax table used in SuperCollider mode.")
667 (defcustom sclang-mode-hook nil
668 "*Hook run when entering SCLang mode."
672 (defun sclang-mode ()
673 "Major mode for editing SuperCollider language code.
677 (kill-all-local-variables)
678 (set-syntax-table sclang-mode-syntax-table
)
679 (use-local-map sclang-mode-map
)
680 (setq mode-name
"SCLang")
681 (setq major-mode
'sclang-mode
)
682 (sclang-mode-set-local-variables)
683 (sclang-set-font-lock-keywords)
684 (sclang-init-document)
685 (sclang-make-document)
686 (run-hooks 'sclang-mode-hook
))
688 ;; =====================================================================
689 ;; module initialization
690 ;; =====================================================================
692 (add-to-list 'auto-mode-alist
'("\\.\\(sc\\|scd\\)$" . sclang-mode
))
693 (add-to-list 'interpreter-mode-alist
'("sclang" . sclang-mode
))
695 (add-hook 'sclang-library-startup-hook
'sclang-document-library-startup-hook-function
)
696 (add-hook 'kill-buffer-hook
'sclang-document-kill-buffer-hook-function
)
697 (add-hook 'post-command-hook
'sclang-document-post-command-hook-function
)
698 (add-hook 'change-major-mode-hook
'sclang-document-change-major-mode-hook-function
)
700 (provide 'sclang-mode
)