Emacs -- How to extract all elements of a list - emacs

I am looking for some assistance, please, to extract all elements of a list of files and/or directories that have been marked in dired-mode. Essentially, if there were some way to just remove the parentheses from around the result of (mapcar (lambda (filename) (file-name-nondirectory filename)) (dired-get-marked-files)), then that would do the trick.
(start-process
"name-of-process"
"*output-buffer*"
"/usr/bin/zip"
"zip-file-name.zip"
(mapcar
(lambda (filename) (file-name-nondirectory filename))
(dired-get-marked-files)) )
The result I am seeking will look like this:
(start-process
"name-of-process"
"*output-buffer*"
"/usr/bin/zip"
"zip-file-name.zip"
"filename-number-one"
"filename-number-two"
"filename-number-three" )
EDIT:
The start-process function does not generally accept a single concatenated string of arguments. Instead, each argument must be separately spelled out (with quotation marks around each argument), or the argument can be a variable.
Here is the debugger message from the first example above -- the error occurs because there is a parentheses around the file names -- i.e., it cannot be a list.
Debugger entered--Lisp error: (wrong-type-argument stringp ("file-name-number-one" "file-name-number-two" "file-name-number-three"))
start-process("name-of-process" "*output-buffer*" "/usr/bin/zip" "zip-file-name.zip" ("file-name-number-one" "file-name-number-two" "file-name-number-three"))
eval((start-process "name-of-process" "*output-buffer*" "/usr/bin/zip" "zip-file-name.zip" (mapcar (lambda (filename) (file-name-nondirectory filename)) (dired-get-marked-files))) nil)
(cons (eval exp lexical-binding) values)
(setq values (cons (eval exp lexical-binding) values))
(let ((debug-on-error old-value)) (setq values (cons (eval exp lexical-binding) values)) (setq new-value debug-on-error))
(let ((old-value (make-symbol "t")) new-value) (let ((debug-on-error old-value)) (setq values (cons (eval exp lexical-binding) values)) (setq new-value debug-on-error)) (if (eq old-value new-value) nil (setq debug-on-error new-value)))
(if (null eval-expression-debug-on-error) (setq values (cons (eval exp lexical-binding) values)) (let ((old-value (make-symbol "t")) new-value) (let ((debug-on-error old-value)) (setq values (cons (eval exp lexical-binding) values)) (setq new-value debug-on-error)) (if (eq old-value new-value) nil (setq debug-on-error new-value))))
(let ((exp (if exp exp (read--expression "Eval: ")))) (if (null eval-expression-debug-on-error) (setq values (cons (eval exp lexical-binding) values)) (let ((old-value (make-symbol "t")) new-value) (let ((debug-on-error old-value)) (setq values (cons (eval exp lexical-binding) values)) (setq new-value debug-on-error)) (if (eq old-value new-value) nil (setq debug-on-error new-value)))) (let ((print-length (and (not (= 0 (prefix-numeric-value insert-value))) eval-expression-print-length)) (print-level (and (not (= 0 (prefix-numeric-value insert-value))) eval-expression-print-level)) (deactivate-mark)) (if insert-value (with-no-warnings (let ((standard-output (current-buffer))) (prog1 (prin1 (car values)) (if (= 0 ...) (progn ...))))) (prog1 (prin1 (car values) t) (let ((str (eval-expression-print-format ...))) (if str (princ str t)))))))
(if (active-minibuffer-window) nil (let ((exp (if exp exp (read--expression "Eval: ")))) (if (null eval-expression-debug-on-error) (setq values (cons (eval exp lexical-binding) values)) (let ((old-value (make-symbol "t")) new-value) (let ((debug-on-error old-value)) (setq values (cons (eval exp lexical-binding) values)) (setq new-value debug-on-error)) (if (eq old-value new-value) nil (setq debug-on-error new-value)))) (let ((print-length (and (not (= 0 ...)) eval-expression-print-length)) (print-level (and (not (= 0 ...)) eval-expression-print-level)) (deactivate-mark)) (if insert-value (with-no-warnings (let ((standard-output ...)) (prog1 (prin1 ...) (if ... ...)))) (prog1 (prin1 (car values) t) (let ((str ...)) (if str (princ str t))))))))
lawlist-eval-expression()
funcall-interactively(lawlist-eval-expression)
call-interactively(lawlist-eval-expression nil nil)
command-execute(lawlist-eval-expression)

