Emacs run forward char in a hook - emacs

I wrote this below to get to search for the next period in tex mode. It works fine except trying to get it to move forward a char after it finds the period. I am not sure how to do this but here was my attempt.
(add-hook 'text-mode-hook (lambda ()
(local-set-key (kbd "s-p")
(lambda () (interactive) ((search-backward "." nil t) (forward-char))))))
Final solution I combined the functions from ajk solution. I couldn't get the other one working without the add-hook. Someone might know how to get the second one working. The below completely works and searches backward for the previous period unless it is currently at a period.
(add-hook 'text-mode-hook
(lambda ()
(local-set-key (kbd "s-p")
(lambda ()
(interactive)
(if (looking-back "\.")
(backward-char))
(search-backward "." nil t)
(forward-char)))))
Thanks for the help.

You have parentheses around the last two function calls in the anonymous function you're assigning to the key, causing Emacs Lisp to think you want to call a function named (search-backward "." nil t). Try
(add-hook 'text-mode-hook
(lambda ()
(local-set-key (kbd "s-p")
(lambda ()
(interactive)
(search-backward "." nil t)
(forward-char)))))
The problem I would have with this binding is it's not repeatable. If you run it a second time, it finds the same period you just found. You might want to check to see if the previous character is a period and if so, skip it. Also, you can simplify it a bit by using define-key to add the binding explicitly to the text-mode keymap:
(define-key text-mode-map (kbd "s-p")
(lambda ()
(interactive)
(if (looking-back "\.")
(backward-char))
(search-backward "." nil t)
(forward-char)))

Related

Emacs bindings documentation

