Make hook local in emacs - hook

How do I make this hook local:
(add-hook 'text-mode-hook(lambda ()
(set-frame-width (selected-frame) 80) ))
I want it to only effect the current buffer and not new buffers in other modes.
EDIT: found an even better way to narrow the frame to my liking:
(add-hook 'window-configuration-change-hook
(lambda ()
(set-window-margins (car (get-buffer-window-list (current-buffer) nil t)) 24 24)))
This of course is a hook in itself but the question remains the same:
How can I have the margins set to 24 24 when I change to text-mode and have them change back when I switch mode.

Great that a solution was found! For the record, I'll just add that a hook can be made buffer-local in Emacs. This may not be what the original question was after since a buffer-local variable applies to a specific buffer - not a specific mode or frame.
Anyway, the Emacs manual states on Hooks:
If the hook variable is buffer-local, the buffer-local variable will be used instead of the global variable. However, if the buffer-local variable contains the element t, the global hook variable will be run as well.
A hook can be made buffer-local by adding a fourth non-nil argument to add-hook as in:
(add-hook 'text-mode-hook #'the-function-to-add nil t)
See also: Buffer-local after-save-hook?

Hooks are, per definition, not local. They are designed so that whenever a new buffer is created in text mode (in this case), they run their hook.
In your case, this mean that whenever you create a new text file, your frame will be resized.
If you only want to do this once, you can easily create a command that does this.
(defun my-set-frame-width ()
(interactive)
(set-frame-width (selected-frame) 80))
You can call this using M-x my-set-frame-width RET.

Related

emacs run shell command against current buffer's file name [duplicate]

