Mode-local variables in Emacs - emacs

I would like to have a global keyboard shortcut that shows the value of a variable. However, the variable's value could change according to the current major mode in the current buffer.
I tried to add the following to my ~/.emacs:
(defun my-elisp-mode-setup ()
(defvar-local *current-mode-var* "elisp-mode")
)
(defun my-sh-mode-setup ()
(defvar-local *current-mode-var* "sh-mode")
)
(add-hook 'emacs-lisp-mode-hook 'my-elisp-mode-setup)
(add-hook 'sh-mode-hook 'my-sh-mode-setup)
If I now start Emacs with emacs test.sh and then type M-x describe-variable *current-mode-var* in the test.sh buffer, I get
*current-mode-var*'s value is "elisp-mode"
Automatically becomes buffer-local when set.
Documentation:
Not documented as a variable.
while I expected to get *current-mode-var*'s value is "sh-mode"

The variables are evaled only at first declaration. All further declarations are skipped.
You need a setq instead.

If all you want to do is examine a variable to determine the major mode (which it seems is what you are doing), then just examine variable major-mode. That's what it's for.
And if you want a key/command to do that, then just create one:
(defun which-mode ()
"Echo the current major mode in the echo area."
(interactive)
(message "Major mode: %s" major-mode))
Or use variable mode-name if you prefer a human-friendly major-mode name.