I am writing some bindings to lambdas in my ~/.emacs and would like to have a description of what the function does appear when I do (for example) C-c ?. I tried to put a string immediately after lambda () but that still does nothing. How do I get something relevant to appear in the binding column?
Example that still functionally works but documentation doesn't:
(global-set-key (kbd "M-p") (lambda ()
"Moves the current line up by one"
(interactive)
(let ((col (current-column)))
(transpose-lines 1)
(forward-line -2)
(forward-char col))))
You should use defun to define your interactive function and bind to that.
(defun my-func ()
"Moves the current line up by one"
(interactive)
(let ((col (current-column)))
(transpose-lines 1)
(forward-line -2)
(forward-char col)))
(global-set-key (kbd "M-p") 'my-func)

local keymap for emacs outline-minor-mode

I want to set the outline-minor-mode for init.el file and when TAB key is pressed on the lines starting with ; the function outline-toggle-children should be called in order to fold and expand the sub headings.
Below is the code for hook. But it does not work for the "TAB" key binding as expected.
(add-hook 'emacs-lisp-mode-hook
(lambda ()
(if (equal (buffer-name) "init.el")
(progn
(outline-regexp "^;+")
(outline-minor-mode 1)
(local-set-key (kbd "TAB") ; this does not work
(lambda ()
(if (string-match outline-regexp (thing-at-point 'line))
(outline-toggle-children))))))))
I presume that the error you get is wrong-type-argument commandp. This happens because functions bound to keys must be "interactive" functions. You need to add an (interactive) declaration to the function, so that Emacs knows how to invoke the function in response to an event:
(lambda ()
(interactive)
(if (string-match outline-regexp (thing-at-point 'line))
(outline-toggle-children)))

Emacs complaining with invalid function?

When I press C-c c with the following code on a buffer, Emacs complains with Invalid function: (select-current-line). Why?
(defun select-current-line ()
"Select the current line"
(interactive)
(end-of-line) ; move to end of line
(set-mark (line-beginning-position)))
(defun my-isend ()
(interactive)
(if (and transient-mark-mode mark-active)
(isend-send)
((select-current-line)
(isend-send)))
)
(global-set-key (kbd "C-c c") 'my-isend)
Not that it matters, but for those interested isend-send is defined here.
You are missing a progn form to group statements together:
(defun my-isend ()
(interactive)
(if (and transient-mark-mode mark-active)
(isend-send)
(progn
(select-current-line)
(isend-send))))
Without the progn form, ((select-current-line) (isend-send)) is interpreted as the (select-current-line) function applied to the result of calling isend-send without arguments. But (select-current-line) is not a valid function name. In other LISPs, such a construct could be valid if the return value of select-current-line was itself a function, which would then be applied to (isend-send). But this is not the case of Emacs LISP and this would not do what you wanted to achieve anyway...

In emacs, how do I save without running save hooks?

I have various things set up in my 'before-save-hook. For example, I run 'delete-trailing-whitespace. This is what I want in almost all occasions.
But sometimes, I'm working on files that are shared with other people, and the file already has a bunch of trailing whitespace. If I save the file, I'll get a big diff that's pretty confusing, as my change is buried in dozens or hundreds of meaningless changes. Yes, everyone could just tell their diff tool to not show whitespace changes, but that's something that everyone has to do every time they look at the diff. I'd rather not even have the whitespace change.
Is there anything I can do to save the file without the whitespace changes, short of starting a new instance of Emacs with no init.el file, or with a modified init.el that doesn't have the hook?
Here is how I save without triggering delete-trailing-whitespace:
C-x C-q C-x C-s C-x C-q: read-only, save, revert read-only
A simpler solution I came up with is that my fundamental-mode has no hooks installed, because I want it to be as plain as possible. Thus if I want to save a file without running hooks, I temporarily switch to fundamental-mode.
Based on a comment discussion with #Stefan, here are two possible (untested) solutions:
Use let:
(defun save-buffer-without-dtw ()
(interactive)
(let ((b (current-buffer))) ; memorize the buffer
(with-temp-buffer ; new temp buffer to bind the global value of before-save-hook
(let ((before-save-hook (remove 'delete-trailing-whitespace before-save-hook)))
(with-current-buffer b ; go back to the current buffer, before-save-hook is now buffer-local
(let ((before-save-hook (remove 'delete-trailing-whitespace before-save-hook)))
(save-buffer)))))))
Use unwind-protect:
(defun save-buffer-without-dtw ()
(interactive)
(let ((restore-global
(memq 'delete-trailing-whitespace (default-value before-save-hook)))
(restore-local
(and (local-variable-p 'before-save-hook)
(memq 'delete-trailing-whitespace before-save-hook))))
(unwind-protect
(progn
(when restore-global
(remove-hook 'before-save-hook 'delete-trailing-whitespace))
(when restore-local
(remove-hook 'before-save-hook 'delete-trailing-whitespace t))
(save-buffer))
(when restore-global
(add-hook 'before-save-hook 'delete-trailing-whitespace))
(when restore-local
(add-hook 'before-save-hook 'delete-trailing-whitespace nil t)))))
The problem with the second solution is that the order of functions in the before-save-hook may change.
Here's another solution:
(defvar my-inhibit-dtw nil)
(defun my-delete-trailing-whitespace ()
(unless my-inhibit-dtw (delete-trailing-whitespace)))
(add-hook 'before-save-hook 'my-delete-trailing-whitespace)
and then
(defun my-inhibit-dtw ()
(interactive)
(set (make-local-variable 'my-inhibit-dtw) t))
so you can M-x my-inhibit-dtw RET in the buffers where you don't want to trim whitespace.
I wrote a command inspired by Nicholas Douma's solution.
(defun olav-save-buffer-as-is ()
"Save file \"as is\", that is in read-only-mode."
(interactive)
(if buffer-read-only
(save-buffer)
(read-only-mode 1)
(save-buffer)
(read-only-mode 0)))
What we need to do is remove 'delete-trailing-whitespace from before-save-hook, save the buffer, then add it back.
This code will do that, but only remove and add it if it's there to begin with.
;; save the buffer, removing and readding the 'delete-trailing-whitespace function
;; to 'before-save-hook if it's there
(defun save-buffer-no-delete-trailing-whitespace ()
(interactive)
(let ((normally-should-delete-trailing-whitespace (memq 'delete-trailing-whitespace before-save-hook)))
(when normally-should-delete-trailing-whitespace
(remove-hook 'before-save-hook 'delete-trailing-whitespace))
(save-buffer)
(when normally-should-delete-trailing-whitespace
(add-hook 'before-save-hook 'delete-trailing-whitespace))))
(global-set-key (kbd "C-c C-s") 'save-buffer-no-delete-trailing-whitespace)
It also binds the command to (kbd C-c C-s), for convenience.

Redefining ENTER key in Emacs

I don't know elisp, but I'm trying to do something like the following:
(add-hook
'scala-mode-hook
(lambda ()
(define-key scala-mode-map (kbd "RET") (lambda ()
(scala-newline)
(scala-indent-line)))))
Goal is to call the two functions each time I hit the ENTER key. How do I actually do this?
I do essentially this in so many modes that I've squashed them all together:
(mapcar (lambda (hooksym)
(add-hook hooksym
(lambda ()
(local-set-key (kbd "C-m") 'newline-and-indent)
)))
'(
clojure-mode-hook
emacs-lisp-mode-hook
erlang-mode-hook
java-mode-hook
js-mode-hook
lisp-interaction-mode-hook
lisp-mode-hook
makefile-mode-hook
nxml-mode-hook
python-mode-hook
ruby-mode-hook
scheme-mode-hook
sh-mode-hook
))
Just stick scala-mode-hook in there somewhere and it'll work for you too :)
You need an (interactive) form after the lambda in your define-key.
EDIT:
To be clear, the inner form should look like:
(lambda ()
(interactive)
(scala-newline)
(scala-indent-line))
In hook you can use local-set-key, for example
(add-hook 'scala-mode-hook
(lambda ()
(local-set-key [return]
(lambda ()
(scala-newline)
(scala-indent-line)))))
although, maybe it will be easier to use something like standard newline-and-indent?
(add-hook 'scala-mode-hook
(lambda ()
(local-set-key [return] 'newline-and-indent)))
Just type C-j it will call the newline-and-indent command and do exactly what you ask.