I can run a shell command quickly by hitting M-!. One thing I'd like to do is perform shell quick operations on the current file. An example would be checking the file out through perforce:
M-! p4 edit buffer-file-name RET
(Yes there are perforce integrations, but I'm more interested in the minishell/variable problem rather than a specific workflow)
Of course, the buffer-file-name variable is not evaluated before the command is sent to the shell.
Is there an easy on-the-fly way to do this? Or will I have to roll a custom elisp function?
It seems current Emacs has something built-in to achieve the desired result, after M-! (shell-command) press <down>, you will get the file name you are currently visiting on the prompt. Now you can edit it to add the command you want to run on it.
In dired-mode it will give you the file your cursor is currently on.
Indeed using C-u M-: is almost right. I'm not so sure about using shell-quote-argument in eval-to-shell-argument since it only works on strings making it impossible to use eval-to-shell-argument to insert a number or a symbol. You could try something like:
(defun sm-minibuffer-insert-val (exp)
(interactive
(list (let ((enable-recursive-minibuffers t))
(read-from-minibuffer "Insert: "
nil read-expression-map t
'read-expression-history))))
(let ((val (with-selected-window (minibuffer-selected-window)
(eval exp)))
(standard-output (current-buffer)))
(prin1 val)))
and then bind this function in your minibuffer with (define-key minibuffer-local-map [?\M-:] 'sm-minibuffer-insert-val).
Of course, if the only thing you ever want to insert is the buffer-file-name, then your execute-shell-command-on-buffer is simpler.
I did roll my own elisp function, and it looks like this:
(defun execute-shell-command-on-buffer (shell-command-text)
(interactive "MShell command:")
(shell-command (format shell-command-text (shell-quote-argument buffer-file-name)))
)
https://gist.github.com/2367513
I bound it to M-", so now my example can be completed with:
M-"p4 edit %sRET
I won't accept this as the answer, because I did ask for solutions that don't require a function.
You can use C-u M-: (eval-expression with a universal prefix argument) to evaluate any Lisp expression and insert its value at point in the current buffer (including minibuffers, as long as you have enable-recursive-minibuffers set to a non-nil value).
In your example: C-u M-: buffer-file-name RET.
Note that the result of the expression is printed in Lisp form: that is, quoted in such a way that a subsequent call to read would construct an equal Lisp value. For strings, this means enclosing in double quotes, which will probably be interpreted as you expect by the inferior shell. However, you may run into problems with strings that contain special characters, which need different escaping by Elisp and the shell.
The more correct way uses shell-quote-argument, as in phils' solution. Here's a quick defun that reads a Lisp expression and inserts its value at point as a properly quoted shell word:
(defun eval-to-shell-argument (form)
(interactive "XEval: ")
(insert (shell-quote-argument form)))
The read-and-evaluate step happens automatically by using an "X" as the argument to interactive.
Edited to add: As #tenpn notes, the above solution doesn't work for inserting buffer-local variables like buffer-file-name in a minibuffer like the one M-! pops up (more precisely, it inserts the buffer-local value of the minibuffer, which is unlikely to be useful). Here is a revised version which seems to work. If the minibuffer is active, it makes the buffer of the previously-selected window temporarily active while reading and evaluating an expression.
Final edit: From #Stefan's answer I see that I should have used (minibuffer-selected-window) to find the previously-selected window. I've also added a (format "%s" ..) to allow inserting non-string values, while still quoting special characters in strings. Here's the final version:
(defun eval-to-shell-argument ()
(interactive)
(let* ((buffer
(if (minibufferp)
(window-buffer (minibuffer-selected-window))
(current-buffer)))
(result
(with-current-buffer buffer
(eval-minibuffer "Eval: "))))
(insert (shell-quote-argument (format "%s" result)))))
You can't do that with M-!, but you can evaluate arbitrary elisp from the minibuffer, so writing a function isn't strictly necessary:
M-: (shell-command (format "p4 edit %s" (shell-quote-argument buffer-file-name))) RET
In this case however, I think eshell is what you want to use:
M-x eshell-command RET p4 edit (eval buffer-file-name) RET
Edit: Except unfortunately that doesn't work, as the *eshell cmd* buffer is selected when that is evaluated. One solution would be:
M-x eshell-command RET p4 edit (eval buffer-file-name (other-buffer nil t)) RET
(Not quite as elegant, sorry.)
Everyone seems to be rolling their own version, so here's mine -- it will substitue the current filename or marked dired-files or current dired file wherever a % is in the shell command. It follows the same conventions as M-! so I bind it to that.
(defun my-shell-command (command &optional output-buffer error-buffer)
"Run a shell command with the current file (or marked dired files).
In the shell command, the file(s) will be substituted wherever a '%' is."
(interactive (list (read-from-minibuffer "Shell command: "
nil nil nil 'shell-command-history)
current-prefix-arg
shell-command-default-error-buffer))
(cond ((buffer-file-name)
(setq command (replace-regexp-in-string "%" (buffer-file-name) command nil t)))
((and (equal major-mode 'dired-mode) (save-excursion (dired-move-to-filename)))
(setq command (replace-regexp-in-string "%" (mapconcat 'identity (dired-get-marked-files) " ") command nil t))))
(shell-command command output-buffer error-buffer))

How to set back to the original value interactively if a variable's value is changed?

Sometimes the defvar/defcustom variable is changed by another expression in other elisp scripts with setq and the like, or they are altered by the directory/file local settings. Indeed I can use describe-variable to see its original value and then set it manually; however it is still a bit verbose.
In Vim, there is always a way to revert back to the default value of some variable by using !. And I believe that Emacs also has a way to achieve that goal.
So is there any simpler and interactive way to do so? Thanks.
Update: using set-default won't work. For instance, the original value of goto-address-mail-face is italic in goto-addr.el, and suppose I (setq goto-address-mail-face 'link) in ~/emacs.d/init.el. However when I (setq goto-address-mail-face (default-value 'goto-address-mail-face)) in the minibuffer, the result is still link.
For defcustom variables you can use the M-x customize-variable interface.
For defvar, I don't think the INITVALUE argument is remembered (and I don't think it is even evaluated in instances where the variable is already bound).
Variables can have "default" values, but this refers to the global value (as opposed to buffer-local bindings), and can of course be modified.
You can interactively set a buffer-local variable to its default value with M-: (setq SYMBOL (default-value 'SYMBOL))
See C-hig (elisp) Default Value RET

Function to evaluate haskell in ghci while editing source file using Emacs

I'm editing a haskell source file. I want to run my main function in my inferior-haskell buffer (already opened in a different frame) and continue editing my source file. To do this, I do
C-c C-l, change frame, main<ret>, change back to original frame
This seems quite inefficient. I'd like an emacs function/key that does it one shot.
There is actually a function to do this already defined in inf-haskell.el: inferior-haskell-load-and-run. This loads your current file and runs :main.
You can bind it to a key in Haskell mode by adding a hook:
(defun my-haskell-mode-hook ()
(local-set-key (kbd "C-x C-r") 'inferior-haskell-load-and-run))
(add-hook 'haskell-mode-hook 'my-haskell-mode-hook)
However, playing around with this for a bit, it seems to have an odd issue on my computer: sometimes, when it pops to the *haskell* buffer, it doesn't move the point to the end. I find this rather annoying. You can easily fix it by moving the point to the end yourself:
(defun my-haskell-load-and-run ()
"Loads and runs the current Haskell file."
(interactive)
(inferior-haskell-load-and-run inferior-haskell-run-command)
(sleep-for 0 100)
(end-of-buffer))
I believe the sleep-for is necessary because the Haskell command is run asynchronously and takes a little bit of time to return. This whole thing is something of a hack, but it seems to work.
Also, you might want to customize exactly what the inferior-haskell-run-command is. By default, it's :main. However, for me, I think just main would be better because main is affected by :set args ... where :main isn't.
If you want to stay in your current Haskell buffer, you can just do this:
(defun my-haskell-load-and-run ()
"Loads and runs the current Haskell file."
(interactive)
(let ((start-buffer (current-buffer)))
(inferior-haskell-load-and-run inferior-haskell-run-command)
(sleep-for 0 100)
(end-of-buffer)
(pop-to-buffer start-buffer)))
To use interactive-haskell-mode, I found a similar setting than the other answer:
(defun my-haskell-load-and-run ()
"Loads and runs the current Haskell file main function."
(interactive)
(haskell-process-load-file)
(haskell-interactive-mode-run-expr "main"))
(defun my-haskell-mode-hook ()
(local-set-key (kbd "C-x C-r") 'my-haskell-load-and-run))
(add-hook 'haskell-mode-hook 'my-haskell-mode-hook)
But I have a small issue with it, it always jumps to the end of the source buffer... which can be annoying.

Change Emacs window appearance when it loses focus

When I program I use two screens with Emacs on both with two buffers split in each window totaling 4 open source files on screen at any one time.
I switch between buffers with C-x b and between Windows with Alt-TAB. I change the appearance of buffers when I switch between them by defining different faces for mode-line and mode-line-inactive. But how do I inactivate a buffer when I switch from the Emacs window completely to another Emacs window via Alt-TAB?
It's probably also relevant that I'm using Emacs 23.2.1 on Ubuntu 11.04 with Gnome 2.32.1.
PS: The question How to automatically save files on lose focus in Emacs is after a different goal but with the same original event of "window losing focus".
It may depend on your window manager and how it manages multiple windows, or frames, in emacs parlance. The code below works like a champ in fvwm but not always in gnome.
I map a keystroke, C-o, to go between frames, this helps when you want to go to the other frame but an alt-tab would take you through a number of superfluous apps on the way.
If you're running a single instance of emacs with two frames you could use something like the following:
(defun pgr-previous-frame ()
"go to the previous frame"
(interactive)
(pgr-switch-frame (previous-frame)))
(defun pgr-next-frame ()
"go to the next frame"
(interactive)
(pgr-switch-frame (next-frame)))
(defun pgr-switch-frame (frame)
"go to the specified frame and raise it"
;; reset the frame properties here
(select-frame frame)
(raise-frame frame)
;;change the display in some manner here
)
You could also try adding some advice to raise-frame and lower-frame haven't tried it but it's worth a try.
I really liked #logoscia answer, which allowed me to do this more generic version. It uses the mode-line-inactive face when no focus.
(add-hook 'focus-out-hook
(lambda ()
(copy-face 'mode-line '--mode-line-backup)
(copy-face 'mode-line-inactive 'mode-line)))
(add-hook 'focus-in-hook
(lambda ()
(copy-face '--mode-line-backup 'mode-line)))
In Emacs 24.4 and later, you can use focus-in-hook and focus-out-hook. This piece of code seems to work, such that the active window of an inactive frame has the same colour as an inactive window:
(defvar my-mode-line-active-background "gray75")
(defvar my-mode-line-inactive-background "gray40")
(defun my-unhighlight-mode-line ()
(set-face-attribute 'mode-line nil
:background my-mode-line-inactive-background))
(add-hook 'focus-out-hook 'my-unhighlight-mode-line)
(defun my-highlight-mode-line ()
(set-face-attribute 'mode-line nil
:background my-mode-line-active-background))
(add-hook 'focus-in-hook 'my-highlight-mode-line)
I don't know if it can be done only with Emacs, but a possible alternative is running wmctrl in a shell script which perodically checks which window has the focus and if there is a change then it lets Emacs know via emacsclient which can send lisp code to a running Emacs for evaluation:
-e'--eval'
Tell Emacs to evaluate some Emacs Lisp code, instead of visiting
some files. When this option is given, the arguments to
`emacsclient' are interpreted as a list of expressions to
evaluate, not as a list of files to visit.

How can I operate on more Emacs buffers at the same time?

I am looking for an equivalent of the :bufdo Vim command in Emacs. :bufdo takes an argument - another command - and executes the command on all open buffers. I have not yet found a similar feature in Emacs.
Depending on what your command is, you can do:
M-: (mapc (lambda (b) (set-buffer b) (*command*)) (buffer-list))
But, I have a feeling you want something not so lispy. Take a look at keyboard macros. Namely, decide what you want to do:
C-x ( <do-your-command> C-x )
M-: (mapc (lambda (b) (set-buffer b) (kmacro-end-and-call-macro)) (buffer-list))
You'd probably want to define that last part as a function if you use it much:
(defun bufdo ()
"execute last macro on all buffers, ala bufdo from vi"
(interactive)
(mapc (lambda (b)
(with-current-buffer b
(kmacro-end-and-call-macro)))
(buffer-list)))
Note: code is untested
You can also checkout ibuffer, it allows you to mark buffers you like to operate on with m and then you can execute something on it with E. Other common operations are also available, e.g. query-replace on Q. Just check out the menu or the mode description (C-h m).
BTW, similar things are also possible from dired, although it doesn't seem to give you an eval command.
Take a look at buffer-list (function). It returns a list of all the open buffers (BUFFER objects). See the manual for a simple example of using it with mapcar (which operates on every element of the list, and accumulates the results). You would probably also find set-buffer, which programatically sets the current buffer from Emacs Lisp, useful.

Resources