emacs org-mode file local key binding - emacs

I'm using org-mode in emacs together with ox-reveal. The latter defines the command org-reveal-export-to-html, which I would like to bind to a key for buffers with org files, which are presentations (so not for all org files).
So the question is: how can I define file local key bindings in org-mode?
What I currently have is this:
#+BEGIN_COMMENT
Local Variables:
eval: (local-set-key [f5] 'org-reveal-export-to-html)
End:
#+END_COMMENT
But imho this is not very elegant.

You can define a key only for org-mode by using org-defkey, basically add the following to your init file
(org-defkey org-mode-map [f5] 'org-reveal-export-to-html)
UPDATE
You can use file local variables.
(defvar export-with-reveal nil)
(defun export-with-reveal-or-html ()
(interactive)
(if (or export-with-reveal (file-exists-p "reveal.js"))
(call-interactively 'org-reveal-export-to-html)
(call-interactively 'org-export-as-html)))
(org-defkey org-mode-map [f5] 'export-with-reveal-or-html)
The function export-with-reveal-or-html if the variable export-with-reveal has value t or there is a file 'reveal.js' relative to org file , if so it exports with reveal or it falls back to default html export. You can specify a file to exported as reveal by adding the following to top of your org file
# -*- export-with-reveal: t -*-
UPDATE 2
You can also define arbitrary export function by doing using, file-local variables
(defvar my-export-fn nil)
(defun my-export ()
(interactive)
(if my-export-fn
(call-interactively my-export-fn)
(call-interactively 'org-export-as-html)))
(org-defkey org-mode-map [f5] 'my-export)
Then at top of the file you can set the export function you want to use eg
# -*- export-fn: org-reveal-export-to-html -*-

I came up with following solution, which exploits local variables hook hack and defines buffer lokal hook:
(add-hook 'org-mode-hook 'my-org-mode-hook)
(defun my-org-mode-hook ()
(add-hook 'hack-local-variables-hook
(lambda ()
(local-set-key [f5] (if (boundp 'my-org-export)
my-org-export
'org-html-export-to-html)))))
Then in org mode I add this:
#+BEGIN_COMMENT
Local Variables:
my-org-export: org-reveal-export-to-html
End:
#+END_COMMENT
Still I would love to see something like this, without any hook hacking:
#+EXPORT: org-reveal-export-to-html

Related

How to turn a (non-interactive) function into a command (interactive function) in Emacs-LISP?

I want to call the function markdown-back-to-heading, which is native in Markdown mode in Emacs. I understand that interactive turns non-interactive functions interactive, or formally functions into commands:
Special Form: interactive arg-descriptor
This special form declares that a function is a command, and that it may therefore be called interactively (via M-x or by entering a key sequence bound to it).
I tried:
(define-key markdown-mode-map (kbd "C-c C-h") 'markdown-back-to-heading)
This throws an error: Wrong type argument: commandp, markdown-back-to-heading.
So I wrapped it with an interactive function, and it works:
(defun my-markdown-back-to-heading ()
"Wrap function to be called interactively."
(interactive)
(markdown-back-to-heading))
(define-key markdown-mode-map (kbd "C-c C-h") 'my-markdown-back-to-heading)
Is there a better way to turn the native function into an interactive command?
You can alternatively use the interactive-form symbol property.
For details see C-hig (elisp)Using Interactive
Here's a simple example:
;; Enable M-x kill-process (to kill the current buffer's process).
;; (This is not normally a command, but it is useful as one.)
(put 'kill-process 'interactive-form '(interactive))
The more complex version that I actually use is:
(put 'kill-process 'interactive-form
'(interactive
(let ((proc (get-buffer-process (current-buffer))))
(if (process-live-p proc)
(unless (yes-or-no-p (format "Kill %S? " proc))
(error "Process not killed"))
(error (format "Buffer %s has no process" (buffer-name))))
(list proc))))
If want to make markdown-back-to-heading interactive, you have a few different good options:
file a bug report to get upstream to make it so. Including a patch along with the bug-report can help speed up the process.
use an advice such as:
(advice-add 'markdown-back-to-heading :before
(lambda () (interactive "^") nil))
If instead you want to improve the interactivity of a function, e.g. if you want to support shift-selection, you can add the interactive code ^ with (interactive "^") instead of (interactive) so that Emacs knows this is a navigation command (and hence if you use it with a shifted-binding it will select the corresponding text). Here is a manual page with the list of interactive codes, and other options for interactivity at the manual page you mentioned.
Following #Stefan's suggestion, I filed a Github issue and submitted a patch, which adds the line (interactive "P") in the source code:
(defun markdown-back-to-heading (&optional invisible-ok)
"Move to previous heading line, or beg of this line if it's a heading.
Only visible heading lines are considered, unless INVISIBLE-OK is non-nil."
(interactive "P")
(markdown-move-heading-common #'outline-back-to-heading invisible-ok))
and now I can keybind it with
(define-key markdown-mode-map (kbd "C-c C-h") 'markdown-back-to-heading)
I had installed markdown-mode from MELPA, so this change required uninstalling the package, then these steps from the repo README. I forked the repo and cloned the repo locally:
git clone git#github.com:miguelmorin/markdown-mode
and added these lines to Emacs initialization:
(add-to-list 'load-path (expand-file-name "~/code/markdown-mode"))
(autoload 'markdown-mode "markdown-mode"
"Major mode for editing Markdown files" t)
(add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
(autoload 'gfm-mode "markdown-mode"
"Major mode for editing GitHub Flavored Markdown files" t)
(add-to-list 'auto-mode-alist '("README\\.md\\'" . gfm-mode))
(require 'markdown-mode)

Set variable under specific mode emacs

Looking to set a variable under latex mode. The idea is that the value set under latex mode will override the value of the same variable set in the customise section. I am very new to emacs so these are my attempts:
(add-hook 'LaTeX-mode-hook '(setq line-move-visual t))
(add-hook 'latex-mode-hook (lambda () (setq line-move-visual t)))
Why do these not work? What should I do instead?
Clarification: looking to set the variable (setq line-move-visual t) as I have it as (setq line-move-visual nil) for all other files
If you just setq the variable in your LaTeX-mode-hook it will also have an effect on any other open buffer. It is possible to make the change only effect the current buffer:
(add-hook 'LaTeX-mode-hook
(lambda ()
(make-local-variable 'line-move-visual)
(setq line-move-visual nil)))
Also, please note that the hook for the default mode for LaTeX in Emacs is called latex-mode-hook but the hook when you are using the (far superior) AUCTeX is called LaTeX-mode-hook
EDIT: Changed make-variable-buffer-local to make-local-variable. See comments to this answer.

Emacs CEDET Hook

I want to hook CEDET modes to c++ mode. I am using the following script in my .emacs file:
(add-hook 'c++-mode-hook
(lambda ()
...
(my_cedet_load)
)
)
where
(defun my_cedet_load ()
(interactive)
(semantic-mode)
(global-semantic-stickyfunc-mode t)
(global-semantic-idle-scheduler-mode t)
(global-semantic-idle-completions-mode t)
(global-semantic-highlight-edits-mode t)
)
Now, the problem is that once I open a .cpp file, the semantic-mode is enabled in all buffers. How do I only enable such mode in only .cpp files?
Semantic is a global minor mode. From semantic.el
To enable Semantic, turn on `semantic-mode', a global minor mode (M-x
semantic-mode RET, or "Source Code Parsers" from the Tools menu). To
enable it at startup, put (semantic-mode 1) in your init file.
As such when you do semantic-mode it is enabled in all buffers. You can use semantic-inhibit-functions to restrict the buffers in which semantic is activated. From the documentation
List of functions to call with no arguments before Semantic is setup.
If any of these functions returns non-nil, the current buffer is not
setup to use Semantic.
Below is an example of using this variable. it would instruct semantic to be activated only in c-mode, cc-mode and java-mode buffers
(add-to-list 'semantic-inhibit-functions
(lambda () (not (member major-mode '(java-mode c-mode c++-mode)))))
I'm guessing the key lies in the global word.
So use semantic-stickyfunc-mode instead of global-semantic-stickyfunc-mode etc.
UPDATE:
Try this:
(add-hook 'c++-mode-hook 'my-c++-hook)
(defun my-c++-hook ()
(semantic-mode 1)
(semantic-stickyfunc-mode 1)
(semantic-idle-scheduler-mode 1)
(semantic-idle-completions-mode 1)
(semantic-highlight-edits-mode 1))

major-mode hook configuration affects other buffers

Let me start by saying I'm very new to emacs.
I'm attempting to create customizations for major-modes. While my settings are functioning correctly, I'm observing that when I open a new buffer, that buffers major-mode customization is being applied to other buffers of a different type.
For instance, if I open a file named 'Makefile', makefile-mode is used and my customizations are applied. If I then open another file such as 'test.c', c-mode is used but customizations from makefile-mode are merged with customizations from c-mode.
The relevant portions of my .emacs file can be seen below:
(defun c-mode-settings ()
(c-set-style "bsd")
(set-buffer-file-coding-system 'utf-8-unix)
(show-paren-mode 1)
(setq c-basic-offset 4)
(setq tab-width 4)
(setq indent-tabs-mode nil)
(setq c-tab-always-indent t)
(setq require-final-newline t)
)
(defun makefile-mode-settings ()
(setq whitespace-style '(tabs spaces space-mark tab-mark face lines-tail))
(whitespace-mode t)
(show-paren-mode 1)
(setq tab-width 4)
(setq require-final-newline t)
)
(add-hook 'c-mode-hook 'c-mode-settings)
(add-hook 'makefile-mode-hook 'makefile-mode-settings)
How can I keep these mode hooks from affecting other buffers in different modes?
Thanks!
Andrew
You need to take into account, that some variables are becoming local to buffer when set, while some are global. Usually they have corresponding comment in their description (use C-h v var-name to get this description.
In some cases, you can force that any variable become local to buffer, using the
(set (make-local-variable 'var-name) var-value)
but you need to be careful with this.

why mode isn't enabled?

I've got an emacs configuration file whatever.el :
(abbrev-mode +1)
(provide 'whatever)
and in my init.el :
(require 'whatever)
but when i start emacs, abbrev-mode isn't enabled. why ?
thank you
Quoting from http://emacswiki.org/emacs/AbbrevMode:
You can also put the following in your ~/.emacs file if you want it
always on:
(setq default-abbrev-mode t)
If you only want it on in text and derived modes, you could do
something like this:
(add-hook 'text-mode-hook (lambda () (abbrev-mode 1)))
For multiple modes, use something like the following:
(dolist (hook '(erc-mode-hook
emacs-lisp-mode-hook
text-mode-hook))
(add-hook hook (lambda () (abbrev-mode 1))))
Abbrev-mode is enabled per-buffer.
One way is to create a hook function that you could add to the major mode hooks you will want to use it in.
For example:
(defun my-enable-abbrev-mode ()
(abbrev-mode 1))
(add-hook 'c-mode-hook 'my-enable-abbrev-hook)
(add-hook 'java-mode-hook 'my-enable-abbrev-hook)
Another approach is to use change-major-mode-hook.
While others explained how to get what you presumably want, I'll just point out that w.r.t to your actual question ("Why?"), the reason is simple: abbrev-mode is a buffer-local minor-mode, so when you run (abbrev-mode +1) at startup it will just enable abbrev-mode in the buffer that happens to be current during evaluation of the ~/.emacs (typically scratch) but not in subsequent buffers.