├── README.md └── faust-mode.el /README.md: -------------------------------------------------------------------------------- 1 | # Faust-Mode 2 | 3 | Major Emacs mode for the [Faust](http://faust.grame.fr) programming language, featuring syntax highlighting, automatic indentation and auto-completion. 4 | 5 | ___ 6 | [![License GPLv3](https://img.shields.io/badge/license-GPL_v3-green.svg)](http://www.gnu.org/licenses/gpl-3.0.html) [![MELPA](https://melpa.org/packages/faust-mode-badge.svg)](https://melpa.org/#/faust-mode) [![MELPA](https://stable.melpa.org/packages/faust-mode-badge.svg)](https://stable.melpa.org/#/faust-mode) 7 | 8 | 9 | ## Features 10 | 11 | - Syntax highlighting of Faust keywords, operators and library functions 12 | - Indentation rules 13 | - Auto-completion of library functions (requires the auto-complete package, also available from [MELPA][]) 14 | - [Compatible](https://github.com/syl20bnr/spacemacs/tree/develop/layers/%2Blang/faust) with SpaceEmacs 15 | 16 | [MELPA]: https://melpa.org 17 | 18 | ## Installation 19 | 20 | - **Easy:** Install it from [MELPA][]. 21 | 22 | - **Hard:** Copy/clone this repository and put it somewhere on your Emacs `load-path`. 23 | 24 | ## Usage 25 | 26 | ```elisp 27 | M-x faust-mode 28 | ``` 29 | 30 | To do this automatically for every Faust file, add something like this to your init file: 31 | 32 | ```elisp 33 | (require 'faust-mode) 34 | (setq auto-mode-alist (cons '("\\.dsp$" . faust-mode) auto-mode-alist)) 35 | ``` 36 | 37 | ## Auto-completion 38 | 39 | To make auto-completion work, install the auto-complete package from [MELPA][] and add the following to your .emacs: 40 | ```elisp 41 | (global-auto-complete-mode t) 42 | ``` 43 | 44 | ## Faust 45 | 46 | Oh, and of course install [the latest 47 | Faust](https://github.com/grame-cncm/faust) and ensure it's in the 48 | PATH. 49 | 50 | ## Faustine 51 | 52 | Based on faust-mode, [Faustine](https://bitbucket.org/yphil/faustine) goes even further into turning Emacs into a full-fledged Faust IDE. 53 | 54 | 55 | ___ 56 | *README.md made on 2017-11-22 at 12:14:16 with [doc-a-mode](https://bitbucket.org/yphil/doc-a-mode)* 57 | -------------------------------------------------------------------------------- /faust-mode.el: -------------------------------------------------------------------------------- 1 | ;;; faust-mode.el --- Faust syntax colorizer for Emacs. 2 | 3 | ;; Copyright (C) 2016 Juan A. Romero 4 | 5 | ;; Author: rukano 6 | ;; Author: Juan A. Romero 7 | ;; Author: Yassin Philip 8 | ;; Maintainer: Yassin Philip 9 | ;; Maintainer: Juan A. Romero 10 | ;; Keywords: languages, faust 11 | ;; Version: 0.2 12 | ;; URL: https://github.com/rukano/emacs-faust-mode 13 | ;; License: GPLv3 14 | ;; MELPA: yes 15 | ;; MELPA-stable: yes 16 | 17 | ;; This program is free software; you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version. 21 | 22 | ;; This program is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with this program. If not, see . 29 | 30 | ;;; Commentary: 31 | 32 | ;; ## Features 33 | 34 | ;; - Syntax highlighting of *all* the Faust commands and operators 35 | ;; - Indentation rules 36 | ;; - [Compatible](https://github.com/syl20bnr/spacemacs/tree/develop/layers/%2Blang/faust) with SpaceEmacs 37 | 38 | ;; ## Installation 39 | 40 | ;; ### Easy 41 | 42 | ;; - Install it from [MELPA](https://melpa.org). 43 | 44 | ;; ### Hard 45 | 46 | ;; - Copy/clone this repository in `load-path` 47 | ;; - Add 48 | ;; ```elisp 49 | ;; (require 'faust-mode) 50 | ;; ``` 51 | ;; to your init file 52 | 53 | ;; ### Faust 54 | 55 | ;; Oh, and of course install [the latest 56 | ;; Faust](http://faust.grame.fr/download/) and ensure it's in the 57 | ;; PATH. 58 | 59 | ;; ### Faustine 60 | 61 | ;; Based on faust-mode, [Faustine](https://bitbucket.org/yphil/faustine) goes even further into turning Emacs into a full-fledged Faust IDE. 62 | 63 | ;;; Code: 64 | 65 | 66 | (require 'smie) 67 | 68 | (defvar ac-sources) 69 | 70 | (defconst faust-keywords-statements 71 | '("process" "with" "letrec" "case" "seq" "par" "sum" "prod" "include" "import" "component" "library" "environment" "declare" "define" "undef" "error" "pragma" "ident" "if" "def" "else" "elif" "endif" "line" "warning")) 72 | 73 | (defconst faust-keywords-functions 74 | '("mem" "prefix" "int" "float" "rdtable" "rwtable" "select2" "select3" "ffunction" "fconstant" "fvariable" "attach" "acos" "asin" "atan" "atan2" "cos" "sin" "tan" "exp" "log" "log10" "pow" "sqrt" "abs" "min" "max" "fmod" "remainder" "floor" "ceil" "rint" "xor")) 75 | 76 | (defconst faust-keywords-ui 77 | '("button" "checkbox" "vslider" "hslider" "nentry" "vgroup" "hgroup" "tgroup" "vbargraph" "hbargraph")) 78 | 79 | (defconst faust-keywords-lib-analyzer 80 | '("amp_follower" "amp_follower_ud" "amp_follower_ar" "mth_octave_analyzer[N]" "mth_octave_spectral_level6e" "octave_filterbank" "octave_analyzer" "half_octave_filterbank" "half_octave_analyzer" "third_octave_filterbank" "third_octave_analyzer" "analyzer")) 81 | 82 | (defconst faust-keywords-lib-basic 83 | '("samp2sec" "sec2samp" "db2linear" "linear2db" "lin2LogGain" "log2LinGain" "tau2pole" "pole2tau" "midikey2hz" "pianokey2hz" "hz2pianokey" "countdown" "countup" "sweep" "time" "tempo" "period" "pulse" "pulsen" "beat" "count" "take" "subseq" "if" "selector" "selectn" "select2stereo" "Other" "latch" "sAndH" "peakhold" "peakholder" "impulsify" "automat" "bypass1" "bypass2")) 84 | 85 | (defconst faust-keywords-lib-compressor 86 | '("compressor_mono" "compressor_stereo" "limiter_*")) 87 | 88 | (defconst faust-keywords-lib-delay 89 | '("delay" "fdelay" "sdelay" "fdelaylti" "fdelayltv" "fdelay[n]" "fdelay[n]a")) 90 | 91 | (defconst faust-keywords-lib-demo 92 | '("Analyzers" "mth_octave_spectral_level_demo" "Filters" "parametric_eq_demo" "spectral_tilt_demo" "mth_octave_filterbank_demo" "filterbank_demo" "Effects" "cubicnl_demo" "gate_demo" "compressor_demo" "exciter" "moog_vcf_demo" "wah4_demo" "crybaby_demo" "vocoder_demo" "flanger_demo" "phaser2_demo" "freeverb_demo" "stereo_reverb_tester" "fdnrev0_demo" "zita_rev_fdn_demo" "zita_rev1" "Generators" "sawtooth_demo" "virtual_analog_oscillator_demo" "oscrs_demo")) 93 | 94 | (defconst faust-keywords-lib-envelope 95 | '("smoothEnvelope" "ar" "asr" "adsr")) 96 | 97 | (defconst faust-keywords-lib-filter 98 | '("zero" "pole" "integrator" "dcblockerat" "dcblocker" "ff_comb" "ff_fcomb" "ffcombfilter" "fb_comb" "fb_fcomb" "rev1" "fbcombfilter" "ffbcombfilter" "allpass_comb" "allpass_fcomb" "rev2" "allpass_fcomb5" "allpass_fcomb1a" "iir" "fir" "conv" "convN" "tf1" "tf2" "tf3" "notchw" "tf21" "tf22" "tf22t" "tf21t" "av2sv" "bvav2nuv" "iir_lat2" "allpassnt" "iir_kl" "allpassnklt" "iir_lat1" "allpassn1mt" "iir_nl" "allpassnnlt" "tf2np" "wgr" "nlf2" "apnl" "allpassn" "allpassnn" "allpasskl" "allpass1m" "tf2s" "tf2snp" "tf3slf" "tf1s" "tf2sb" "tf1sb" "resonlp" "resonhp" "resonbp" "lowpass" "highpass" "lowpass0_highpass1" "lowpass_plus|minus_highpass" "lowpass_plus|minus_highpass" "lowpass3e" "lowpass6e" "highpass3e" "highpass6e" "bandpass" "bandstop" "bandpass6e" "bandpass12e" "low_shelf" "lowshelf_other_freq" "high_shelf" "highshelf_other_freq" "peak_eq" "cubicnl" "gate_mono" "gate_stereo" "Filtering" "speakerbp" "piano_dispersion_filter" "stereo_width" "echo" "transpose" "mesh_square")) 99 | 100 | (defconst faust-keywords-lib-hoa 101 | '("encoder" "decoder" "decoderStereo" "optimBasic" "optimMaxRe" "optimInPhase" "Usage" "wider" "map" "rotate")) 102 | 103 | (defconst faust-keywords-lib-math 104 | '("SR" "BS" "PI" "FTZ" "neg" "sub(x,y)" "inv" "cbrt" "hypot" "ldexp" "scalb" "log1p" "logb" "ilogb" "log2" "expm1" "acosh" "asinh" "atanh" "sinh" "cosh" "tanh" "erf" "erfc" "gamma" "lgamma" "J0" "J1" "Jn" "Y0" "Y1" "Yn" "fabs" "fmax" "fmin" "np2" "frac" "isnan" "chebychev" "chebychevpoly" "diffn")) 105 | 106 | (defconst faust-keywords-lib-misceffect 107 | '("Dynamic" "cubicnl" "gate_mono" "gate_stereo" "Filtering" "speakerbp" "piano_dispersion_filter" "stereo_width" "echo" "transpose" "Meshes" "mesh_square")) 108 | 109 | (defconst faust-keywords-lib-miscoscillator 110 | '("sinwaveform" "coswaveform" "phasor" "oscsin" "osc" "oscos" "oscp" "osci" "lf_imptrain" "lf_pulsetrainpos" "lf_squarewavepos" "lf_squarewave" "lf_trianglepos" "lf_rawsaw" "lf_sawpos" "lf_sawpos_phase" "sawN(N,freq)" "sawNp" "saw2dpw(freq)" "saw2(freq)" "saw3(freq)" "saw4(freq)" "saw5(freq)" "saw6(freq)" "sawtooth(freq)" "saw2f2(freq)" "saw2f4(freq)" "pulsetrainN" "pulsetrain" "squareN" "square" "imptrain" "imptrainN" "triangle" "triangleN" "oscb" "oscr" "oscrs" "oscs" "oscs" "oscw" "oscwq" "oscwc" "oscws")) 111 | 112 | (defconst faust-keywords-lib-noise 113 | '("noise" "multirandom" "multinoise" "noises" "pink_noise" "pink_noise_vm" "lfnoise" "lfnoise0" "lfnoiseN")) 114 | 115 | (defconst faust-keywords-lib-phafla 116 | '("flanger_mono" "flanger_stereo" "phaser2_mono" "phaser2_stereo")) 117 | 118 | (defconst faust-keywords-lib-pm 119 | '("chain" "input" "output" "terminations" "fullTerminations" "leftTermination" "rightTermination" "waveguide" "idealString")) 120 | 121 | (defconst faust-keywords-lib-reverb 122 | '("jcrev" "satrev" "mono_freeverb" "stereo_freeverb" "fdnrev0" "zita_rev_fdn" "zita_rev1_stereo" "zita_rev1_ambi")) 123 | 124 | (defconst faust-keywords-lib-route 125 | '("cross" "crossnn" "crossn1" "interleave" "butterfly" "hadamard" "recursivize")) 126 | 127 | (defconst faust-keywords-lib-signal 128 | '("bus" "block" "interpolate" "smooth" "smoo" "polySmooth" "bsmooth" "lag_ud" "dot")) 129 | 130 | (defconst faust-keywords-lib-spat 131 | '("panner" "spat" "stereoize")) 132 | 133 | (defconst faust-keywords-lib-synth 134 | '("popFilterPerc" "dubDub" "sawTrombone" "combString" "additiveDrum" "additiveDrum")) 135 | 136 | (defconst faust-keywords-lib-vaeffect 137 | '("moog_vcf" "moog_vcf_2b" "wah4" "autowah" "crybaby" "vocoder")) 138 | 139 | (defvar faust-keywords-lib 140 | (append 141 | faust-keywords-lib-analyzer 142 | faust-keywords-lib-basic 143 | faust-keywords-lib-compressor 144 | faust-keywords-lib-delay 145 | faust-keywords-lib-demo 146 | faust-keywords-lib-envelope 147 | faust-keywords-lib-filter 148 | faust-keywords-lib-hoa 149 | faust-keywords-lib-math 150 | faust-keywords-lib-misceffect 151 | faust-keywords-lib-miscoscillator 152 | faust-keywords-lib-noise 153 | faust-keywords-lib-phafla 154 | faust-keywords-lib-pm 155 | faust-keywords-lib-reverb 156 | faust-keywords-lib-route 157 | faust-keywords-lib-signal 158 | faust-keywords-lib-spat 159 | faust-keywords-lib-synth 160 | faust-keywords-lib-vaeffect) 161 | "All the Faust library function keywords.") 162 | 163 | (defvar faust-keywords-misc 164 | (append 165 | faust-keywords-statements 166 | faust-keywords-functions 167 | faust-keywords-ui) 168 | "Miscellaneous Faust keywords and built-in functions.") 169 | 170 | (defvar faust-keywords-all 171 | (append 172 | faust-keywords-misc 173 | faust-keywords-lib) 174 | "All Faust keywords and functions.") 175 | 176 | (defvar faust-mode-ac-source 177 | '((candidates . faust-keywords-all))) 178 | 179 | (defvar faust-regexp-keywords-function (regexp-opt faust-keywords-functions 'words)) 180 | (defvar faust-regexp-keywords-statement (regexp-opt faust-keywords-statements 'words)) 181 | (defvar faust-regexp-keywords-ui (regexp-opt faust-keywords-ui 'words)) 182 | (defvar faust-regexp-keywords-lib (regexp-opt faust-keywords-lib 'words)) 183 | 184 | (defconst faust-regexp-faust-operator (rx (any ?- ",'@:*/%^+|&~>=grammar 274 | (smie-bnf->prec2 275 | `((id) 276 | ,(if outdent-blocks 277 | '(def ("declare" id) 278 | (id "=" exp) 279 | (id "=" exp "with" "{" defs "}") 280 | (id "=" exp "letrec" "{" defs "}") 281 | (exp)) 282 | '(def ("declare" id) 283 | (id "=" exp) 284 | (exp))) 285 | (defs (defs ";" defs) (def)) 286 | (exp (id) 287 | (id "(" exp ")") 288 | (exp "~" exp) 289 | (exp "," exp) 290 | (exp ":" exp) 291 | (exp "<:" exp) (exp ":>" exp))) 292 | '((assoc ";")) 293 | '((nonassoc "=") (assoc "~") (assoc ",") (assoc ":") (assoc "<:" ":>"))))) 294 | 295 | (defcustom faust-outdent-blocks t 296 | "Configure indentation of Faust block constructs. 297 | Non-nil means to indent the `with' and `letrec' constructs 298 | relative to the definition, not the right-hand side expression. 299 | 300 | Please note that this option will only take effect in newly 301 | created Faust buffers. To apply the setting to an already 302 | existing Faust buffer, you have to run \\[faust-smie-reset] in 303 | that buffer." 304 | :type 'boolean 305 | :set (lambda (_symbol value) 306 | (setq-default faust-outdent-blocks value) 307 | (setq faust-smie-grammar (faust-make-smie-grammar value))) 308 | :group 'faust) 309 | 310 | (defvar faust-smie-grammar (faust-make-smie-grammar faust-outdent-blocks)) 311 | 312 | (defun faust-smie-reset () 313 | "Reset the SMIE setup in the current Faust buffer." 314 | (interactive) 315 | (when (and (derived-mode-p 'faust-mode) faust-enable-smie) 316 | (smie-setup faust-smie-grammar #'faust-smie-rules))) 317 | 318 | (defun faust-smie-rules (kind token) 319 | (pcase (cons kind token) 320 | (`(:elem . basic) faust-indent) 321 | (`(:list-intro . ,_) t) 322 | (`(,_ . ",") (smie-rule-separator kind)) 323 | (`(:after . "=") faust-indent) 324 | (`(:before . ,(or `"(" `"{" `"[")) 325 | (if (smie-rule-hanging-p) (smie-rule-parent))) 326 | )) 327 | 328 | (defvar faust-font-lock-syntactic-keywords 329 | '(;; .. sections are treated as comments 330 | ("\\(<\\)mdoc>" 1 "!" t) ("\\)" 1 "!" t))) 331 | 332 | ;;;###autoload 333 | (define-derived-mode faust-mode prog-mode 334 | "Faust" 335 | "Major mode for editing Faust code (URL `http://faust.grame.fr'). 336 | 337 | Provides syntax highlighting of Faust keywords and library 338 | functions, as well as indentation rules. Auto-completion of 339 | library functions is available if you install and enable the 340 | `auto-complete' package available from MELPA." 341 | 342 | (setq 343 | comment-start "//" 344 | comment-end "" 345 | comment-start-skip "\\(//+\\|/\\*+\\)\\s *" 346 | font-lock-defaults 347 | '(faust-mode-font-lock-keywords 348 | nil nil nil nil 349 | (font-lock-syntactic-keywords . faust-font-lock-syntactic-keywords))) 350 | 351 | (if (boundp 'ac-sources) 352 | (progn 353 | (add-to-list 'ac-modes 'faust-mode) 354 | (add-to-list 'ac-sources 'faust-mode-ac-source)) 355 | (message "You really should install and use auto-complete")) 356 | 357 | (when faust-enable-smie 358 | (smie-setup faust-smie-grammar #'faust-smie-rules)) 359 | 360 | (set-syntax-table faust-mode-syntax-table)) 361 | 362 | (provide 'faust-mode) 363 | 364 | ;; End: 365 | ;;; faust-mode.el ends here 366 | --------------------------------------------------------------------------------