I prefer official native package https://www.emacswiki.org/emacs/ModeLocal .
It is better configurable, because you do not require add-hook
For example
(require 'mode-local)
(setq-mode-local sh-mode *current-mode-var* "sh-mode")
(setq-mode-local emacs-lisp-mode *current-mode-var* "elisp-mode")
Then by just changing mode cause changing the value of *current-mode-var*

defvar-local is a macro calling defvar and make-variable-buffer-local under the hood.
defvar SYMBOL [VALUE [DOC-STRING]
... But if SYMBOL is not void, VALUE is not evaluated, and SYMBOL’s value is left unchanged...
You code should be:
(defvar-local *current-mode-var*)
(defun my-elisp-mode-setup ()
(setq *current-mode-var* "elisp-mode"))
(add-hook 'emacs-lisp-mode-hook 'my-elisp-mode-setup)
(defun my-sh-mode-setup ()
(setq *current-mode-var* "sh-mode"))
(add-hook 'sh-mode-hook 'my-sh-mode-setup)

Related

Symbol's function definition is void: gst Emacs 24.5 smalltalk-mode [duplicate]

i want to use a new comint mode for plink(putty), i put the code in init.el, but if M-x run-plink, i got below error:
let*: Symbol's function definition is void: comint-check-proc
;; path
(defvar plink-file-path "C:/Programme/Putty/plink.exe"
"Path to the program used by `run-plink'")
;; arguments
(defvar plink-arguments '()
"Commandline arguments to pass to `plink'")
;; prompt
(defvar plink-prompt-regexp "^>\s"
"Prompt for `run-plink'.")
;; Run-plink
(defun run-plink ()
"Run an inferior instance of `plink.js' inside Emacs."
(interactive)
(setq plink-buffer "*Plink*")
(let* ((plink-program plink-file-path) (buffer (comint-check-proc "Plink")))
;; pop to the "*plink*" buffer if the process is dead, the
;; buffer is missing or it's got the wrong mode.
(pop-to-buffer-same-window
(if (or buffer (not (derived-mode-p 'plink-mode))
(comint-check-proc (current-buffer)))
(get-buffer-create (or buffer "*Plink*"))
(current-buffer)))
;; create the comint process if there is no buffer.
(unless buffer
(apply 'make-comint-in-buffer "Plink" buffer plink-program plink-arguments)
(plink-mode))))
;; plink-mode
(define-derived-mode plink-mode comint-mode "plink" nil "plink"
(setq comint-process-echoes t)
(setq comint-use-prompt-regexp t)
(setq comint-prompt-regexp plink-prompt-regexp)
; ">" read-only
(setq comint-prompt-read-only t)
(set (make-local-variable 'paragraph-separate) "..'")
(set (make-local-variable 'paragraph-start) plink-prompt-regexp))
You have not loaded library comint. You need to do that before Emacs can know about comint-check-proc.
Add a (require 'comint), either in your init file or near the beginning of run-plink - somewhere before it tries to use comint-check-proc.
To give this question an answer, which is also meaningful for other questions marked as duplicates of this one, but actually are about other packages not being loaded, I will give a more general answer, which should be applicable to the other questions as well.
Generally an error Symbol's function definition is void often indicates, that a package was not loaded, but then someone/something tried to use it.
So the general answer, that you probably need to (require '<package name>) in your init.el, where the package name is the name of the package which provides what is currently void.

new comint mod in emacs for plink (putty): Symbol's function definition is void

i want to use a new comint mode for plink(putty), i put the code in init.el, but if M-x run-plink, i got below error:
let*: Symbol's function definition is void: comint-check-proc
;; path
(defvar plink-file-path "C:/Programme/Putty/plink.exe"
"Path to the program used by `run-plink'")
;; arguments
(defvar plink-arguments '()
"Commandline arguments to pass to `plink'")
;; prompt
(defvar plink-prompt-regexp "^>\s"
"Prompt for `run-plink'.")
;; Run-plink
(defun run-plink ()
"Run an inferior instance of `plink.js' inside Emacs."
(interactive)
(setq plink-buffer "*Plink*")
(let* ((plink-program plink-file-path) (buffer (comint-check-proc "Plink")))
;; pop to the "*plink*" buffer if the process is dead, the
;; buffer is missing or it's got the wrong mode.
(pop-to-buffer-same-window
(if (or buffer (not (derived-mode-p 'plink-mode))
(comint-check-proc (current-buffer)))
(get-buffer-create (or buffer "*Plink*"))
(current-buffer)))
;; create the comint process if there is no buffer.
(unless buffer
(apply 'make-comint-in-buffer "Plink" buffer plink-program plink-arguments)
(plink-mode))))
;; plink-mode
(define-derived-mode plink-mode comint-mode "plink" nil "plink"
(setq comint-process-echoes t)
(setq comint-use-prompt-regexp t)
(setq comint-prompt-regexp plink-prompt-regexp)
; ">" read-only
(setq comint-prompt-read-only t)
(set (make-local-variable 'paragraph-separate) "..'")
(set (make-local-variable 'paragraph-start) plink-prompt-regexp))
You have not loaded library comint. You need to do that before Emacs can know about comint-check-proc.
Add a (require 'comint), either in your init file or near the beginning of run-plink - somewhere before it tries to use comint-check-proc.
To give this question an answer, which is also meaningful for other questions marked as duplicates of this one, but actually are about other packages not being loaded, I will give a more general answer, which should be applicable to the other questions as well.
Generally an error Symbol's function definition is void often indicates, that a package was not loaded, but then someone/something tried to use it.
So the general answer, that you probably need to (require '<package name>) in your init.el, where the package name is the name of the package which provides what is currently void.

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 / Elisp / Closure / Toggle

I currently have the following:
(defun my-hide-code ()
(interactive)
(set-selective-display 2))
(defvar my-keys-minor-mode-map (make-keymap) "my-keys-minor-mode keymap.")
(define-key my-keys-minor-mode-map (kbd "<f2>") 'my-hide-code)
(define-minor-mode my-keys-minor-mode
"use"
t " my-keys" 'my-keys-minor-mode-map)
(my-keys-minor-mode 1)
Now, I want to toggle between
(set-selective-display 2)
and
(set-selective-display 'nil)
Now, if I was in scheme, I would just create a s closure, and the closure would store a state variable, which would allow me to know which state I was in, and how to toggle.
However, Elisp is apparently a lisp-2 where variables and functions have different scope. Given this, how do I create closures / have be a toggle key?
Emacs 24 supports lexical binding, so real closures can be written.
See:
What are the new rules for variable scoping in Emacs 24?
Just be aware that dynamic binding is a very large part of what makes Emacs so customizable, so use lexical binding with due care if you are writing something which may be of use to others -- ensure that you defvar any variable which might potentially be useful for someone to override (ensuring, of course, that you think up all those potential use-cases that don't apply to you! :)
For Emacs < 24, see:
http://www.emacswiki.org/emacs/FakeClosures
Other Stack Overflow Q&As
selective-display itself is the variable that contains the state you need to check, so you can write
(defun my-toggle-selective-display ()
(interactive)
(if selective-display
(set-selective-display nil)
(set-selective-display 2)))
As for closures in general, I had need of them for a project long ago and resorted to inserting uninterned symbols into a function definition using backquote substitution to avoid global variables. E.g.
(fset 'toggler
(let ((toggle-var (make-symbol "toggle")))
(set toggle-var nil)
`(lambda () (interactive)
(cond (,toggle-var
(setq ,toggle-var nil))
(t
(setq ,toggle-var t)))
(message "toggle is %s" ,toggle-var))))
which when run produces
M-x toggler
toggle is t
M-x toggler
toggle is nil
M-x toggler
toggle is t
M-: (boundp 'toggle)
nil
I guess this qualifies as a kludge, but I know of no other way to get anything like a closure in Emacs-Lisp.
Here is a link to an answer I gave elsewhere about how to create real (not fake)
closures in Elisp:
https://stackoverflow.com/a/14088107/1857114
I use a macro I call defun****. It works in Emacs 24.2.1 but I'm not sure what
earlier versions it works for. Presumably the **defun special form will be
upgraded some time in the future and the macro will be unnecessary.

Enable auto-complete in Emacs minibuffer

I'm trying to turn auto-complete in the minibuffer:
(add-hook 'minibuffer-setup-hook 'auto-complete-mode)
What I get is auto-complete working in the first instance of minibuffer, but no longer. That is the full minibuffer-setup-hook after loading:
(auto-complete-mode turn-on-visual-line-mode ido-minibuffer-setup rfn-eshadow-setup-minibuffer minibuffer-history-isearch-setup minibuffer-history-initialize)
How to turn auto-complete on persistently?
You rarely ever want to add a function symbol to a hook variable if that function acts as a toggle (which will be the case for most minor modes).
minibuffer-setup-hook runs "just after entry to minibuffer", which means that you would be enabling auto complete mode the first time you enter the minibuffer; disabling it the second time; enabling it the third time; etc...
Typically you would either look to see if there's a pre-defined turn-on-autocomplete-mode type of function, or define your own:
(defun my-turn-on-auto-complete-mode ()
(auto-complete-mode 1)) ;; an argument of 1 will enable most modes
(add-hook 'minibuffer-setup-hook 'my-turn-on-auto-complete-mode)
I can't test that, because you haven't linked to the autocomplete-mode you are using.
The creator of "auto-complete-mode" explicitly excludes the minibuffer for use with auto completion. The definition for the minor mode is:
(define-global-minor-mode global-auto-complete-mode
auto-complete-mode auto-complete-mode-maybe
:group 'auto-complete)
so the "turn mode on" function is "auto-complete-mode-maybe" - the definition of that function is:
(defun auto-complete-mode-maybe ()
"What buffer `auto-complete-mode' prefers."
(if (and (not (minibufferp (current-buffer)))
(memq major-mode ac-modes))
(auto-complete-mode 1)))
This function explicitly tests in the if statement if the current-buffer is the minibuffer and doesn't turn on the auto-complete-mode if it is.
If you want to use auto-complete-mode in the minibuffer, you should probably contact the maintainer of the mode and ask him why he excluded the minibuffer and what programming changes he feels are necessary to enable the mode in the minibuffer.
Zev called to my attention auto-complete-mode-maybe, and that is the required modifications (file auto-complete.el, all changes have comments):
;; Add this variable
(defcustom ac-in-minibuffer t
"Non-nil means expand in minibuffer."
:type 'boolean
:group 'auto-complete)
...
(defun ac-handle-post-command ()
(condition-case var
(when (and ac-triggered
(not (ido-active)) ;; Disable auto pop-up in ido mode
(or ac-auto-start
ac-completing)
(not isearch-mode))
(setq ac-last-point (point))
(ac-start :requires (unless ac-completing ac-auto-start))
(ac-inline-update))
(error (ac-error var))))
...
(defun auto-complete-mode-maybe ()
"What buffer `auto-complete-mode' prefers."
(if (or (and (minibufferp (current-buffer)) ac-in-minibuffer) ;; Changed
(memq major-mode ac-modes))
(auto-complete-mode 1)))
And .emacs:
(add-hook 'minibuffer-setup-hook 'auto-complete-mode)
Certainly, there are binding conflicts but it is possible to solve them.