I want to switch to Emacs for my SuperCOllider programming, since i also do every other work in emacs.
I got SuperCollider running in Emacs, but i have a little bug, which i can’t solve.
The bug is related to code highlighting and appears like this:
when i open a .scd document the SCLang mode starts and everything looks fine. the code is highlighted as expected
then i start the interpreter (C-c C-o). The SCLang Workspace starts and the interpreter buffer is opened. but the highlighting of the UGens is disappearing. for example: ‘SinOsc’ is not highlighted anymore, but ‘var’, and ‘\symbols’ are still highlited.
I guess it has something to do with rescanning the SC database for UGens.
I checked the Repo for the scel package and i noticed, that this is a known problem.
There is even a PR which solves this problem, so i copied the PR manually, since it is not merged yet.
This solved the problem.
But i have another question:
what is the best auto-complete package for emacs and supercollider? normally i use company, but it does not complete for my variables. what are you using?
But i found a bug and since the Emacs package is not maintained, i assume that other people have also problems with this and maybe found a solution:
i wanted to use the sclang-eval-region command in Emacs to evluate everything in between two panrenthesis. This does not seem to work, since i always get syntax error, but the code evaluates fine in the SuperCollider IDE.
I tried to be sure. It is still working with my setup using GNU Emacs 30.2.
This is my init.el file, but it should work out of the box:
;; ------------------------
;; Package Manager Setup
;; ------------------------
(require 'package)
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/"))
(package-initialize)
;; Ensure use-package is installed
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(require 'use-package)
;; Lua Keybindings
(with-eval-after-load 'lua-mode
;; Remove old keys first (optional if reloading)
(define-key lua-mode-map (kbd "C-c C-c") nil)
(define-key lua-mode-map (kbd "C-c C-d") nil)
(define-key lua-mode-map (kbd "C-c C-l") nil)
(define-key lua-mode-map (kbd "C-c C-f") nil)
;; Now define them cleanly
(define-key lua-mode-map (kbd "C-c C-c") 'lua-send-current-line)
(define-key lua-mode-map (kbd "C-c C-d") 'lua-send-region)
(define-key lua-mode-map (kbd "C-c C-l") 'lua-send-buffer)
(define-key lua-mode-map (kbd "C-c C-f") 'lua-search-documentation))
;; Hide Toolbar
(tool-bar-mode -1)
;; Enable mouse support in terminal
(xterm-mouse-mode 1)
;; Clipboard support in terminal mode
(xclip-mode 1)
;; deactivate C-z
(global-unset-key (kbd "C-z"))
;; ------------------------
;; Startup UI
;; ------------------------
(setq inhibit-startup-screen t) ;; disable welcome screen
(setq initial-scratch-message "") ;; empty scratch buffer
;; Ask for confirmation before quitting Emacs
(setq confirm-kill-emacs 'y-or-n-p)
;; ------------------------
;; Put backup files neatly away
;; ------------------------
(let ((backup-dir "~/tmp/emacs/backups")
(auto-saves-dir "~/tmp/emacs/auto-saves/"))
(dolist (dir (list backup-dir auto-saves-dir))
(when (not (file-directory-p dir))
(make-directory dir t)))
(setq backup-directory-alist `(("." . ,backup-dir))
auto-save-file-name-transforms `((".*" ,auto-saves-dir t))
auto-save-list-file-prefix (concat auto-saves-dir ".saves-")
tramp-backup-directory-alist `((".*" . ,backup-dir))
tramp-auto-save-directory auto-saves-dir))
(setq backup-by-copying t ; Don't delink hardlinks
delete-old-versions t ; Clean up the backups
version-control t ; Use version numbers on backups,
kept-new-versions 5 ; keep some new versions
kept-old-versions 2) ; and some old ones, too
;; ------------------------
;; Global line numbers
;; ------------------------
(global-display-line-numbers-mode 1)
(setq display-line-numbers-type 'absolute) ;; or 'relative
;; Force solid background for line numbers, this is used to supress colored artifact pixels when using relative line numbering
;; Reported the bug to the emacs bug tracker mailing list
;;(set-face-attribute 'line-number nil
;; :background "#282a36" ;; Dracula background color
;; :foreground "#6272a4") ;; Dracula line number color
;; (set-face-attribute 'line-number-current-line nil
;; :background "#282a36" ;; same as background, no transparency
;; :foreground "#f8f8f2") ;; brighter for current line
;; (setq display-line-numbers-width 100)
;; ------------------------
;; Theme
;; ------------------------
(setq catppuccin-flavor 'frappe) ;; or 'latte, 'macchiato, or 'mocha
(use-package catppuccin-theme
:ensure t
:config
(load-theme 'catppuccin :no-confirm))
;; ------------------------
;; Company-mode (autocomplete)
;; ------------------------
(use-package company
:ensure t
:hook (after-init . global-company-mode)
:config
(setq company-idle-delay 0.2
company-minimum-prefix-length 1)
;; Filter out candidates that are purely numeric
(push (apply-partially #'cl-remove-if
(lambda (c)
(string-match-p "^[0-9]+\\(?:\\.[0-9]*\\)?$" c)))
company-transformers))
;; ------------------------
;; SuperCollider-specific configuration
;; ------------------------
(with-eval-after-load 'sclang
(add-hook 'sclang-mode-hook
(lambda ()
(company-mode 1)
;; Only set backends after sclang is loaded
(setq-local company-backends '(company-capf company-dabbrev-code))
(setq sclang-autocomplete-enable t))))
;; ------------------------
;; SuperCollider Emacs Integration
;; ------------------------
;; Adjust this path to where you installed the SC Quark 'scel'
(add-to-list 'load-path "~/.local/share/SuperCollider/downloaded-quarks/scel/el")
(require 'sclang)
;; ------------------------
;; Associate .scd and .sc files automatically
(add-to-list 'auto-mode-alist '("\\.scd$" . sclang-mode))
(add-to-list 'auto-mode-alist '("\\.sc$" . sclang-mode))
;; Move PostBuffer to right side window
(add-to-list 'display-buffer-alist
'("\\*SCLang:PostBuffer\\*"
(display-buffer-in-side-window)
(side . right)
(window-width . 60)))
;; ------------------------
;; Custom-set Variables (generated by Emacs, keep as is)
;; ------------------------
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(cua-mode t)
'(custom-enabled-themes '(modus-operandi-tinted))
'(custom-safe-themes
'("36c5acdaf85dda0dad1dd3ad643aacd478fb967960ee1f83981d160c52b3c8ac"
"fae5872ff90462502b3bedfe689c02d2fa281bc63d33cb007b94a199af6ccf24"
"dfb1c8b5bfa040b042b4ef660d0aab48ef2e89ee719a1f24a4629a0c5ed769e8"
"13096a9a6e75c7330c1bc500f30a8f4407bd618431c94aeab55c9855731a95e1"
"19b62f442479efd3ca4c1cef81c2311579a98bbc0f3684b49cdf9321bd5dfdbf"
"b9c002dc827fb75b825da3311935c9f505d48d7ee48f470f0aa7ac5d2a595ab2"
"ffa78fc746f85d1c88a2d1691b1e37d21832e9a44a0eeee114a00816eabcdaf9"
"4c16a8be2f20a68f0b63979722676a176c4f77e2216cc8fe0ea200f597ceb22e"
"aff0396925324838889f011fd3f5a0b91652b88f5fd0611f7b10021cc76f9e09"
"c038d994d271ebf2d50fa76db7ed0f288f17b9ad01b425efec09519fa873af53"
"df39cc8ecf022613fc2515bccde55df40cb604d7568cb96cd7fe1eff806b863b"
"d6b369a3f09f34cdbaed93eeefcc6a0e05e135d187252e01b0031559b1671e97"
"b3ba955a30f22fe444831d7bc89f6466b23db8ce87530076d1f1c30505a4c23b"
"ac893acecb0f1cf2b6ccea5c70ea97516c13c2b80c07f3292c21d6eb0cb45239"
"d609d9aaf89d935677b04d34e4449ba3f8bbfdcaaeeaab3d21ee035f43321ff1"
"59c36051a521e3ea68dc530ded1c7be169cd19e8873b7994bfc02a216041bf3b"
"cd5f8f91cc2560c017cc9ec24a9ab637451e36afd22e00a03e08d7b1b87c29ca"
"5a0ddbd75929d24f5ef34944d78789c6c3421aa943c15218bac791c199fc897d"
"8363207a952efb78e917230f5a4d3326b2916c63237c1f61d7e5fe07def8d378"
"5244ba0273a952a536e07abaad1fdf7c90d7ebb3647f36269c23bfd1cf20b0b8"
"83550d0386203f010fa42ad1af064a766cfec06fc2f42eb4f2d89ab646f3ac01"
"b5fd9c7429d52190235f2383e47d340d7ff769f141cd8f9e7a4629a81abc6b19"
"166a2faa9dc5b5b3359f7a31a09127ebf7a7926562710367086fcc8fc72145da"
"7de64ff2bb2f94d7679a7e9019e23c3bf1a6a04ba54341c36e7cf2d2e56e2bcc"
"014cb63097fc7dbda3edf53eb09802237961cbb4c9e9abd705f23b86511b0a69"
"e85a354f77ae6c2e47667370a8beddf02e8772a02e1f7edb7089e793f4762a45"
"6af300029805f10970ebec4cea3134f381cd02f04c96acba083c76e2da23f3ec"
"f9d423fcd4581f368b08c720f04d206ee80b37bfb314fa37e279f554b6f415e9"
default))
'(display-line-numbers-type 'absolute)
'(global-display-line-numbers-mode t)
'(package-selected-packages
'(buffer-move catppuccin-theme company doom-themes doric-themes
dracula-theme ef-themes ement eradio evil fzf
gruvbox-theme lsp-pyright lua-mode marginalia
multi-vterm pyenv-mode pyvenv tidal vertico xclip))
'(sclang-auto-scroll-post-buffer t)
'(sclang-eval-line-forward nil)
'(sclang-show-workspace-on-startup nil)
'(tool-bar-mode nil))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(highlight ((t (:background "dark green" :foreground "#2e3436")))))
;; ------------------------
;; QWERTZ-friendly paragraph navigation
;; Rebind M-{ (backward-paragraph) and M-} (forward-paragraph) to easier keys
;; ------------------------
(global-set-key (kbd "C-ü") 'backward-paragraph)
(global-set-key (kbd "C-+") 'forward-paragraph)
;; Optional: also keep original M-{ and M-} if you want
(global-set-key (kbd "M-{") 'backward-paragraph)
(global-set-key (kbd "M-}") 'forward-paragraph)
;; Thank you, undltd!!! https://xn--w5d.cc/2024/07/28/supercollider-emacs-highlight-eval.html
(require 'pulse)
(defun my/sclang-highlight-defun (&optional silent-p)
(cl-multiple-value-bind (beg end) (sclang-point-in-defun-p)
(when (and beg end)
(pulse-momentary-highlight-region beg end))))
(defun my/sclang-highlight-region (&optional silent-p)
(when (use-region-p)
(pulse-momentary-highlight-region (region-beginning) (region-end))))
(defun my/sclang-highlight-line (&optional silent-p)
(pulse-momentary-highlight-one-line (point)))
;; Hook into evaluation commands
(advice-add 'sclang-eval-defun :before #'my/sclang-highlight-defun)
(advice-add 'sclang-eval-region :before #'my/sclang-highlight-region)
(advice-add 'sclang-eval-line :before #'my/sclang-highlight-line)
;; --- SuperCollider record setup ---
;; Set path where recordings should be stored
(setq kf/sclang-recording-path "~/sc-recordings") ;; change this!
(defun kf/sclang-record ()
"Toggle SuperCollider recording. Files go to `kf/sclang-recording-path`."
(interactive)
(sclang-eval-expression
(format
"if(s.isRecording) {
s.stopRecording
} {
s.record(
\"%s/\" ++ Date.localtime.stamp ++ \".wav\",
numChannels: s.options.numOutputBusChannels
)
}"
(expand-file-name kf/sclang-recording-path))))
;; Keybinding for sclang-mode
(with-eval-after-load 'sclang
(define-key sclang-mode-map (kbd "<f5>") #'kf/sclang-record)
(define-key sclang-mode-map (kbd "<f12>") #'sclang-main-stop))
;; Prot dired configuration -- see https://protesilaos.com/codelog/2023-06-26-emacs-file-dired-basics/
;; Install the `vertico' package to get a vertical view of the
;; minibuffer. Vertico is optimised for performance and is also
;; highly configurable. Here is my minimal setup:
(setq vertico-resize nil)
(vertico-mode 1)
;; Install the `marginalia' package. This will display useful
;; annotations next to entries in the minibuffer. For example, when
;; using M-x it will show a brief description of the command as well
;; as the keybinding associated with it (if any).
(marginalia-mode 1)
;; When you first call `find-file' (C-x C-f by default), you do not
;; need to clear the existing file path before adding the new one.
;; Just start typing the whole path and Emacs will "shadow" the
;; current one. For example, you are at ~/Documents/notes/file.txt
;; and you want to go to ~/.emacs.d/init.el: type the latter directly
;; and Emacs will take you there.
(file-name-shadow-mode 1)
;; This works with `file-name-shadow-mode' enabled. When you are in
;; a sub-directory and use, say, `find-file' to go to your home '~/'
;; or root '/' directory, Vertico will clear the old path to keep
;; only your current input.
(add-hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy)
;; Do not outright delete files. Move them to the system trash
;; instead. The `trashed' package can act on them in a Dired-like
;; fashion. I use it and can recommend it to either restore (R) or
;; permanently delete (D) the files.
(setq delete-by-moving-to-trash t)
;; When there are two Dired buffers side-by-side make Emacs
;; automatically suggest the other one as the target of copy or rename
;; operations. Remember that you can always use M-p and M-n in the
;; minibuffer to cycle through the history, regardless of what this
;; does. (The "dwim" stands for "Do What I Mean".)
(setq dired-dwim-target t)
;; Automatically hide the detailed listing when visiting a Dired
;; buffer. This can always be toggled on/off by calling the
;; `dired-hide-details-mode' interactively with M-x or its keybindings
;; (the left parenthesis by default).
(add-hook 'dired-mode-hook #'dired-hide-details-mode)
;; Teach Dired to use a specific external program with either the
;; `dired-do-shell-command' or `dired-do-async-shell-command' command
;; (with the default keys, those are bound to `!' `&', respectively).
;; The first string is a pattern match against file names. The
;; remaining strings are external programs that Dired will provide as
;; suggestions. Of course, you can always type an arbitrary program
;; despite these defaults.
;;
;; Note that the * can be added to a program to instruct it to open
;; all the files as a set rather than all as separate instances. You
;; write the name of the program, then space followed by the asterisk
;; (thanks to @mac68tm on YouTube for pointing this out).
(setq dired-guess-shell-alist-user
'(("\\.\\(png\\|jpe?g\\|tiff\\)" "feh *" "xdg-open")
("\\.\\(mp[34]\\|m4a\\|ogg\\|flac\\|webm\\|mkv\\)" "mpv *" "xdg-open")
(".*" "xdg-open")))
;; Set folders first
(setq dired-listing-switches "-al --group-directories-first")
;; Change keybinding to go up in directory
(eval-after-load "dired" '(progn
(define-key dired-mode-map (kbd "M-u") 'dired-up-directory) ))
;; Hide dotfiles
(use-package dired
:init
(require 'dired-x) ;; needed for dired-omit-mode
:hook
(dired-mode . (lambda () (dired-omit-mode))) ;; hide .dot files by default
:config
(setq dired-omit-files
(concat dired-omit-files "\\|^\\..+$")))
;; Enable Evil mode
(require 'evil)
(evil-mode 0)
;; Python configuration
(use-package lsp-pyright
:ensure t
:hook (python-mode . (lambda ()
(require 'lsp-pyright)
(lsp-deferred)))
:custom
(lsp-pyright-python-executable-cmd "~/python/myenv/bin/python")
(lsp-pyright-langserver-command "~/python/myenv/bin/pyright"))
;; Python REPL
(setq python-shell-interpreter "~/python/myenv/bin/python")
(setq python-shell-interpreter-args "-i")
;; Lua configuration
(use-package lsp-mode
:ensure t
:hook (lua-mode . lsp)
:commands lsp)
(setq lsp-clients-lua-language-server-bin
"~/builds/luals/lua-language-server/bin/lua-language-server")
;; Stuff to get a better Tidal experience
(with-eval-after-load 'cua-base
;; disable C-Enter from triggering CUA rectangle select
(define-key cua-global-keymap (kbd "C-<return>") nil))
;; Fixing C-c C-c error
(add-hook 'haskell-interactive-mode-hook
(lambda ()
(define-key interactive-haskell-mode-map
(kbd "C-c C-c") nil)))
;; Tidal autocompletion
(add-to-list 'load-path "~/.emacs.d/tidal_completion")
(require 'tidal-completion)
(setq tidal-completion-sample-directories
'("~/.local/share/SuperCollider/downloaded-quarks/Dirt-Samples"))
;; only init after tidal/haskell are loaded
(with-eval-after-load 'tidal
(tidal-completion-init)
(defun my-tidal-completion-add-hook ()
(add-hook 'completion-at-point-functions
#'tidal-completion-at-point nil t))
(add-hook 'tidal-mode-hook #'my-tidal-completion-add-hook))
;; company integration (buffer-local)
(with-eval-after-load 'company
(add-hook 'tidal-mode-hook
(lambda ()
(company-mode 1)
(setq-local company-backends
(cons #'company-capf company-backends)))))
Sometime i want to search for something in the post buffer via scrolling upwards in it. After this, the post buffer will not scroll down anymore, when i excute code. Once i scrolled in it i have to scroll down for every new line. The post buffer does not jump to the new line anymore.