Intelligent auto closing matching characters - emacs

In some of the modes I'm using, emacs helps me by auto closing some elements such as quotes, parenthesis.
However some times, out of habit I type the closing element my self and end up with ()) or """.
How can I set up emacs to ignore the extra key?

While it is fun to roll your own, autopair has emerged as the canonical solution to this problem. It does everything you ask, and a few things, you didn't know you wanted. Emacs wiki entry.
Emacs 24 (currently in pretest) will be prepackaged with an electric pairing package. Autopair is still much more sophisticated than the builtin one.

EDIT: I had had the following in my .emacs for a while, and it worked fine so I didn't think too much about it. As event_jr points out in his answer, the same features (and apparently a bit more) can be had with the autopairs.el package, linked from the same page that I got this code from.
I have the following code in my .emacs to do this, taken from the emacs wiki:
(setq skeleton-pair t)
(setq skeleton-pair-alist
'((?\( _ ?\))
(?[ _ ?])
(?{ _ ?})
(?\" _ ?\")))
(defun autopair-insert (arg)
(interactive "P")
(let (pair)
(cond
((assq last-command-char skeleton-pair-alist)
(autopair-open arg))
(t
(autopair-close arg)))))
(defun autopair-open (arg)
(interactive "P")
(let ((pair (assq last-command-char
skeleton-pair-alist)))
(cond
((and (not mark-active)
(eq (car pair) (car (last pair)))
(eq (car pair) (char-after)))
(autopair-close arg))
(t
(skeleton-pair-insert-maybe arg)))))
(defun autopair-close (arg)
(interactive "P")
(cond
(mark-active
(let (pair open)
(dolist (pair skeleton-pair-alist)
(when (eq last-command-char (car (last pair)))
(setq open (car pair))))
(setq last-command-char open)
(skeleton-pair-insert-maybe arg)))
((looking-at
(concat "[ \t\n]*"
(regexp-quote (string last-command-char))))
(replace-match (string last-command-char))
(indent-according-to-mode))
(t
(self-insert-command (prefix-numeric-value arg))
(indent-according-to-mode))))
(defun autopair-backspace (arg)
(interactive "p")
(if (eq (char-after)
(car (last (assq (char-before) skeleton-pair-alist))))
(and (char-after) (delete-char 1)))
(delete-backward-char arg))
(global-set-key [backspace] 'autopair-backspace)
(define-key isearch-mode-map [backspace] 'isearch-delete-char) ;; required to fix behaviour in isearch
(global-set-key "(" 'autopair-insert)
(global-set-key ")" 'autopair-insert)
(global-set-key "[" 'autopair-insert)
(global-set-key "]" 'autopair-insert)
(global-set-key "{" 'autopair-insert)
(global-set-key "}" 'autopair-insert)
(global-set-key "\"" 'autopair-insert)

I'm not sure if it's Emacs 24 feature only, but electric-pair-mode seems to do what you want.

Related

Emacs; custom functions defined repetitively, how to use dolist, or other approach

Emacs' Bookmarks are great, as is navigating the list of buffers. But I find it nice to have shorter chords to get directly to where I want to go. So I have been accruing a repetitive set of functions and keybindings for all my favorite files and folders.
I wondered if I could use a dolist to handle this repetitiveness, but am no good programmer.
Here is one of the (seven and rising) repetitively defined functions, and a feeble attempt at writing the dolist following:
(defun jump-to-main ()
(interactive)
(find-file main))
(global-set-key (kbd "C-c m") 'jump-to-main)
This might barely qualify as pseudocode:
(dolist (x '(("m" main)
("t" tech))
(defun (concat 'jump-to- (cdr x)) ()
(interactive)
(find-file (cdr x)))
(global-set-key (kbd (concat "C-c " (car x)))
'(concat 'jump-to- (cdr x)))
))
The payoff in an elegant init file, versus how fast I am at solving at Lisp problems... hoping the Stackoverflow can save me.
Other strategies and approaches are appreciated.
EDIT:
With lawlist's suggestion, my question may reduce and be more clear presented the following way. I would like to reduce the repetition in the following series of keybindings.
(global-set-key (kbd "C-c A")
(lambda ()
(interactive)
(find-file fileA)))
(global-set-key (kbd "C-c B")
(lambda ()
(interactive)
(find-file fileB)))
...
(global-set-key (kbd "C-c Z")
(lambda ()
(interactive)
(find-file fileZ)))
fileK for example expands to something like "~/fileK.txt".
EDIT:
So here is another try:
(dolist (x '(("m" main)
("t" tech))
(global-set-key (kbd (concat "C-c " (car x)))
(lambda ()
(interactive)
(find-file (cdr x))
))))
The keybinding part seems okay, but (find-file (cdr x)) isn't doing what I need, and I couldn't fix it in a small amount of googling lisp.
Here are the expressions I'm using to focus on the broken parts:
(setq somefile "~/somefile.txt")
(setq x '("s" . somefile))
(concat "C-c " (car x))
(find-file (cdr x))
The last line is the one that doesn't work, as (cdr x) apparently evaluates to (main). I tried slipping in an eval to expand the main variable, but it doesn't seem...
Reading Phil's answer now, this may take me a while.
FWIW, a fairly direct translation of your pseudo-code is:
(defvar my-file-main (expand-file-name "~/main") "My main file")
(defvar my-file-tech (expand-file-name "~/tech") "My tech file")
(dolist (x '(("m" . my-file-main)
("t" . my-file-tech)))
(let* ((sym (cdr x))
(func (intern (concat "jump-to-" (symbol-name sym)))))
(defalias func `(lambda ()
,(format "Jump to file `%s'." (symbol-name sym))
(interactive)
(find-file ,sym)))
(global-set-key (kbd (concat "C-c " (car x))) func)))

Toggle case of next letter in elisp

I'd like to be able to toggle the case of the letter under the point. To that end, I wrote this:
(defun toggle-case-next-letter ()
"Toggles the case of the next letter, then moves the point forward one character"
(interactive)
(let* ((p (point))
(upcased (upcasep (char-after)))
(f (if upcased 'downcase-region 'upcase-region)))
(progn
(f p (+ 1 p))
(forward-char))))
However, when I run it (I've bound it to M-#), I get progn: Symbol's function definition is void: f. I assume this means f isn't bound, but I'm not sure.
Upcasep is defined as:
(defun upcasep (c) (eq c (upcase c)))
Is the problem in the let binding, or something else? (Also, if there's a better way to do this, that'd be nice as well).
Note that originally I had (upcased (upcasep (buffer-substring-no-properties p (+ 1 p)))), which I've corrected to (upcased (upcasep (char-after)), because using upcasep as defined above is always nil for strings (so I couldn't downcase again).
You've got a typical case of lisp-1 / lisp-2 confusion. Here's a fix (just a funcall):
(defun toggle-case-next-letter ()
"Toggles the case of the next letter, then moves the point forward one character"
(interactive)
(let* ((p (point))
(upcased (char-upcasep (buffer-substring-no-properties p (+ 1 p))))
(f (if upcased 'downcase-region 'upcase-region)))
(progn
(funcall f p (+ 1 p))
(forward-char))))
And here's what I have:
(global-set-key (kbd "C->") 'upcase-word-toggle)
(global-set-key (kbd "C-z") 'capitalize-word-toggle)
(defun char-upcasep (letter)
(eq letter (upcase letter)))
(defun capitalize-word-toggle ()
(interactive)
(let ((start (car
(save-excursion
(backward-word)
(bounds-of-thing-at-point 'symbol)))))
(if start
(save-excursion
(goto-char start)
(funcall
(if (char-upcasep (char-after))
'downcase-region
'upcase-region)
start (1+ start)))
(capitalize-word -1))))
(defun upcase-word-toggle ()
(interactive)
(let ((bounds (bounds-of-thing-at-point 'symbol))
beg end
regionp)
(if (eq this-command last-command)
(setq regionp (get this-command 'regionp))
(put this-command 'regionp nil))
(cond
((or (region-active-p) regionp)
(setq beg (region-beginning)
end (region-end))
(put this-command 'regionp t))
(bounds
(setq beg (car bounds)
end (cdr bounds)))
(t
(setq beg (point)
end (1+ beg))))
(save-excursion
(goto-char (1- beg))
(and (re-search-forward "[A-Za-z]" end t)
(funcall (if (char-upcasep (char-before))
'downcase-region
'upcase-region)
beg end)))))
I couldn't get #abo-abo's answer working for me but using his comments I was able to google better and found the following at http://chneukirchen.org/dotfiles/.emacs
(defun chris2-toggle-case ()
(interactive)
(let ((char (following-char)))
(if (eq char (upcase char))
(insert-char (downcase char) 1 t)
(insert-char (upcase char) 1 t)))
(delete-char 1 nil)
(backward-char))
(global-set-key (kbd "M-#") 'chris2-toggle-case)
This answers the original question if you remove (backward-char).
I realize this is a very old question, but having stumbled upon the same problem recently, I'd like to suggest a simpler solution.
I start with a pure function for toggling character case, based on char code property inspection:
(cl-defun toggle-char-case (c)
(cl-case (get-char-code-property c 'general-category)
(Lu (downcase c))
(Ll (upcase c))
(t c)))
I then use it from within an interactive function operating at point:
(cl-defun toggle-char-case-at-point ()
(interactive)
(let ((new (toggle-char-case (char-after))))
(delete-char 1)
(insert new)))
I then bound this interactive function to a keybinding of my choice:
(global-set-key (kbd "C-M-c") 'toggle-char-case-at-point)
The way this function operates is, after toggling the case it advances the point by one. So calling it repeatedly will toggle the cases of a sequence of chars. One could make it keep the point unchanged - that would require adding (backward-char) to the body.

How to bind keys to indent/unindent region in emacs?

I want to define two key-bindings to indent/unindent region by 4 spaces.
Before:
hello
world
foo
bar
Visually select world and foo.
Type >
After:
hello
world
foo
bar
I also want to bind < to unindent region.
I'm not familiar with emacs, please help.
There are already keyboard shortcuts for that:
Indent: C-u 4 C-x TAB
Unindent C-u - 4 C-x TAB
If you find that too long to type, you could put the following in your .emacs file:
(defun my-indent-region (N)
(interactive "p")
(if (use-region-p)
(progn (indent-rigidly (region-beginning) (region-end) (* N 4))
(setq deactivate-mark nil))
(self-insert-command N)))
(defun my-unindent-region (N)
(interactive "p")
(if (use-region-p)
(progn (indent-rigidly (region-beginning) (region-end) (* N -4))
(setq deactivate-mark nil))
(self-insert-command N)))
(global-set-key ">" 'my-indent-region)
(global-set-key "<" 'my-unindent-region)
With this code the greater than (>) and less than (<) keys will indent/unindent a marked region by 4 spaces each.
(defun keyboard-indent (&optional arg)
(interactive)
(let ((deactivate-mark nil)
(beg (or (and mark-active (region-beginning))
(line-beginning-position)))
(end (or (and mark-active (region-end)) (line-end-position))))
(indent-rigidly beg end (* (or arg 1) tab-width))))
(defun keyboard-unindent (&optional arg)
(interactive)
(keyboard-indent (* -1 (or arg 1))))
In addition to what #Thomas already wrote, you might not want to use the keys < and > for indenting or unindenting. Just image you need to write some HTML and can't enter those characters anymore. This is why I inserted the following in my init file, as key settings:
(global-set-key (kbd "C-<") 'my-indent-region)
(global-set-key (kbd "C->") 'my-unindent-region)
Note: It doesn't work without the (kbd ...). You will get an error:
global-set-key: Key sequence C - > starts with non-prefix key C
You can use replace 4 with tab-width as
(defun indent-region-shift-right-n (N)
(interactive "p")
(if (use-region-p)
(progn (indent-rigidly (region-beginning) (region-end) (* N tab-width))
(setq deactivate-mark nil))
(self-insert-command N)))
(defun unindent-region-shift-left-n (N)
(interactive "p")
(if (use-region-p)
(progn (indent-rigidly (region-beginning) (region-end) (* N (- tab-width)))
(setq deactivate-mark nil))
(self-insert-command N)))
(global-set-key ">" 'indent-region-shift-right-n)
(global-set-key "<" 'unindent-region-shift-left-n)

eval every line in the scratch buffer and append the result to the line

I've got this snippet of code:
(define-key lisp-interaction-mode-map (kbd "C-c C-e")
(lambda ()
(let ((result (eval (read (buffer-substring
(point-at-bol) (point-at-eol)))))
(goto-char (point-at-eol))))
(insert (format " ; => %s" result))))
but it doesn't work, as in
Wrong type argument: commandp, (lambda nil (let ((result (eval (read (buffer-substring (point-at-bol) (point-at-eol))))) (goto-char (point-at-eol)))) (insert (format " ; => %s" result)))
This command shouldn't function on a per-line basis. Move point by sexp instead.
Here is a library I made that does basically this, but works with mult-line
results, and is reentrant. So you can change some stuff, and re-run the
command to update results.
EDIT: correct link to package mentioned.
Solved.
(define-key lisp-interaction-mode-map (kbd "C-c C-e")
(lambda ()
(interactive)
(let ((result (eval (read (buffer-substring
(point-at-bol) (point-at-eol))))))
(goto-char (point-at-eol))
(insert (format " ; ⇒ %s" result)))))

How can I execute a lisp function while pressing prefix key C-h and then let Emacs continue the normal processing of C-h?

I want to execute a lisp function while pressing prefix key C-h and then let Emacs continue the normal processing of C-h.
How can I do it?
Thank you!
Evaluating
(key-binding [(control h)])
I found out the command bound is help-command. You can use an "around" defadvice to run your code. See manual.
(defvar smart-ime--state 'normal)
(defvar smart-ime--debug nil)
(defvar smart-ime--ena-prefix-override-keymap nil)
(defvar smart-ime--prefix-override-keymap (make-sparse-keymap))
(defvar smart-ime--keymaps-initialized nil)
(defvar smart-ime--keymap-alist
`(
(smart-ime--ena-prefix-override-keymap . ,smart-ime--prefix-override-keymap)
)
)
(defun smart-ime--init-keymaps ()
(define-key smart-ime--prefix-override-keymap [(control x)] 'smart-ime--prefix-override-handler)
(define-key smart-ime--prefix-override-keymap [(control c)] 'smart-ime--prefix-override-handler)
(define-key smart-ime--prefix-override-keymap [(control h)] 'smart-ime--prefix-override-handler)
)
(defun smart-ime--prefix-override-handler (arg)
(interactive "P")
(smart-ime--prefix-override-replay arg))
;; the most important part
(defun smart-ime--prefix-override-replay (arg)
(let* ((keys (this-command-keys))
(i (length keys))
(key (aref keys (1- i))))
(ime-save-and-set-status 0)
(add-hook 'post-command-hook 'smart-ime--post-command-handler)
(setq smart-ime--state 'prefix)
(setq smart-ime--ena-prefix-override-keymap nil)
;; Don't record this command
(setq this-command last-command)
;; Restore the prefix arg
(setq prefix-arg arg)
(reset-this-command-lengths)
;; Push the key back on the event queue
(setq unread-command-events (cons key unread-command-events))))
(defun smart-ime--post-command-handler-1 ()
(cond ((eq smart-ime--state 'prefix)
(setq smart-ime--state 'sequence))
((eq smart-ime--state 'sequence)
(ime-restore-status)
(setq smart-ime--ena-prefix-override-keymap t)
(setq smart-ime--state 'normal)
(remove-hook 'post-command-hook 'smart-ime--post-command-handler)))
(t
(error "error state")))
(defun smart-ime--post-command-handler ()
(when smart-ime-mode
(condition-case nil
(smart-ime--post-command-handler-1)
(error nil))))
(define-minor-mode smart-ime-mode
"Toggle Smart IME mode."
:init-value nil
:lighter " SmartIME"
:global t
(unless smart-ime--keymaps-initialized
(smart-ime--init-keymaps)
(setq smart-ime--keymaps-initialized t))
(unless smart-ime-mode
(remove-hook 'post-command-hook 'smart-ime--post-command-handler))
(if (not smart-ime-mode)
(setq emulation-mode-map-alists (delq 'smart-ime--keymap-alist emulation-mode-map-alists))
(add-to-ordered-list 'emulation-mode-map-alists 'smart-ime--keymap-alist 400)
(setq smart-ime--ena-prefix-override-keymap t))
)
;;; Announce
(provide 'smart-ime)