From 19dfecc8ca2ec5b58e761ef272845cbb19d6f968 Mon Sep 17 00:00:00 2001 From: John Andrews Date: Mon, 16 Aug 2021 19:57:43 -0400 Subject: [PATCH] Revert "Combine sclang-mode into the main sclang file" This reverts commit c414b9c7abacd7b59ff9cae34e3334669b2d72cb. --- el/sclang-help.el | 1 + el/sclang-minor-mode.el | 1 + el/sclang-mode.el | 703 ++++++++++++++++++++++++++++++++++++++++ el/sclang-server.el | 1 + el/sclang-util.el | 2 +- el/sclang.el | 702 +-------------------------------------- 6 files changed, 723 insertions(+), 687 deletions(-) create mode 100644 el/sclang-mode.el diff --git a/el/sclang-help.el b/el/sclang-help.el index 8580d45..46e1c1a 100644 --- a/el/sclang-help.el +++ b/el/sclang-help.el @@ -23,6 +23,7 @@ (require 'sclang-util) (require 'sclang-interp) (require 'sclang-language) +(require 'sclang-mode) (require 'sclang-vars nil 'ignore-missing-file) (require 'sclang-minor-mode) diff --git a/el/sclang-minor-mode.el b/el/sclang-minor-mode.el index 98b4e13..c5e2a47 100644 --- a/el/sclang-minor-mode.el +++ b/el/sclang-minor-mode.el @@ -17,6 +17,7 @@ ;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA (require 'sclang-util) +(require 'sclang-mode) (easy-mmode-define-minor-mode sclang-minor-mode "Toggle sclang-minor-mode. diff --git a/el/sclang-mode.el b/el/sclang-mode.el new file mode 100644 index 0000000..0f42491 --- /dev/null +++ b/el/sclang-mode.el @@ -0,0 +1,703 @@ +;; copyright 2003-2005 stefan kersten +;; +;; 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. +;; +;; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +;; USA + +;;; Code: + +(require 'cl-lib) + +;; Make byte-compiler happy by declaring external functions and +;; variables. +(declare-function company-mode "ext:company") +(defvar company-backends) + +(require 'font-lock) +(require 'sclang-util) +(require 'sclang-interp) +(require 'sclang-language) +(require 'sclang-dev) + +(defun sclang-fill-syntax-table (table) + ;; string + (modify-syntax-entry ?\" "\"" table) + (modify-syntax-entry ?\' "\"" table) ; no string syntax class for single quotes + ;; expression prefix + (modify-syntax-entry ?~ "'" table) + ;; escape + (modify-syntax-entry ?\\ "\\" table) + ;; character quote + (modify-syntax-entry ?$ "/" table) + ;; symbol + (modify-syntax-entry ?_ "_" table) + ;; symbol/punctuation + (modify-syntax-entry ?! "." table) + (modify-syntax-entry ?% "." table) + (modify-syntax-entry ?& "." table) + (modify-syntax-entry ?* ". 23n" table) + (modify-syntax-entry ?+ "." table) + (modify-syntax-entry ?- "." table) + (modify-syntax-entry ?/ ". 124b" table) + (modify-syntax-entry ?< "." table) + (modify-syntax-entry ?= "." table) + (modify-syntax-entry ?> "." table) + (modify-syntax-entry ?? "." table) + (modify-syntax-entry ?@ "." table) + (modify-syntax-entry ?| "." table) + ;; punctuation + (modify-syntax-entry ?: "." table) + (modify-syntax-entry ?\; "." table) + (modify-syntax-entry ?^ "." table) + ;; parenthesis + (modify-syntax-entry ?\( "()" table) + (modify-syntax-entry ?\) ")(" table) + (modify-syntax-entry ?\[ "(]" table) + (modify-syntax-entry ?\] ")[" table) + (modify-syntax-entry ?\{ "(}" table) + (modify-syntax-entry ?\} "){" table) + ;; comment end + (modify-syntax-entry ?\n "> b" table) + ;; Give CR the same syntax as newline, for selective-display + (modify-syntax-entry ?\^m "> b" table) + ;; return table + table) + +(defun sclang-mode-make-menu (title) + (easy-menu-create-menu + title + '( + ["Start Interpreter" sclang-start :included (not (sclang-library-initialized-p))] + ["Restart Interpreter" sclang-start :included (sclang-library-initialized-p)] + ["Recompile Class Library" sclang-recompile :included (sclang-library-initialized-p)] + ["Stop Interpreter" sclang-stop :included (sclang-get-process)] + ["Kill Interpreter" sclang-kill :included (sclang-get-process)] + "-" + ["Show Post Buffer" sclang-show-post-buffer] + ["Clear Post Buffer" sclang-clear-post-buffer] + "-" + ["Switch To Workspace" sclang-switch-to-workspace] + "-" + ["Evaluate Region" sclang-eval-region] + ["Evaluate Line" sclang-eval-region-or-line] + ["Evaluate Defun" sclang-eval-defun] + ["Evaluate Expression ..." sclang-eval-expression] + ["Evaluate Document" sclang-eval-document] + "-" + ["Find Definitions ..." sclang-find-definitions] + ["Find References ..." sclang-find-references] + ["Pop Mark" sclang-pop-definition-mark] + ["Show Method Arguments" sclang-show-method-args] + ["Complete keyword" sclang-complete-symbol] + ["Dump Interface" sclang-dump-interface] + ["Dump Full Interface" sclang-dump-full-interface] + "-" + ["Index Help Topics" sclang-index-help-topics] + ["Find Help ..." sclang-find-help] + ["Switch to Help Browser" sclang-goto-help-browser] + ["Open Help GUI" sclang-open-help-gui] + "-" + ["Run Main" sclang-main-run] + ["Stop Main" sclang-main-stop] + ["Show Server Panels" sclang-show-server-panel] + ))) + +(defun sclang-fill-mode-map (map) + ;; process control + (define-key map "\C-c\C-l" 'sclang-recompile) + (define-key map "\C-c\C-o" 'sclang-start) + ;; post buffer control + (define-key map "\C-c<" 'sclang-clear-post-buffer) + (define-key map "\C-c>" 'sclang-show-post-buffer) + ;; workspace access + (define-key map "\C-c\C-w" 'sclang-switch-to-workspace) + ;; code evaluation + (define-key map "\C-c\C-c" 'sclang-eval-region-or-line) + (define-key map "\C-c\C-d" 'sclang-eval-region) + (define-key map "\C-\M-x" 'sclang-eval-defun) + (define-key map "\C-c\C-e" 'sclang-eval-expression) + (define-key map "\C-c\C-f" 'sclang-eval-document) + ;; language information + (define-key map "\C-c\C-n" 'sclang-complete-symbol) + (define-key map "\C-c:" 'sclang-find-definitions) + (define-key map "\C-c;" 'sclang-find-references) + (define-key map "\C-c}" 'sclang-pop-definition-mark) + (define-key map "\C-c\C-m" 'sclang-show-method-args) + (define-key map "\C-c{" 'sclang-dump-full-interface) + (define-key map "\C-c[" 'sclang-dump-interface) + ;; documentation access + (define-key map "\C-c\C-h" 'sclang-find-help) + (define-key map "\C-\M-h" 'sclang-goto-help-browser) + (define-key map "\C-c\C-y" 'sclang-open-help-gui) + (define-key map "\C-ch" 'sclang-find-help-in-gui) + ;; language control + (define-key map "\C-c\C-r" 'sclang-main-run) + (define-key map "\C-c\C-s" 'sclang-main-stop) + (define-key map "\C-c\C-p" 'sclang-show-server-panel) + (define-key map "\C-c\C-k" 'sclang-edit-dev-source) + ;; electric characters + (define-key map "}" 'sclang-electric-brace) + (define-key map ")" 'sclang-electric-brace) + (define-key map "]" 'sclang-electric-brace) + (define-key map "/" 'sclang-electric-slash) + (define-key map "*" 'sclang-electric-star) + ;; menu + (let ((title "SCLang")) + (define-key map [menu-bar sclang] (cons title (sclang-mode-make-menu title)))) + ;; return map + map) + +;; ===================================================================== +;; font-lock support +;; ===================================================================== + +(defconst sclang-font-lock-keyword-list + '( + "arg" + "classvar" + "const" + "super" + "this" + "thisFunction" + "thisFunctionDef" + "thisMethod" + "thisProcess" + "thisThread" + "var" + ) + "*List of keywords to highlight in SCLang mode.") + +(defconst sclang-font-lock-builtin-list + '( + "false" + "inf" + "nil" + "true" + ) + "*List of builtins to highlight in SCLang mode.") + +(defconst sclang-font-lock-method-list + '( + "ar" + "for" + "forBy" + "if" + "ir" + "kr" + "tr" + "loop" + "while" + ) + "*List of methods to highlight in SCLang mode.") + +(defconst sclang-font-lock-error-list + '( + "die" + "error" + "exit" + "halt" + "verboseHalt" + "warn" + ) + "*List of methods signalling errors or warnings.") + +(defvar sclang-font-lock-class-keywords nil) + +(defvar sclang-font-lock-keywords-1 nil + "Subdued level highlighting for SCLang mode.") + +(defvar sclang-font-lock-keywords-2 nil + "Medium level highlighting for SCLang mode.") + +(defvar sclang-font-lock-keywords-3 nil + "Gaudy level highlighting for SCLang mode.") + +(defvar sclang-font-lock-keywords nil + "Default expressions to highlight in SCLang mode.") + +(defconst sclang-font-lock-defaults '((sclang-font-lock-keywords + sclang-font-lock-keywords-1 + sclang-font-lock-keywords-2 + sclang-font-lock-keywords-3 + ) + nil nil + nil + beginning-of-defun + )) + +(defun sclang-font-lock-syntactic-face (state) + (cond ((eq (nth 3 state) ?') + ;; symbol + 'font-lock-constant-face) + ((nth 3 state) + ;; string + 'font-lock-string-face) + ((nth 4 state) + ;; comment + 'font-lock-comment-face))) + +(defun sclang-font-lock-class-keyword-matcher (limit) + (let ((regexp (concat "\\<" sclang-class-name-regexp "\\>")) + (case-fold-search nil) + (continue t) + (res nil)) + (while continue + (setq res (re-search-forward regexp limit t)) + (if (or (null res) (null sclang-class-list)) + (setq continue nil) + (let ((thing (thing-at-point 'word))) + (if (null thing) + (setq res nil continue nil) + (when (cl-position (substring-no-properties thing) sclang-class-list :test 'equal) + (setq continue nil)))))) + res)) + +(defun sclang-set-font-lock-keywords () + (setq + ;; level 1 + sclang-font-lock-keywords-1 + (list + ;; keywords + (cons (regexp-opt sclang-font-lock-keyword-list 'words) + 'font-lock-keyword-face) + ;; builtins + (cons (regexp-opt sclang-font-lock-builtin-list 'words) + 'font-lock-builtin-face) + ;; pi is a special case + (cons "\\<\\([0-9]+\\(\\.\\)\\)pi\\>" 'font-lock-builtin-face) + ;; constants + (cons "\\s/\\s\\?." 'font-lock-constant-face) ; characters + (cons (concat "\\\\\\(" sclang-symbol-regexp "\\)") + 'font-lock-constant-face) ; symbols + ) + ;; level 2 + sclang-font-lock-keywords-2 + (append + sclang-font-lock-keywords-1 + (list + ;; variables + (cons (concat "\\s'\\(" sclang-identifier-regexp "\\)") + 'font-lock-variable-name-face) ; environment variables + (cons (concat "\\<\\(" sclang-identifier-regexp "\\)\\>:") ; keyword arguments + 'font-lock-variable-name-face) + ;; method definitions + (cons sclang-method-definition-regexp + (list 1 'font-lock-function-name-face)) + ;; methods + (cons (regexp-opt sclang-font-lock-method-list 'words) + 'font-lock-function-name-face) + ;; errors + (cons (regexp-opt sclang-font-lock-error-list 'words) + 'font-lock-warning-face) + )) + ;; level 3 + sclang-font-lock-keywords-3 + (append + sclang-font-lock-keywords-2 + (list + ;; classes + (cons 'sclang-font-lock-class-keyword-matcher 'font-lock-type-face) +;; (cons (concat "\\<" sclang-class-name-regexp "\\>") 'font-lock-type-face) + )) + ;; default level + sclang-font-lock-keywords sclang-font-lock-keywords-1 + )) + +(defun sclang-update-font-lock () + "Update font-lock information in all sclang-mode buffers." + ;; too expensive + ;; (dolist (buffer (buffer-list)) + ;; (with-current-buffer buffer + ;; (and (eq major-mode 'sclang-mode) + ;; (eq t (car font-lock-keywords)) + ;; (setq font-lock-keywords (cdr font-lock-keywords))))) + (if (eq major-mode 'sclang-mode) + (font-lock-fontify-buffer))) + +;; ===================================================================== +;; indentation +;; ===================================================================== + +(defcustom sclang-indent-level 4 + "*Indentation offset for SCLang statements." + :group 'sclang-mode + :type 'integer) + +(defun sclang-indent-line () + "Indent current line as sclang code. +Return the amount the indentation changed by." + (let ((indent (calculate-sclang-indent)) + beg shift-amt + (case-fold-search nil) + (pos (- (point-max) (point)))) + (beginning-of-line) + (setq beg (point)) + (skip-chars-forward " \t") + (setq shift-amt (- indent (current-column))) + (if (zerop shift-amt) + (if (> (- (point-max) pos) (point)) + (goto-char (- (point-max) pos))) + (delete-region beg (point)) + (indent-to indent) + ;; if initial point was within line's indentation, position + ;; after the indentation, else stay at same point in text. + (if (> (- (point-max) pos) (point)) + (goto-char (- (point-max) pos)))) + shift-amt)) + +(defun calculate-sclang-indent (&optional parse-start) + "Return appropriate indentation for current line as sclang code. +Returns the column to indent to." + (save-excursion + (beginning-of-line) + (let ((indent-point (point)) + (case-fold-search nil) + state) + (if parse-start + (goto-char parse-start) + (beginning-of-defun)) + (while (< (point) indent-point) + (setq state (parse-partial-sexp (point) indent-point 0))) + (let* ((containing-sexp (nth 1 state)) + (inside-string-p (nth 3 state)) + (inside-comment-p (nth 4 state))) + (cond (inside-string-p + ;; inside string: no change + (current-indentation)) + ((integerp inside-comment-p) + ;; inside comment + (let ((base (if containing-sexp + (save-excursion + (goto-char containing-sexp) + (+ (current-indentation) sclang-indent-level)) + 0)) + (offset (* sclang-indent-level + (- inside-comment-p + (if (save-excursion + (back-to-indentation) + (looking-at "\\*/")) + 1 0))))) + (+ base offset))) + ((null containing-sexp) + ;; top-level: no indentation + 0) + (t + (back-to-indentation) + (let ((open-paren (and (looking-at "\\s)") + (matching-paren (char-after)))) + (indent (current-indentation))) + (goto-char containing-sexp) + (if (or (not open-paren) (eq open-paren (char-after))) + (cond ((progn (beginning-of-line) (looking-at sclang-block-regexp)) 0) + (open-paren (current-indentation)) + (t (+ (current-indentation) sclang-indent-level))) + ;; paren mismatch: do nothing + indent)))))))) + +;; ===================================================================== +;; electric character commands +;; ===================================================================== + +(defun sclang-electric-brace (arg) + (interactive "*P") + (self-insert-command (prefix-numeric-value arg)) + (and (save-excursion + (beginning-of-line) + (looking-at "\\s *\\s)")) + (indent-according-to-mode))) + +(defun sclang-electric-slash (arg) + (interactive "*P") + (let* ((char (char-before)) + (indent-p (or (eq char ?/) + (eq char ?*)))) + (self-insert-command (prefix-numeric-value arg)) + (if indent-p (indent-according-to-mode)))) + +(defun sclang-electric-star (arg) + (interactive "*P") + (let ((indent-p (eq (char-before) ?/))) + (self-insert-command (prefix-numeric-value arg)) + (if indent-p (indent-according-to-mode)))) + +;; ===================================================================== +;; document interface +;; ===================================================================== + +(defvar sclang-document-id nil) +(defvar sclang-document-state nil) +(defvar sclang-document-envir nil) + +(defvar sclang-document-counter 0) +(defvar sclang-document-list nil) +(defvar sclang-current-document nil + "Currently active document.") + +(defvar sclang-document-idle-timer nil) + +(defconst sclang-document-property-map + '((sclang-document-name . (prSetTitle (buffer-name))) + (sclang-document-path . (prSetFileName (buffer-file-name))) + (sclang-document-listener-p . (prSetIsListener (eq (current-buffer) (sclang-get-post-buffer)))) + (sclang-document-editable-p . (prSetEditable (not buffer-read-only))) + (sclang-document-edited-p . (prSetEdited (buffer-modified-p))))) + +(defmacro sclang-next-document-id () + `(cl-incf sclang-document-counter)) + +(defun sclang-document-id (buffer) + (cdr (assq 'sclang-document-id (buffer-local-variables buffer)))) + +(defun sclang-document-p (buffer) + (integerp (sclang-document-id buffer))) + +(defmacro with-sclang-document (buffer &rest body) + `(when (sclang-document-p buffer) + (with-current-buffer buffer + ,@body))) + +(defun sclang-get-document (id) + (cl-find-if (lambda (buffer) (eq id (sclang-document-id buffer))) + sclang-document-list)) + +(defun sclang-init-document () + (set (make-local-variable 'sclang-document-id) (sclang-next-document-id)) + (set (make-local-variable 'sclang-document-envir) nil) + (dolist (assoc sclang-document-property-map) + (set (make-local-variable (car assoc)) nil)) + (cl-pushnew (current-buffer) sclang-document-list)) + +(defun sclang-document-update-property-1 (assoc &optional force) + (when (consp assoc) + (let* ((key (car assoc)) + (prop (cdr assoc)) + (prev-value (eval key)) + (cur-value (eval (cadr prop)))) + (when (or force (not (equal prev-value cur-value))) + (set key cur-value) + (sclang-perform-command-no-result + 'documentSetProperty sclang-document-id + (car prop) cur-value))))) + +(defun sclang-document-update-property (key &optional force) + (sclang-document-update-property-1 (assq key sclang-document-property-map) force)) + +(defun sclang-document-update-properties (&optional force) + (dolist (assoc sclang-document-property-map) + (sclang-document-update-property-1 assoc force))) + +(defun sclang-make-document () + (sclang-perform-command-no-result 'documentNew sclang-document-id) + (sclang-document-update-properties t)) + +(defun sclang-close-document (buffer) + (with-sclang-document + buffer + (setq sclang-document-list (delq buffer sclang-document-list)) + (sclang-perform-command-no-result + 'documentClosed sclang-document-id))) + +(defun sclang-set-current-document (buffer &optional force) + (when (or force (not (eq buffer sclang-current-document))) + (setq sclang-current-document buffer) + (sclang-perform-command-no-result 'documentSetCurrent (sclang-document-id buffer)) + t)) + +(defun sclang-document-library-startup-hook-function () + (dolist (buffer sclang-document-list) + (with-current-buffer buffer + (sclang-make-document))) + (sclang-set-current-document (current-buffer) t)) + +(defun sclang-document-kill-buffer-hook-function () + (sclang-close-document (current-buffer))) + +(defun sclang-document-post-command-hook-function () + (when (and (sclang-library-initialized-p) + (sclang-document-p (current-buffer))) + (sclang-document-update-properties)) + (sclang-set-current-document (current-buffer))) + +(defun sclang-document-change-major-mode-hook-function () + (sclang-close-document (current-buffer))) + +;; ===================================================================== +;; command handlers +;; ===================================================================== + +(sclang-set-command-handler + '_documentOpen + (lambda (arg) + (cl-multiple-value-bind (file-name region-start region-length) arg + (let ((buffer (get-file-buffer file-name))) + (unless buffer + (setf buffer (find-file-noselect file-name))) + (when buffer + (unless (sclang-document-p buffer) + (with-current-buffer buffer (sclang-mode))) + (goto-char (max (point-min) (min (point-max) region-start))) + ;; TODO: how to activate region in transient-mark-mode? + (sclang-document-id buffer)))))) + +(sclang-set-command-handler + '_documentNew + (lambda (arg) + (cl-multiple-value-bind (name str make-listener) arg + (let ((buffer (generate-new-buffer name))) + (with-current-buffer buffer + (insert str) + (set-buffer-modified-p nil) + (sclang-mode)) + (sclang-document-id buffer))))) + +(sclang-set-command-handler + '_documentClose + (lambda (arg) + (let ((doc (and (integerp arg) (sclang-get-document arg)))) + (and doc (kill-buffer doc))) + nil)) + +(sclang-set-command-handler + '_documentRename + (lambda (arg) + (cl-multiple-value-bind (id name) arg + (when (stringp name) + (let ((doc (and (integerp id) (sclang-get-document id)))) + (when doc + (with-current-buffer doc + (rename-buffer name t) + (sclang-document-update-property 'sclang-document-name)))))) + nil)) + +(sclang-set-command-handler + '_documentSetEditable + (lambda (arg) + (cl-multiple-value-bind (id flag) arg + (let ((doc (and (integerp id) (sclang-get-document id)))) + (when doc + (with-current-buffer doc + (setq buffer-read-only (not flag)) + (sclang-document-update-property 'sclang-editable-p))))) + nil)) + +(sclang-set-command-handler + '_documentSwitchTo + (lambda (arg) + (let ((doc (and (integerp arg) (sclang-get-document arg)))) + (and doc (switch-to-buffer doc))) + nil)) + +(sclang-set-command-handler + '_documentPutString +(lambda (arg) + (cl-multiple-value-bind (id str) arg + (let ((doc (and (integerp id) (sclang-get-document id)))) + (when doc + (with-current-buffer doc + (insert str) + ) + nil))))) + +(sclang-set-command-handler + '_documentPopTo + (lambda (arg) + (let ((doc (and (integerp arg) (sclang-get-document arg)))) + (and doc (display-buffer doc))) + nil)) + +;; ===================================================================== +;; sclang-mode +;; ===================================================================== + +(defun sclang-mode-set-local-variables () + (set (make-local-variable 'require-final-newline) nil) + ;; indentation + (set (make-local-variable 'indent-line-function) + 'sclang-indent-line) + (set (make-local-variable 'tab-width) 4) + (set (make-local-variable 'indent-tabs-mode) t) + ;; comment formatting + (set (make-local-variable 'comment-start) "// ") + (set (make-local-variable 'comment-end) "") + (set (make-local-variable 'comment-column) 40) + (set (make-local-variable 'comment-start-skip) "/\\*+ *\\|//+ *") + ;; "\\(^\\|\\s-\\);?// *") + (set (make-local-variable 'comment-multi-line) t) + ;; parsing and movement + (set (make-local-variable 'parse-sexp-ignore-comments) t) + (set (make-local-variable 'beginning-of-defun-function) + 'sclang-beginning-of-defun) + (set (make-local-variable 'end-of-defun-function) + 'sclang-end-of-defun) + ;; paragraph formatting + ;; (set (make-local-variable 'paragraph-start) (concat "$\\|" page-delimiter)) + ;; mostly copied from c++-mode, seems to work + (set (make-local-variable 'paragraph-start) + "[ \t]*\\(//+\\|\\**\\)[ \t]*$\\|^ ") + (set (make-local-variable 'paragraph-separate) paragraph-start) + (set (make-local-variable 'paragraph-ignore-fill-prefix) t) + (set (make-local-variable 'adaptive-fill-mode) t) + (set (make-local-variable 'adaptive-fill-regexp) + "[ \t]*\\(//+\\|\\**\\)[ \t]*\\([ \t]*\\([-|#;>*]+[ \t]*\\|(?[0-9]+[.)][ \t]*\\)*\\)") + ;; font lock + (set (make-local-variable 'font-lock-syntactic-face-function) + 'sclang-font-lock-syntactic-face) + (set (make-local-variable 'font-lock-defaults) + sclang-font-lock-defaults) + ;; --- + nil) + +(defvar sclang-mode-map (sclang-fill-mode-map (make-sparse-keymap)) + "Keymap used in SuperCollider mode.") + +(defvar sclang-mode-syntax-table (sclang-fill-syntax-table (make-syntax-table)) + "Syntax table used in SuperCollider mode.") + +(defcustom sclang-mode-hook nil + "*Hook run when entering SCLang mode." + :group 'sclang-mode + :type 'hook) + +;;;###autoload +(define-derived-mode sclang-mode prog-mode "SCLang" + "Major mode for editing SuperCollider language code. +\\{sclang-mode-map}" + :group 'sclang + :syntax-table sclang-mode-syntax-table + (sclang-mode-set-local-variables) + (sclang-set-font-lock-keywords) + (sclang-init-document) + (sclang-make-document) + + ;; Setup completion + (add-hook 'completion-at-point-functions + #'sclang-completion-at-point nil 'local) + (when (fboundp 'company-mode) + (add-to-list 'company-backends 'company-capf))) + +;; ===================================================================== +;; module initialization +;; ===================================================================== + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.scd?\\'" . sclang-mode)) +(add-to-list 'interpreter-mode-alist '("sclang" . sclang-mode)) + +(add-hook 'sclang-library-startup-hook 'sclang-document-library-startup-hook-function) +(add-hook 'kill-buffer-hook 'sclang-document-kill-buffer-hook-function) +(add-hook 'post-command-hook 'sclang-document-post-command-hook-function) +(add-hook 'change-major-mode-hook 'sclang-document-change-major-mode-hook-function) + +(provide 'sclang-mode) +;;; sclang-mode ends here diff --git a/el/sclang-server.el b/el/sclang-server.el index f2bfa27..375c492 100644 --- a/el/sclang-server.el +++ b/el/sclang-server.el @@ -19,6 +19,7 @@ (require 'sclang-util) (require 'sclang-interp) (require 'sclang-language) +(require 'sclang-mode) (defcustom sclang-server-panel "Server.default.makeWindow" "Expression to execute when `sclang-show-server-panel' is invoked." diff --git a/el/sclang-util.el b/el/sclang-util.el index 7c33d35..ea104cb 100644 --- a/el/sclang-util.el +++ b/el/sclang-util.el @@ -83,4 +83,4 @@ (provide 'sclang-util) -;; EOF +;; EOF \ No newline at end of file diff --git a/el/sclang.el b/el/sclang.el index 8f6d990..9bbedcc 100644 --- a/el/sclang.el +++ b/el/sclang.el @@ -26,24 +26,6 @@ ;; for more information. ;;; Code: - -(require 'cl-lib) -(require 'font-lock) -(require 'sclang-util) -(require 'sclang-browser) -(require 'sclang-interp) -(require 'sclang-language) -(require 'sclang-document) -(require 'sclang-minor-mode) -(require 'sclang-help) -(require 'sclang-server) -(require 'sclang-widgets) - -;; Make byte-compiler happy by declaring external functions and -;; variables. -(declare-function company-mode "ext:company") -(defvar company-backends) - (defgroup sclang nil "IDE for working with the SuperCollider language." :group 'languages) @@ -73,674 +55,22 @@ (interactive) (customize-group 'sclang)) -(defun sclang-fill-syntax-table (table) - ;; string - (modify-syntax-entry ?\" "\"" table) - (modify-syntax-entry ?\' "\"" table) ; no string syntax class for single quotes - ;; expression prefix - (modify-syntax-entry ?~ "'" table) - ;; escape - (modify-syntax-entry ?\\ "\\" table) - ;; character quote - (modify-syntax-entry ?$ "/" table) - ;; symbol - (modify-syntax-entry ?_ "_" table) - ;; symbol/punctuation - (modify-syntax-entry ?! "." table) - (modify-syntax-entry ?% "." table) - (modify-syntax-entry ?& "." table) - (modify-syntax-entry ?* ". 23n" table) - (modify-syntax-entry ?+ "." table) - (modify-syntax-entry ?- "." table) - (modify-syntax-entry ?/ ". 124b" table) - (modify-syntax-entry ?< "." table) - (modify-syntax-entry ?= "." table) - (modify-syntax-entry ?> "." table) - (modify-syntax-entry ?? "." table) - (modify-syntax-entry ?@ "." table) - (modify-syntax-entry ?| "." table) - ;; punctuation - (modify-syntax-entry ?: "." table) - (modify-syntax-entry ?\; "." table) - (modify-syntax-entry ?^ "." table) - ;; parenthesis - (modify-syntax-entry ?\( "()" table) - (modify-syntax-entry ?\) ")(" table) - (modify-syntax-entry ?\[ "(]" table) - (modify-syntax-entry ?\] ")[" table) - (modify-syntax-entry ?\{ "(}" table) - (modify-syntax-entry ?\} "){" table) - ;; comment end - (modify-syntax-entry ?\n "> b" table) - ;; Give CR the same syntax as newline, for selective-display - (modify-syntax-entry ?\^m "> b" table) - ;; return table - table) - -(defun sclang-mode-make-menu (title) - (easy-menu-create-menu - title - '( - ["Start Interpreter" sclang-start :included (not (sclang-library-initialized-p))] - ["Restart Interpreter" sclang-start :included (sclang-library-initialized-p)] - ["Recompile Class Library" sclang-recompile :included (sclang-library-initialized-p)] - ["Stop Interpreter" sclang-stop :included (sclang-get-process)] - ["Kill Interpreter" sclang-kill :included (sclang-get-process)] - "-" - ["Show Post Buffer" sclang-show-post-buffer] - ["Clear Post Buffer" sclang-clear-post-buffer] - "-" - ["Switch To Workspace" sclang-switch-to-workspace] - "-" - ["Evaluate Region" sclang-eval-region] - ["Evaluate Line" sclang-eval-region-or-line] - ["Evaluate Defun" sclang-eval-defun] - ["Evaluate Expression ..." sclang-eval-expression] - ["Evaluate Document" sclang-eval-document] - "-" - ["Find Definitions ..." sclang-find-definitions] - ["Find References ..." sclang-find-references] - ["Pop Mark" sclang-pop-definition-mark] - ["Show Method Arguments" sclang-show-method-args] - ["Complete keyword" sclang-complete-symbol] - ["Dump Interface" sclang-dump-interface] - ["Dump Full Interface" sclang-dump-full-interface] - "-" - ["Index Help Topics" sclang-index-help-topics] - ["Find Help ..." sclang-find-help] - ["Switch to Help Browser" sclang-goto-help-browser] - ["Open Help GUI" sclang-open-help-gui] - "-" - ["Run Main" sclang-main-run] - ["Stop Main" sclang-main-stop] - ["Show Server Panels" sclang-show-server-panel] - ))) - -(defun sclang-fill-mode-map (map) - ;; process control - (define-key map "\C-c\C-l" 'sclang-recompile) - (define-key map "\C-c\C-o" 'sclang-start) - ;; post buffer control - (define-key map "\C-c<" 'sclang-clear-post-buffer) - (define-key map "\C-c>" 'sclang-show-post-buffer) - ;; workspace access - (define-key map "\C-c\C-w" 'sclang-switch-to-workspace) - ;; code evaluation - (define-key map "\C-c\C-c" 'sclang-eval-region-or-line) - (define-key map "\C-c\C-d" 'sclang-eval-region) - (define-key map "\C-\M-x" 'sclang-eval-defun) - (define-key map "\C-c\C-e" 'sclang-eval-expression) - (define-key map "\C-c\C-f" 'sclang-eval-document) - ;; language information - (define-key map "\C-c\C-n" 'sclang-complete-symbol) - (define-key map "\C-c:" 'sclang-find-definitions) - (define-key map "\C-c;" 'sclang-find-references) - (define-key map "\C-c}" 'sclang-pop-definition-mark) - (define-key map "\C-c\C-m" 'sclang-show-method-args) - (define-key map "\C-c{" 'sclang-dump-full-interface) - (define-key map "\C-c[" 'sclang-dump-interface) - ;; documentation access - (define-key map "\C-c\C-h" 'sclang-find-help) - (define-key map "\C-\M-h" 'sclang-goto-help-browser) - (define-key map "\C-c\C-y" 'sclang-open-help-gui) - (define-key map "\C-ch" 'sclang-find-help-in-gui) - ;; language control - (define-key map "\C-c\C-r" 'sclang-main-run) - (define-key map "\C-c\C-s" 'sclang-main-stop) - (define-key map "\C-c\C-p" 'sclang-show-server-panel) - (define-key map "\C-c\C-k" 'sclang-edit-dev-source) - ;; electric characters - (define-key map "}" 'sclang-electric-brace) - (define-key map ")" 'sclang-electric-brace) - (define-key map "]" 'sclang-electric-brace) - (define-key map "/" 'sclang-electric-slash) - (define-key map "*" 'sclang-electric-star) - ;; menu - (let ((title "SCLang")) - (define-key map [menu-bar sclang] (cons title (sclang-mode-make-menu title)))) - ;; return map - map) - -;; ===================================================================== -;; font-lock support -;; ===================================================================== - -(defconst sclang-font-lock-keyword-list - '( - "arg" - "classvar" - "const" - "super" - "this" - "thisFunction" - "thisFunctionDef" - "thisMethod" - "thisProcess" - "thisThread" - "var" - ) - "*List of keywords to highlight in SCLang mode.") - -(defconst sclang-font-lock-builtin-list - '( - "false" - "inf" - "nil" - "true" - ) - "*List of builtins to highlight in SCLang mode.") - -(defconst sclang-font-lock-method-list - '( - "ar" - "for" - "forBy" - "if" - "ir" - "kr" - "tr" - "loop" - "while" - ) - "*List of methods to highlight in SCLang mode.") - -(defconst sclang-font-lock-error-list - '( - "die" - "error" - "exit" - "halt" - "verboseHalt" - "warn" - ) - "*List of methods signalling errors or warnings.") - -(defvar sclang-font-lock-class-keywords nil) - -(defvar sclang-font-lock-keywords-1 nil - "Subdued level highlighting for SCLang mode.") - -(defvar sclang-font-lock-keywords-2 nil - "Medium level highlighting for SCLang mode.") - -(defvar sclang-font-lock-keywords-3 nil - "Gaudy level highlighting for SCLang mode.") - -(defvar sclang-font-lock-keywords nil - "Default expressions to highlight in SCLang mode.") - -(defconst sclang-font-lock-defaults '((sclang-font-lock-keywords - sclang-font-lock-keywords-1 - sclang-font-lock-keywords-2 - sclang-font-lock-keywords-3 - ) - nil nil - nil - beginning-of-defun - )) - -(defun sclang-font-lock-syntactic-face (state) - (cond ((eq (nth 3 state) ?') - ;; symbol - 'font-lock-constant-face) - ((nth 3 state) - ;; string - 'font-lock-string-face) - ((nth 4 state) - ;; comment - 'font-lock-comment-face))) - -(defun sclang-font-lock-class-keyword-matcher (limit) - (let ((regexp (concat "\\<" sclang-class-name-regexp "\\>")) - (case-fold-search nil) - (continue t) - (res nil)) - (while continue - (setq res (re-search-forward regexp limit t)) - (if (or (null res) (null sclang-class-list)) - (setq continue nil) - (let ((thing (thing-at-point 'word))) - (if (null thing) - (setq res nil continue nil) - (when (cl-position (substring-no-properties thing) sclang-class-list :test 'equal) - (setq continue nil)))))) - res)) - -(defun sclang-set-font-lock-keywords () - (setq - ;; level 1 - sclang-font-lock-keywords-1 - (list - ;; keywords - (cons (regexp-opt sclang-font-lock-keyword-list 'words) - 'font-lock-keyword-face) - ;; builtins - (cons (regexp-opt sclang-font-lock-builtin-list 'words) - 'font-lock-builtin-face) - ;; pi is a special case - (cons "\\<\\([0-9]+\\(\\.\\)\\)pi\\>" 'font-lock-builtin-face) - ;; constants - (cons "\\s/\\s\\?." 'font-lock-constant-face) ; characters - (cons (concat "\\\\\\(" sclang-symbol-regexp "\\)") - 'font-lock-constant-face) ; symbols - ) - ;; level 2 - sclang-font-lock-keywords-2 - (append - sclang-font-lock-keywords-1 - (list - ;; variables - (cons (concat "\\s'\\(" sclang-identifier-regexp "\\)") - 'font-lock-variable-name-face) ; environment variables - (cons (concat "\\<\\(" sclang-identifier-regexp "\\)\\>:") ; keyword arguments - 'font-lock-variable-name-face) - ;; method definitions - (cons sclang-method-definition-regexp - (list 1 'font-lock-function-name-face)) - ;; methods - (cons (regexp-opt sclang-font-lock-method-list 'words) - 'font-lock-function-name-face) - ;; errors - (cons (regexp-opt sclang-font-lock-error-list 'words) - 'font-lock-warning-face) - )) - ;; level 3 - sclang-font-lock-keywords-3 - (append - sclang-font-lock-keywords-2 - (list - ;; classes - (cons 'sclang-font-lock-class-keyword-matcher 'font-lock-type-face) -;; (cons (concat "\\<" sclang-class-name-regexp "\\>") 'font-lock-type-face) - )) - ;; default level - sclang-font-lock-keywords sclang-font-lock-keywords-1 - )) - -(defun sclang-update-font-lock () - "Update font-lock information in all sclang-mode buffers." - ;; too expensive - ;; (dolist (buffer (buffer-list)) - ;; (with-current-buffer buffer - ;; (and (eq major-mode 'sclang-mode) - ;; (eq t (car font-lock-keywords)) - ;; (setq font-lock-keywords (cdr font-lock-keywords))))) - (if (eq major-mode 'sclang-mode) - (font-lock-fontify-buffer))) - -;; ===================================================================== -;; indentation -;; ===================================================================== - -(defcustom sclang-indent-level 4 - "*Indentation offset for SCLang statements." - :group 'sclang-mode - :type 'integer) - -(defun sclang-indent-line () - "Indent current line as sclang code. -Return the amount the indentation changed by." - (let ((indent (calculate-sclang-indent)) - beg shift-amt - (case-fold-search nil) - (pos (- (point-max) (point)))) - (beginning-of-line) - (setq beg (point)) - (skip-chars-forward " \t") - (setq shift-amt (- indent (current-column))) - (if (zerop shift-amt) - (if (> (- (point-max) pos) (point)) - (goto-char (- (point-max) pos))) - (delete-region beg (point)) - (indent-to indent) - ;; if initial point was within line's indentation, position - ;; after the indentation, else stay at same point in text. - (if (> (- (point-max) pos) (point)) - (goto-char (- (point-max) pos)))) - shift-amt)) - -(defun calculate-sclang-indent (&optional parse-start) - "Return appropriate indentation for current line as sclang code. -Returns the column to indent to." - (save-excursion - (beginning-of-line) - (let ((indent-point (point)) - (case-fold-search nil) - state) - (if parse-start - (goto-char parse-start) - (beginning-of-defun)) - (while (< (point) indent-point) - (setq state (parse-partial-sexp (point) indent-point 0))) - (let* ((containing-sexp (nth 1 state)) - (inside-string-p (nth 3 state)) - (inside-comment-p (nth 4 state))) - (cond (inside-string-p - ;; inside string: no change - (current-indentation)) - ((integerp inside-comment-p) - ;; inside comment - (let ((base (if containing-sexp - (save-excursion - (goto-char containing-sexp) - (+ (current-indentation) sclang-indent-level)) - 0)) - (offset (* sclang-indent-level - (- inside-comment-p - (if (save-excursion - (back-to-indentation) - (looking-at "\\*/")) - 1 0))))) - (+ base offset))) - ((null containing-sexp) - ;; top-level: no indentation - 0) - (t - (back-to-indentation) - (let ((open-paren (and (looking-at "\\s)") - (matching-paren (char-after)))) - (indent (current-indentation))) - (goto-char containing-sexp) - (if (or (not open-paren) (eq open-paren (char-after))) - (cond ((progn (beginning-of-line) (looking-at sclang-block-regexp)) 0) - (open-paren (current-indentation)) - (t (+ (current-indentation) sclang-indent-level))) - ;; paren mismatch: do nothing - indent)))))))) - -;; ===================================================================== -;; electric character commands -;; ===================================================================== - -(defun sclang-electric-brace (arg) - (interactive "*P") - (self-insert-command (prefix-numeric-value arg)) - (and (save-excursion - (beginning-of-line) - (looking-at "\\s *\\s)")) - (indent-according-to-mode))) - -(defun sclang-electric-slash (arg) - (interactive "*P") - (let* ((char (char-before)) - (indent-p (or (eq char ?/) - (eq char ?*)))) - (self-insert-command (prefix-numeric-value arg)) - (if indent-p (indent-according-to-mode)))) - -(defun sclang-electric-star (arg) - (interactive "*P") - (let ((indent-p (eq (char-before) ?/))) - (self-insert-command (prefix-numeric-value arg)) - (if indent-p (indent-according-to-mode)))) - -;; ===================================================================== -;; document interface -;; ===================================================================== - -(defvar sclang-document-id nil) -(defvar sclang-document-state nil) -(defvar sclang-document-envir nil) - -(defvar sclang-document-counter 0) -(defvar sclang-document-list nil) -(defvar sclang-current-document nil - "Currently active document.") - -(defvar sclang-document-idle-timer nil) - -(defconst sclang-document-property-map - '((sclang-document-name . (prSetTitle (buffer-name))) - (sclang-document-path . (prSetFileName (buffer-file-name))) - (sclang-document-listener-p . (prSetIsListener (eq (current-buffer) (sclang-get-post-buffer)))) - (sclang-document-editable-p . (prSetEditable (not buffer-read-only))) - (sclang-document-edited-p . (prSetEdited (buffer-modified-p))))) - -(defmacro sclang-next-document-id () - `(cl-incf sclang-document-counter)) - -(defun sclang-document-id (buffer) - (cdr (assq 'sclang-document-id (buffer-local-variables buffer)))) - -(defun sclang-document-p (buffer) - (integerp (sclang-document-id buffer))) - -(defmacro with-sclang-document (buffer &rest body) - `(when (sclang-document-p buffer) - (with-current-buffer buffer - ,@body))) - -(defun sclang-get-document (id) - (cl-find-if (lambda (buffer) (eq id (sclang-document-id buffer))) - sclang-document-list)) - -(defun sclang-init-document () - (set (make-local-variable 'sclang-document-id) (sclang-next-document-id)) - (set (make-local-variable 'sclang-document-envir) nil) - (dolist (assoc sclang-document-property-map) - (set (make-local-variable (car assoc)) nil)) - (cl-pushnew (current-buffer) sclang-document-list)) - -(defun sclang-document-update-property-1 (assoc &optional force) - (when (consp assoc) - (let* ((key (car assoc)) - (prop (cdr assoc)) - (prev-value (eval key)) - (cur-value (eval (cadr prop)))) - (when (or force (not (equal prev-value cur-value))) - (set key cur-value) - (sclang-perform-command-no-result - 'documentSetProperty sclang-document-id - (car prop) cur-value))))) - -(defun sclang-document-update-property (key &optional force) - (sclang-document-update-property-1 (assq key sclang-document-property-map) force)) - -(defun sclang-document-update-properties (&optional force) - (dolist (assoc sclang-document-property-map) - (sclang-document-update-property-1 assoc force))) - -(defun sclang-make-document () - (sclang-perform-command-no-result 'documentNew sclang-document-id) - (sclang-document-update-properties t)) - -(defun sclang-close-document (buffer) - (with-sclang-document - buffer - (setq sclang-document-list (delq buffer sclang-document-list)) - (sclang-perform-command-no-result - 'documentClosed sclang-document-id))) - -(defun sclang-set-current-document (buffer &optional force) - (when (or force (not (eq buffer sclang-current-document))) - (setq sclang-current-document buffer) - (sclang-perform-command-no-result 'documentSetCurrent (sclang-document-id buffer)) - t)) - -(defun sclang-document-library-startup-hook-function () - (dolist (buffer sclang-document-list) - (with-current-buffer buffer - (sclang-make-document))) - (sclang-set-current-document (current-buffer) t)) - -(defun sclang-document-kill-buffer-hook-function () - (sclang-close-document (current-buffer))) - -(defun sclang-document-post-command-hook-function () - (when (and (sclang-library-initialized-p) - (sclang-document-p (current-buffer))) - (sclang-document-update-properties)) - (sclang-set-current-document (current-buffer))) - -(defun sclang-document-change-major-mode-hook-function () - (sclang-close-document (current-buffer))) - -;; ===================================================================== -;; command handlers -;; ===================================================================== - -(sclang-set-command-handler - '_documentOpen - (lambda (arg) - (cl-multiple-value-bind (file-name region-start region-length) arg - (let ((buffer (get-file-buffer file-name))) - (unless buffer - (setf buffer (find-file-noselect file-name))) - (when buffer - (unless (sclang-document-p buffer) - (with-current-buffer buffer (sclang-mode))) - (goto-char (max (point-min) (min (point-max) region-start))) - ;; TODO: how to activate region in transient-mark-mode? - (sclang-document-id buffer)))))) - -(sclang-set-command-handler - '_documentNew - (lambda (arg) - (cl-multiple-value-bind (name str make-listener) arg - (let ((buffer (generate-new-buffer name))) - (with-current-buffer buffer - (insert str) - (set-buffer-modified-p nil) - (sclang-mode)) - (sclang-document-id buffer))))) - -(sclang-set-command-handler - '_documentClose - (lambda (arg) - (let ((doc (and (integerp arg) (sclang-get-document arg)))) - (and doc (kill-buffer doc))) - nil)) - -(sclang-set-command-handler - '_documentRename - (lambda (arg) - (cl-multiple-value-bind (id name) arg - (when (stringp name) - (let ((doc (and (integerp id) (sclang-get-document id)))) - (when doc - (with-current-buffer doc - (rename-buffer name t) - (sclang-document-update-property 'sclang-document-name)))))) - nil)) - -(sclang-set-command-handler - '_documentSetEditable - (lambda (arg) - (cl-multiple-value-bind (id flag) arg - (let ((doc (and (integerp id) (sclang-get-document id)))) - (when doc - (with-current-buffer doc - (setq buffer-read-only (not flag)) - (sclang-document-update-property 'sclang-editable-p))))) - nil)) - -(sclang-set-command-handler - '_documentSwitchTo - (lambda (arg) - (let ((doc (and (integerp arg) (sclang-get-document arg)))) - (and doc (switch-to-buffer doc))) - nil)) - -(sclang-set-command-handler - '_documentPutString -(lambda (arg) - (cl-multiple-value-bind (id str) arg - (let ((doc (and (integerp id) (sclang-get-document id)))) - (when doc - (with-current-buffer doc - (insert str) - ) - nil))))) - -(sclang-set-command-handler - '_documentPopTo - (lambda (arg) - (let ((doc (and (integerp arg) (sclang-get-document arg)))) - (and doc (display-buffer doc))) - nil)) - -;; ===================================================================== -;; sclang-mode -;; ===================================================================== - -(defun sclang-mode-set-local-variables () - (set (make-local-variable 'require-final-newline) nil) - ;; indentation - (set (make-local-variable 'indent-line-function) - 'sclang-indent-line) - (set (make-local-variable 'tab-width) 4) - (set (make-local-variable 'indent-tabs-mode) t) - ;; comment formatting - (set (make-local-variable 'comment-start) "// ") - (set (make-local-variable 'comment-end) "") - (set (make-local-variable 'comment-column) 40) - (set (make-local-variable 'comment-start-skip) "/\\*+ *\\|//+ *") - ;; "\\(^\\|\\s-\\);?// *") - (set (make-local-variable 'comment-multi-line) t) - ;; parsing and movement - (set (make-local-variable 'parse-sexp-ignore-comments) t) - (set (make-local-variable 'beginning-of-defun-function) - 'sclang-beginning-of-defun) - (set (make-local-variable 'end-of-defun-function) - 'sclang-end-of-defun) - ;; paragraph formatting - ;; (set (make-local-variable 'paragraph-start) (concat "$\\|" page-delimiter)) - ;; mostly copied from c++-mode, seems to work - (set (make-local-variable 'paragraph-start) - "[ \t]*\\(//+\\|\\**\\)[ \t]*$\\|^ ") - (set (make-local-variable 'paragraph-separate) paragraph-start) - (set (make-local-variable 'paragraph-ignore-fill-prefix) t) - (set (make-local-variable 'adaptive-fill-mode) t) - (set (make-local-variable 'adaptive-fill-regexp) - "[ \t]*\\(//+\\|\\**\\)[ \t]*\\([ \t]*\\([-|#;>*]+[ \t]*\\|(?[0-9]+[.)][ \t]*\\)*\\)") - ;; font lock - (set (make-local-variable 'font-lock-syntactic-face-function) - 'sclang-font-lock-syntactic-face) - (set (make-local-variable 'font-lock-defaults) - sclang-font-lock-defaults) - ;; --- - nil) - -(defvar sclang-mode-map (sclang-fill-mode-map (make-sparse-keymap)) - "Keymap used in SuperCollider mode.") - -(defvar sclang-mode-syntax-table (sclang-fill-syntax-table (make-syntax-table)) - "Syntax table used in SuperCollider mode.") - -(defcustom sclang-mode-hook nil - "*Hook run when entering SCLang mode." - :group 'sclang-mode - :type 'hook) - -;;;###autoload -(define-derived-mode sclang-mode prog-mode "SCLang" - "Major mode for editing SuperCollider language code. -\\{sclang-mode-map}" - :group 'sclang - :syntax-table sclang-mode-syntax-table - (sclang-mode-set-local-variables) - (sclang-set-font-lock-keywords) - (sclang-init-document) - (sclang-make-document) - - ;; Setup completion - (add-hook 'completion-at-point-functions - #'sclang-completion-at-point nil 'local) - (when (fboundp 'company-mode) - (add-to-list 'company-backends 'company-capf))) - -;; ===================================================================== -;; module initialization -;; ===================================================================== - -;;;###autoload -(add-to-list 'auto-mode-alist '("\\.scd?\\'" . sclang-mode)) -(add-to-list 'interpreter-mode-alist '("sclang" . sclang-mode)) - -(add-hook 'sclang-library-startup-hook 'sclang-document-library-startup-hook-function) -(add-hook 'kill-buffer-hook 'sclang-document-kill-buffer-hook-function) -(add-hook 'post-command-hook 'sclang-document-post-command-hook-function) -(add-hook 'change-major-mode-hook 'sclang-document-change-major-mode-hook-function) +(eval-and-compile + (let ((load-path + (if (and (boundp 'byte-compile-dest-file) + (stringp byte-compile-dest-file)) + (cons (file-name-directory byte-compile-dest-file) load-path) + load-path))) + (require 'sclang-util) + (require 'sclang-browser) + (require 'sclang-interp) + (require 'sclang-language) + (require 'sclang-document) + (require 'sclang-mode) + (require 'sclang-minor-mode) + (require 'sclang-help) + (require 'sclang-server) + (require 'sclang-widgets))) (provide 'sclang)