What you want is to use apply with (mapcar ...) as its last argument:
(apply 'start-process
"name-of-process"
"*output-buffer*"
"/usr/bin/zip"
"zip-file-name.zip"
(mapcar #'file-name-nondirectory (dired-get-marked-files)))
Note that (mapcar #'function list) is a shorter spelling of (mapcar (lambda (arg) (function arg)) list).

combine-and-quote-strings is what you want:
(combine-and-quote-strings (mapcar (lambda (x)
(file-name-nondirectory x))
(dired-get-marked-files)))
EDIT: the following will give you a single, quoted string with internal quotes. Not sure if it'll play nicely with start-process:
(mapconcat
(lambda (x)
(concat "\"" (file-name-nondirectory x) "\""))
(dired-get-marked-files) " ")
EDIT: Righty-o, let's try this. Splice the backquoted list with ,#, then eval the whole thing:
(eval `(start-process
"name-of-process"
"*output-buffer*"
"/usr/bin/zip"
"zip-file-name.zip"
,#(mapcar
(lambda (x)
(file-name-nondirectory x))
(dired-get-marked-files))))

Related

Can't start emacs (spacemacs) anymore: Invalid read syntax: Invalid byte-code object

Can someone tell me how I can recover from this error? I runs emacs 28.0.50 with spacemacs 0.300.0#28.0.50 on Ubuntu 19.10.
Here is the backtrace from emacs --debug-init
Debugger entered--Lisp error: (invalid-read-syntax "Invalid byte-code object")
read(get-file-char)
require(use-package-core)
byte-code("\300\301!\210\300\302!\210\300\303!\210\300\304!\210\300\305!\210\306\307\310\311\312$\210\313\314!\207" [require use-package-core use-package-bind-key use-package-diminish use-package-delight use-package-ensure autoload use-package-jump-to-package-form "use-package-jump" nil t provide use-package] 5)
require(use-package)
spacemacs-bootstrap/init-use-package()
funcall(spacemacs-bootstrap/init-use-package)
(let* ((pkg-name (eieio-oref pkg ':name)) (owner (car (eieio-oref pkg ':owners)))) (spacemacs-buffer/message (format "%S -> init (%S)..." pkg-name owner)) (funcall (intern (format "%S/init-%S" owner pkg-name))))
configuration-layer//configure-package(#<cfgl-package cfgl-package-15636ced90d0>)
mapc(configuration-layer//configure-package (#<cfgl-package cfgl-package-15636ced6330> #<cfgl-package cfgl-package-15636ced7678> #<cfgl-package cfgl-package-15636ceccf10> #<cfgl-package cfgl-package-15636ced78e4> #<cfgl-package cfgl-package-15636ced7b48> #<cfgl-package cfgl-package-15636ced7db0> #<cfgl-package cfgl-package-15636ced90d0> #<cfgl-package cfgl-package-15636ced9340>))
(let (packages-to-configure) (let ((--dolist-tail-- packages) pkg-name) (while --dolist-tail-- (setq pkg-name (car --dolist-tail--)) (let ((pkg (configuration-layer/get-package pkg-name))) (cond ((eieio-oref pkg ':lazy-install) (spacemacs-buffer/message (format "%S ignored since it can be lazily installed." pkg-name))) ((and (eieio-oref pkg ...) (not ...)) (spacemacs-buffer/message (format "%S ignored since it has been excluded." pkg-name))) ((null (eieio-oref pkg ...)) (spacemacs-buffer/message (format "%S ignored since it has no owner layer." pkg-name))) ((not (configuration-layer//package-reqs-used-p pkg)) (spacemacs-buffer/message (format ... pkg-name))) ((not (cfgl-package-enabled-p pkg)) (spacemacs-buffer/message (format "%S is disabled." pkg-name))) (t (let (...) (if dir ...)) (if (memq ... ...) nil (configuration-layer//activate-package pkg-name)) (cond (... ...) (t ... ...))))) (setq --dolist-tail-- (cdr --dolist-tail--)))) (setq packages-to-configure (reverse packages-to-configure)) (mapc 'configuration-layer//configure-package packages-to-configure) (mapc 'configuration-layer//post-configure-package packages-to-configure))
configuration-layer//configure-packages-2((async bind-key bind-map diminish evil hydra use-package which-key))
configuration-layer//configure-packages((abbrev ac-ispell academic-phrases ace-jump-helm-line ace-link ace-window add-node-modules-path aggressive-indent all-the-icons all-the-icons-dired amx anaconda-mode anki-editor ansi-colors archive-mode async attrap auctex auctex-latexmk auto-compile auto-complete auto-correct auto-dim-other-buffers auto-highlight-symbol auto-yasnippet avy beacon biblio biblio-core bibtex bind-key bind-map blacken bnf-mode bookmark bracketed-paste bug-hunter calendar calibre-mode camcorder centered-cursor-mode cheat-sh chronometer clean-aindent-mode cloc cmm-mode color-identifiers-mode column-enforce-mode comint command-log-mode ...))
configuration-layer//load()
(cond (changed-since-last-dump-p (configuration-layer//load) (if (spacemacs/emacs-with-pdumper-set-p) (progn (configuration-layer/message "Layer list has changed since last dump.") (configuration-layer//dump-emacs)))) (spacemacs-force-dump (configuration-layer//load) (if (spacemacs/emacs-with-pdumper-set-p) (progn (configuration-layer/message (concat "--force-dump passed on the command line, " "forcing a redump.")) (configuration-layer//dump-emacs)))) ((spacemacs-is-dumping-p) (configuration-layer//load)) ((and (spacemacs/emacs-with-pdumper-set-p) (spacemacs-run-from-dump-p)) (configuration-layer/message "Running from a dumped file. Skipping the loading p...")) (t (configuration-layer//load) (if (spacemacs/emacs-with-pdumper-set-p) (progn (configuration-layer/message (concat "Layer list has not changed since last time. " "Skipping dumping process!"))))))
configuration-layer/load()
(let ((file-name-handler-alist nil)) (require 'core-spacemacs) (spacemacs/dump-restore-load-path) (configuration-layer/load-lock-file) (spacemacs/init) (configuration-layer/stable-elpa-init) (configuration-layer/load) (spacemacs-buffer/display-startup-note) (spacemacs/setup-startup-hook) (spacemacs/dump-eval-delayed-functions) (if (and dotspacemacs-enable-server (not (spacemacs-is-dumping-p))) (progn (require 'server) (if dotspacemacs-server-socket-dir (progn (setq server-socket-dir dotspacemacs-server-socket-dir))) (if (server-running-p) nil (message "Starting a server...") (server-start)))))
(if (not (version<= spacemacs-emacs-min-version emacs-version)) (error (concat "Your version of Emacs (%s) is too old. " "Spacemacs requires Emacs version %s or above.") emacs-version spacemacs-emacs-min-version) (let ((file-name-handler-alist nil)) (require 'core-spacemacs) (spacemacs/dump-restore-load-path) (configuration-layer/load-lock-file) (spacemacs/init) (configuration-layer/stable-elpa-init) (configuration-layer/load) (spacemacs-buffer/display-startup-note) (spacemacs/setup-startup-hook) (spacemacs/dump-eval-delayed-functions) (if (and dotspacemacs-enable-server (not (spacemacs-is-dumping-p))) (progn (require 'server) (if dotspacemacs-server-socket-dir (progn (setq server-socket-dir dotspacemacs-server-socket-dir))) (if (server-running-p) nil (message "Starting a server...") (server-start))))))
eval-buffer(#<buffer *load*-45090> nil "/home/chriad/.dotfiles/emacs.d/init.el" nil t) ; Reading at buffer position 1880
load-with-code-conversion("/home/chriad/.dotfiles/emacs.d/init.el" "/home/chriad/.dotfiles/emacs.d/init.el" nil nil)
load("/home/chriad/.dotfiles/emacs.d/init.el")
(let* ((emacs-directory (file-name-as-directory (chemacs-emacs-profile-key 'user-emacs-directory))) (init-file (expand-file-name "init.el" emacs-directory)) (custom-file- (chemacs-emacs-profile-key 'custom-file init-file)) (server-name- (chemacs-emacs-profile-key 'server-name))) (setq user-emacs-directory emacs-directory) (if server-name- (progn (setq server-name server-name-))) (mapcar #'(lambda (env) (setenv (car env) (cdr env))) (chemacs-emacs-profile-key 'env)) (if (chemacs-emacs-profile-key 'straight-p) (progn (chemacs-load-straight))) (load init-file) (if (not custom-file) (progn (setq custom-file custom-file-) (if (equal custom-file init-file) nil (load custom-file)))))
chemacs-load-profile("default")
(if args (let ((s (split-string (car args) "="))) (cond ((equal (car args) "--with-profile") (add-to-list 'command-switch-alist '("--with-profile" lambda (_) (pop command-line-args-left))) (chemacs-load-profile (car (cdr args)))) ((equal (car s) "--with-profile") (add-to-list 'command-switch-alist (cons (car args) '(lambda ...))) (chemacs-load-profile (mapconcat 'identity (cdr s) "="))) (t (chemacs-check-command-line-args (cdr args))))) (chemacs-load-profile (chemacs-detect-default-profile)))
chemacs-check-command-line-args(nil)
(cond ((equal (car args) "--with-profile") (add-to-list 'command-switch-alist '("--with-profile" lambda (_) (pop command-line-args-left))) (chemacs-load-profile (car (cdr args)))) ((equal (car s) "--with-profile") (add-to-list 'command-switch-alist (cons (car args) '(lambda (_)))) (chemacs-load-profile (mapconcat 'identity (cdr s) "="))) (t (chemacs-check-command-line-args (cdr args))))
(let ((s (split-string (car args) "="))) (cond ((equal (car args) "--with-profile") (add-to-list 'command-switch-alist '("--with-profile" lambda (_) (pop command-line-args-left))) (chemacs-load-profile (car (cdr args)))) ((equal (car s) "--with-profile") (add-to-list 'command-switch-alist (cons (car args) '(lambda (_)))) (chemacs-load-profile (mapconcat 'identity (cdr s) "="))) (t (chemacs-check-command-line-args (cdr args)))))
(if args (let ((s (split-string (car args) "="))) (cond ((equal (car args) "--with-profile") (add-to-list 'command-switch-alist '("--with-profile" lambda (_) (pop command-line-args-left))) (chemacs-load-profile (car (cdr args)))) ((equal (car s) "--with-profile") (add-to-list 'command-switch-alist (cons (car args) '(lambda ...))) (chemacs-load-profile (mapconcat 'identity (cdr s) "="))) (t (chemacs-check-command-line-args (cdr args))))) (chemacs-load-profile (chemacs-detect-default-profile)))
chemacs-check-command-line-args(("emacs"))
eval-buffer(#<buffer *load*> nil "/home/chriad/.emacs" nil t) ; Reading at buffer position 7021
load-with-code-conversion("/home/chriad/.emacs" "/home/chriad/.emacs" t t)
load("~/.emacs" noerror nomessage)
startup--load-user-init-file(#f(compiled-function () #<bytecode 0x2bc902d994a710f>) #f(compiled-function () #<bytecode 0x81a386fa1b19353>) t)
command-line()
normal-top-level()
I had the same issue this morning.
I'm using emacs 28.0.50 on Kubuntu 19.10.
My issue was gone by deleting use-package:
rm -rf ~/.emacs.d/elpa/use-package-*
# if using the `develop` branch:
# rm -rf ~/.emacs.d/elpa/<your emacs version>/develop/use-package-*
and re-installing it:
emacs -q
eval:
(progn
(require 'package)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
(package-initialize)
(package-refresh-contents)
(package-install 'use-package)
(require 'use-package)
)
For me it was a matter of doing "M-x reinstall-package RET use-package RET" and restarting Emacs.
Reinstalling use-package via the list-packages UI worked for me.
(Delete use-package, install it again)
I did not see a re-install option there.
Thank you for the hints here.
I received almost exactly the same error (emacs 28.0.50 with spacemacs 0.200.13#28.0.50 on Ubuntu 18.04). I updated the emacs packages and the problem disappeared. If I had any better ideas (or explanations) I would include them but that's all I got. Good luck!

How to use a cons cell to define and later remove overlays with `dolist`

I am looking for some guidance, please, to reduce the time needed to perform my custom overlay removal function. The delay of up to 0.1 seconds is caused because a plethora of variables all have values, however, not every variable is necessarily used.
My goal is to attach a second variable that can be set to non-nil whenever the first variable is used, but I am unsure how to set this up and how to incorporate that into the overlay removal function.
Perhaps something that looks like this would be useful:
if (variable-one . t), then (remove-overlays (point-min) (point-max) 'display character)
In the following example, M-x sub-char-mode will place an overlay over the characters 1, 2 or 3 whenever the cursor is visiting any of those characters:
1 will become |1
2 will become |2
3 will become |3
(defvar variable-one (concat
(propertize (char-to-string ?\u007C)
'face 'font-lock-warning-face
'cursor t)
(propertize "1" 'face 'highlight 'cursor t) ))
(defvar variable-one-p (cons variable-one nil))
(defvar variable-two (concat
(propertize (char-to-string ?\u007C)
'face 'font-lock-warning-face
'cursor t)
(propertize "2" 'face 'highlight 'cursor t) ))
(defvar variable-two-p (cons variable-two nil))
(defvar variable-three (concat
(propertize (char-to-string ?\u007C)
'face 'font-lock-warning-face
'cursor t)
(propertize "3" 'face 'highlight 'cursor t) ))
(defvar variable-three-p (cons variable-three nil))
(defun substitute-character ()
(cond
((eq (char-after (point)) 49)
(setq variable-one-p (cons variable-one t))
(overlay-put (make-overlay (point) (1+ (point))) 'display variable-one))
((eq (char-after (point)) 50)
(setq variable-two-p (cons variable-two t))
(overlay-put (make-overlay (point) (1+ (point))) 'display variable-two))
((eq (char-after (point)) 51)
(setq variable-three-p (cons variable-three t))
(overlay-put (make-overlay (point) (1+ (point))) 'display variable-three))))
(defun remove-sub-char ()
(dolist (character `(
,variable-one
,variable-two
,variable-three))
(remove-overlays (point-min) (point-max) 'display character))
(dolist (my-variable `(
,variable-one-p
,variable-two-p
,variable-three-p))
(setq my-variable nil)) )
(defun sub-char-post-command-hook ()
(remove-sub-char)
(substitute-character))
(define-minor-mode sub-char-mode
"A minor-mode for testing overlay-removal with cons cells."
:init-value nil
:lighter " OV-REMOVE"
:keymap nil
:global nil
:group 'lawlist
(cond
(sub-char-mode
(add-hook 'post-command-hook 'sub-char-post-command-hook nil t)
(message "Turned ON `sub-char-mode`."))
(t
(remove-hook 'post-command-hook 'sub-char-post-command-hook t)
(remove-sub-char)
(message "Turned OFF `sub-char-mode`."))))
Apologies for pasting this image here - feel free to remove it. But I couldn't paste it into a comment, to reply to your comment asking for the appearance. This is vline-style = compose and col-highlight-vline-face-flag = nil:
First Draft (August 24, 2014):  The first draft answer defines the variables as a cons cell -- the car is a predetermined overlay string, and the cdr is nil. When the cursor visits the characters 1, 2 or 3, an overlay is placed on top of those characters and the cdr of the applicable cons cell is set to t by using setcdr. The overlay removal function contains a list of variable names and the corresponding cons cells -- when the cdr of the cons cell is non-nil (i.e., t), the overlay is removed, and the cdr of the applicable cons cell is set back to nil using setcdr. The advantage of this type of setup is that the overlay removal function will quickly look at and then skip over variables whose cons cell cdr is nil -- thus saving a substantial amount of time when dealing with large quantities of variables with predetermined overlay strings.
EDIT (August 26, 2014):  Modified code to permit using the same variable names in different buffers and set buffer-local values. Related threads are: How to use `setcdr` with buffer-local variables and Incorporate variable name into `dolist` cycle and change its value .
(defvar variable-one
(cons
(concat
(propertize (char-to-string ?\u007C)
'face 'font-lock-warning-face
'cursor t)
(propertize "1" 'face 'highlight 'cursor t) )
nil))
(make-variable-buffer-local 'variable-one)
(defvar variable-two
(cons
(concat
(propertize (char-to-string ?\u007C)
'face 'font-lock-warning-face
'cursor t)
(propertize "2" 'face 'highlight 'cursor t) )
nil))
(make-variable-buffer-local 'variable-two)
(defvar variable-three
(cons
(concat
(propertize (char-to-string ?\u007C)
'face 'font-lock-warning-face
'cursor t)
(propertize "3" 'face 'highlight 'cursor t) )
nil))
(make-variable-buffer-local 'variable-three)
(defun sub-char ()
(cond
((eq (char-after (point)) 49)
(let ((newlist (copy-list variable-one)))
(setcdr newlist t)
(setq-local variable-one newlist)
(overlay-put (make-overlay (point) (1+ (point))) 'display (car variable-one))))
((eq (char-after (point)) 50)
(let ((newlist (copy-list variable-two)))
(setcdr newlist t)
(setq-local variable-two newlist)
(overlay-put (make-overlay (point) (1+ (point))) 'display (car variable-two))))
((eq (char-after (point)) 51)
(let ((newlist (copy-list variable-three)))
(setcdr newlist t)
(setq-local variable-three newlist)
(overlay-put (make-overlay (point) (1+ (point))) 'display (car variable-three))))))
(defun remove-sub-char ()
(dolist (character `(
(variable-one ,variable-one)
(variable-two ,variable-two)
(variable-three ,variable-three)))
(when (cdr (car (cdr character)))
(let* (
(var (car character))
(newlist (copy-list (car (cdr character)))) )
(remove-overlays (point-min) (point-max) 'display (car (car (cdr character))))
(setcdr newlist nil)
(set (car character) newlist)
(message "var1: %s | var2: %s | var3: %s" variable-one variable-two variable-three) ))))
(defun sub-char-post-command-hook ()
(remove-sub-char)
(sub-char))
(define-minor-mode sub-char-mode
"A minor-mode for testing overlay-removal with cons cells."
:init-value nil
:lighter " OV-REMOVE"
:keymap nil
:global nil
:group 'lawlist
(cond
(sub-char-mode
(add-hook 'post-command-hook 'sub-char-post-command-hook nil t)
(message "Turned ON `sub-char-mode`."))
(t
(remove-hook 'post-command-hook 'sub-char-post-command-hook t)
(remove-sub-char)
(message "Turned OFF `sub-char-mode`."))))
I suggest you start by getting rid of your variable-FOO-p vars: not only their names are wrong (the "-p" suffix is meant for use with predicates which are necessarily functions, and not variables) but they're unneeded. Rather than tell remove-overlays to remove all overlays with a particular display property, just add a property of your own (e.g. (overlay-put <youroverlay> 'vline t)) so you can then do a single (remove-overlays (point-min) (point-max) 'vline t). Of course, another approach which will work at least as well is to keep a single buffer-local variable (better yet, window-local) which holds a list of all the overlays you currently have placed. This way, you can remove those overlays with a single (mapc #'delete-overlay vline--overlays), which is more efficient. It can be made even more efficient by moving/reusing those overlays rather than deleting them and then creating new ones instead.

How does intelligent code completion work in Scheme?

From reading a Lisp book I remember they showed an example of an OOP-style method dispatcher based on closures:
(defun create-object ()
(let ((val 0)
(get (lambda () val))
(set (lambda (new-val) (setq val new-val)))
(inc (lambda () (setq val (+ 1 val)))))
(lambda (method)
(cond ((eq method 'get)
get)
((eq method 'set)
set)
((eq method 'inc)
inc)))))
(let ((obj (create-object)))
(funcall (obj 'set) 1)
(funcall (obj 'inc))
(funcall (obj 'get))) ;; 2
Since it's just a function with a string symbol argument, I guess code intel won't be of much help here, not completing the method names or their signatures. (Compare with a similar JavaScript object.)
Is this problem generally solved? How do you program an object system in Scheme so that an editor (like Emacs) can be more intelligent with your code?
P.S. The example may be not a valid Scheme code, but you should get the idea.
I've made some starting code for you.
It's for Emacs Lisp, but it's should be very easily portable to Scheme.
Here's your usage example:
(defun create-object ()
(lexical-let* ((val 0)
(get (lambda() val))
(set (lambda(x) (setq val x))))
(generate-dispatch-table get set)))
(setq obj (create-object))
(funcall (funcall obj 'get))
;; => 0
(funcall (funcall obj 'set) 1)
;; => 1
(funcall (funcall obj 'get))
;; => 1
(scheme-completions obj)
;; => (get set)
And here's how it's implemented:
(defmacro generate-dispatch-table (&rest members)
`(lambda (method)
(cond ,#(mapcar
(lambda (x) `((eq method ',x) ,x)) members))))
(defun collect (pred x)
(when (and x (listp x))
(let ((y (funcall pred x))
(z (append
(collect pred (car x))
(collect pred (cdr x)))))
(if y
(append (list y) z)
z))))
(defun scheme-completions (obj)
(collect
(lambda(x) (and (eq (car x) 'eq)
(eq (cadr x) 'method)
(eq (caaddr x) 'quote)
(cadr (caddr x))))
obj))
And here's a simple visual interface for completions:
(require 'helm)
(defun scheme-completions-helm ()
(interactive)
(let ((y (and
(looking-back "(funcall \\([^ ]*\\) +")
(intern-soft (match-string 1)))))
(when y
(helm :sources
`((name . "members")
(candidates . ,(scheme-completions (eval y)))
(action . (lambda(x) (insert "'" x))))))))
I'm not a Emacs user, but use DrRacket and it does have an object system and do what an IDE should do, but I know Emacs is very customizable since it uses elisp so you can make support for your own syntax both in syntax highlighting and tab-completion. So you do:
Make your own object system
Edit your Emacs editor to do what you want
Many of my colleagues use it and they fix their Emacs in such ways.
Another thing, this question makes me think about the resources at schemewiki.org on the subject where the different approaches are mentioned and even a similar code to the one you posted is posted as example. It's a good read.
I would avoid double notion of symbols in create-object via an obarray.
Furthermore, the interface of the object are all functions. Therefore, use fset and avoid the double funcall.
(defun create-object ()
(lexical-let (val
(_oa (make-vector 11 0)))
(fset (intern "get" _oa) (lambda () val))
(fset (intern "inc" _oa) (lambda () (incf val)))
(fset (intern "set" _oa) (lambda (new-val) (setq val new-val)))
(lambda (method &rest args)
(apply 'funcall (intern (symbol-name method) _oa) args))))
(fset 'obj1 (create-object))
(fset 'obj2 (create-object))
(obj1 'set 1)
(obj2 'set 2)
(obj1 'inc)
(obj2 'inc)
(obj2 'inc)
(obj2 'get)
(obj1 'get)
Example for inheritance:
(defun create-object ()
(lexical-let (val
(_oa (make-vector 11 0)))
(fset (intern "get" _oa) (lambda () val))
(fset (intern "inc" _oa) (lambda () (incf val)))
(fset (intern "set" _oa) (lambda (new-val) (setq val new-val)))
(lambda (method &rest args)
(apply 'funcall (or (intern-soft (symbol-name method) _oa)
(error "Undefined function: %s" method))
args))))
(defun create-object-add10 ()
(lexical-let ((base (create-object))
(_oa (make-vector 11 0)))
(fset (intern "inc" _oa) (lambda () (funcall base 'set (+ (funcall base 'get) 10))))
(lambda (method &rest args)
(let ((call (intern-soft (symbol-name method) _oa)))
(if call
(apply 'funcall call args)
(apply 'funcall base method args))))))
(fset 'obj1 (create-object))
(fset 'obj2 (create-object-add10))
(obj1 'set 1)
(obj2 'set 2)
(obj1 'inc)
(obj2 'inc)
(obj2 'inc)
(obj2 'get)
(obj1 'get)
The definition of create-object-like methods should additionally be supported through macros. That is not done here.
For more features, note, there is a CLOS-compatible object oriented system in emacs:
https://www.gnu.org/software/emacs/manual/html_node/eieio/index.html

In-Place Word/Symbol Dabbrev Expand

Here's my extension to dabbrev-expand to support sub-string expansion.It works as expected, as far as I know. However I would find it even more useful if it supported in-symbol expansion similar to the behaviour of mdabbrev, which, by the way, is incomplete in terms of symbol-character and case-adjustment support. The pattern argument to dabbrev-substring-search, however, is only the pattern before point but for in-place expansions we need the pattern after point aswell. Why isn't this pattern available in hippie/dabbrev-expand and is there a preferred way to query it?
(defun dabbrev-substring-search (pattern &optional reverse limit syntax-context)
"Expand dabbrev substring. See:
http://www.emacswiki.org/cgi-bin/wiki/HippieExpand#toc5"
(let ((result ())
(regpat (cond ((not hippie-epxand-dabbrev-as-symbol)
(concat (regexp-quote pattern) W*))
;; ((eq (char-syntax (aref pattern 0)) ?_)
;; (concat (regexp-quote pattern)
;; "\\(\\sw\\|\\s_\\)*"))
(t
(concat "\\(?:"
Y<
"\\(" "\\(?:\\sw\\|\\s_\\)+" "\\)"
"\\(" (regexp-quote pattern) "\\)"
"\\(" "\\(?:\\sw\\|\\s_\\)*" "\\)"
Y>
"\\)"
"\\|"
"\\(?:"
Y<
"\\(" "\\(?:\\sw\\|\\s_\\)*" "\\)"
"\\(" (regexp-quote pattern) "\\)"
"\\(" "\\(?:\\sw\\|\\s_\\)+" "\\)"
Y>
"\\)"
)))))
(while (and (not result)
(if reverse
(re-search-backward regpat limit t)
(re-search-forward regpat limit t)))
(setq result (buffer-substring-no-properties (save-excursion
(goto-char (match-beginning 0))
;;(skip-syntax-backward "w_")
(point))
(match-end 0)))
(if (he-string-member result he-tried-table t)
(setq result nil))) ; ignore if bad prefix or already in table
(when nil
(when result
(let* ((p (point))
(end3 (match-end 3))
(beg2 (match-end 2))
(end2 (match-end 2))
(dummy (message "%s %s %s" end3 beg2 end2))
(beg (- end3 beg2)) ;begin offset from point
(end (- end3 end2))) ;end offset from point
(setq dabbrev-substring-match-region (cons beg end))
(hictx-generic (- p beg) (- p end) nil 'match 3))))
result))
;; Use: (dabbrev-substring-search "he")
(defun try-expand-dabbrev-substring-visible (old)
"Like `try-expand-dabbrev' but for visible part of buffer."
(interactive "P")
(let ((old-fun (symbol-function 'he-dabbrev-search)))
(fset 'he-dabbrev-search (symbol-function 'dabbrev-substring-search))
(unwind-protect (try-expand-dabbrev-visible old)
(fset 'he-dabbrev-search old-fun))))
(defun try-expand-dabbrev-substring (old)
"Like `try-expand-dabbrev' but for substring match."
(interactive "P")
(let ((old-fun (symbol-function 'he-dabbrev-search)))
(fset 'he-dabbrev-search (symbol-function 'dabbrev-substring-search))
(unwind-protect (try-expand-dabbrev old)
(fset 'he-dabbrev-search old-fun))))
(defun try-expand-dabbrev-substring-all-buffers (old)
"Like `try-expand-dabbrev-all-buffers' but for substring match."
(interactive "P")
(let ((old-fun (symbol-function 'he-dabbrev-search)))
(fset 'he-dabbrev-search (symbol-function 'dabbrev-substring-search))
(unwind-protect (try-expand-dabbrev-all-buffers old)
(fset 'he-dabbrev-search old-fun))))
which is activated for example using
(setq hippie-expand-try-functions-list
(append
'(
try-expand-dabbrev-substring-visible
try-expand-dabbrev-substring
try-expand-dabbrev-substring-all-buffers)))
This might or might not help. Like ordinary dabbrev, it works with the text before point, but candidate matching can be substring, regexp, or fuzzy (various kinds), in addition to prefix. Icicles - Dynamic Abbreviation

Emacs determining keyboard layout

Is there a way for Emacs to detect the current keyboard layout?
I often write texts in English and German, switching the (Win OS) keyboard layout. However, some functions (C-Y e.g.) should always be at the same physical key, no matter what language Im currently typing in.
Thanks
Consider using M-x set-input-method and M-x toggle-input-method. Toggle is bound to C-\, set is bound to C-x RET C-\. I recommend this binding, if you have hyper key:
(global-set-key [?\H-\\] 'set-input-method).
If you asking not how to type in different language, but how to make several commands work when you using different languages in your OS, try just to bind them. It worked nice on russian symbols. One black-black night i even wrote
(setq russian-symbols '(
(?й . ?q)
(?ц . ?w)
(?у . ?e)
(?к . ?r)
(?е . ?t)
(?н . ?y)
(?г . ?u)
(?ш . ?i)
(?щ . ?o)
(?з . ?p)
(?х . ?\[)
(?ъ . ?\])
(?ф . ?a)
(?ы . ?s)
(?в . ?d)
(?а . ?f)
(?п . ?g)
(?р . ?h)
(?о . ?j)
(?л . ?k)
(?д . ?l)
(?ж . ?\;)
(?э . ?')
(?я . ?z)
(?ч . ?x)
(?с . ?c)
(?м . ?v)
(?и . ?b)
(?т . ?n)
(?ь . ?m)
(?б . ?,)
(?ю . ?.)
(?Й . ?Q)
(?Ц . ?W)
(?У . ?E)
(?К . ?R)
(?Е . ?T)
(?Н . ?Y)
(?Г . ?U)
(?Ш . ?I)
(?Щ . ?O)
(?З . ?P)
(?Х . ?{)
(?Ъ . ?})
(?Ф . ?A)
(?Ы . ?S)
(?В . ?D)
(?А . ?F)
(?П . ?G)
(?Р . ?H)
(?О . ?J)
(?Л . ?K)
(?Д . ?L)
(?Ж . ?:)
(?Э . ?\")
(?Я . ?Z)
(?Ч . ?X)
(?С . ?C)
(?М . ?V)
(?И . ?B)
(?Т . ?N)
(?Ь . ?M)
(?Б . ?<)
(?Ю . ?>)
(?Ё . ?~)
(?ё . ?`)
))
(setq russian-symbols-full (append russian-symbols
'((?. . ?/)
(?, . ??)
(?\" . ?#)
(?№ . ?#)
(?\; . ?$)
(?: . ?^)
(?\? . ?&))))
(defun cm-ru-to-en-string(string)
(apply 'concat (mapcar (lambda (arg) (setq arg (format "%c" (or (cdr (assoc arg russian-symbols-full)) arg)))) string)))
(defun cm-en-to-ru-string(string)
(apply 'concat (mapcar (lambda (arg) (setq arg (format "%c" (or (car (rassoc arg russian-symbols-full)) arg)))) string)))
(defun cm-ru-to-en-region()
(interactive)
(let ((text (buffer-substring-no-properties (mark) (point))))
(delete-region (mark) (point))
(insert (cm-ru-to-en-string text))))
(defun cm-en-to-tu-region()
(interactive)
(let ((text (buffer-substring-no-properties (mark) (point))))
(delete-region (mark) (point))
(insert (cm-en-to-ru-string text))))
;; DO NOT USE vvv SINCE YOU WILL NOT BE ABLE TO INPUT THROUGH C-\
;; (let ((symbols russian-symbols))
;; (while symbols
;; (global-set-key (vector (car (car symbols))) (vector (cdr (car symbols))))
;; (setq symbols (cdr symbols))))
;; DO NOT USE ^^^ SINCE YOU WILL NOT BE ABLE TO INPUT THROUGH C-\
;; (- ?\C-ы ?ы) ;;russian C-
;; (- ?\C-s ?s) ;;english C-
;; (- ?\M-ы ?ы) ;;russian M-
;; (- ?\M-s ?s) ;;english M-
(setq russian-symbols-map1
(append
(mapcar (lambda (arg) (setq arg (cons (+ (- ?\C-ы ?ы) (car arg)) (+ (- ?\C-s ?s) (cdr arg))))) russian-symbols)
(mapcar (lambda (arg) (setq arg (cons (+ (- ?\M-ы ?ы) (car arg)) (+ (- ?\M-s ?s) (cdr arg))))) russian-symbols)
(mapcar (lambda (arg) (setq arg (cons (+ (- ?\C-\M-ы ?ы) (car arg)) (+ (- ?\C-\M-s ?s) (cdr arg))))) russian-symbols)
(mapcar (lambda (arg) (setq arg (cons (+ (- ?\H-ы ?ы) (car arg)) (+ (- ?\H-s ?s) (cdr arg))))) russian-symbols)
(mapcar (lambda (arg) (setq arg (cons (+ (- ?\H-\C-ы ?ы) (car arg)) (+ (- ?\H-\C-s ?s) (cdr arg))))) russian-symbols)
(mapcar (lambda (arg) (setq arg (cons (+ (- ?\H-\M-ы ?ы) (car arg)) (+ (- ?\H-\M-s ?s) (cdr arg))))) russian-symbols)
(mapcar (lambda (arg) (setq arg (cons (+ (- ?\H-\C-\M-ы ?ы) (car arg)) (+ (- ?\H-\C-\M-s ?s) (cdr arg))))) russian-symbols)))
(setq russian-symbols-map2
(append
russian-symbols-map1
russian-symbols)) ; We must not start with russian letters, but if it is element in a sequence - in should be fine.
(setq symbols2 russian-symbols-map1) ; One-key sequence command.
(let ((symbols2 russian-symbols-map1))
(while symbols2
(if
(and (symbolp (lookup-key global-map
(vector
(cdr (car symbols2))
)))
(lookup-key global-map
(vector
(cdr (car symbols2))
)))
(global-set-key
(vector
(car (car symbols2))
)
(lookup-key global-map
(vector
(cdr (car symbols2))
))))
(setq symbols2 (cdr symbols2))))
(let ((symbols1 russian-symbols-map2) (symbols2 russian-symbols-map1)) ; Two keys sequence
(while symbols1
(while symbols2
(if
(and (symbolp (lookup-key global-map
(vector
(cdr (car symbols2))
(cdr (car symbols1))
)))
(lookup-key global-map
(vector
(cdr (car symbols2))
(cdr (car symbols1))
)))
(global-set-key
(vector
(car (car symbols2))
(car (car symbols1))
)
(lookup-key global-map
(vector
(cdr (car symbols2))
(cdr (car symbols1))
))))
(setq symbols2 (cdr symbols2)))
(setq symbols2 russian-symbols-map1)
(setq symbols1 (cdr symbols1))))
(provide 'shamanizm) ;russian emacs-users should lol reading this
It works. I've binded all global hotkeys up to 2 level with russian symbols.
I am not using it now, it eat startup time, and it ruins readability of my *Help* with crazy things like It is bound to C-x b, C-x и, C-ч b, C-ч и. Use it wisely.