How to remap a function to another in Emacs?

532 Views Asked by At

In coffee-mode RET is bound to coffee-newline-and-indent which works fine.

I also use evil-mode to have Vim emulation. evil-mode uses the standard newline-and-indent so the indentation is not correct for some vim commands such as o or O.

What would be the best way to rebind newline-and-indent to coffee-newline-and-indent ?

I'm still a newbie in ELisp and tried the line below but it doesn't work.

(add-hook 'coffee-mode-hook
          (lambda () 
            (setq newline-and-indent '(funcall coffee-newline-and-indent))))
5

There are 5 best solutions below

0
On

Try the following:

(define-key evil-mode-map (kbd "RET") nil)

I know it looks overly simple, but if evil-mode works the way I think it does then it should work.

  1. This will wipe the ret key from your evil-mode-map, which will let the binding of coffee-mode-map shine through.
  2. In non-coffee buffers, the ret key will still work, because it's still bind in the global map.
1
On

The standard way to accomplish what you seem to be asking for is

(autoload 'coffee-newline-and-indent "coffee-mode") ; (or whatever)
(define-key evil-mode-map (kbd "RET") 'coffee-newline-and-indent)

EDIT: to enable coffee-newline-and-indent only in coffee-mode:

(define-key evil-mode-map (kbd "RET")
  (lambda ()
    (interactive)
    (if (eq major-mode 'coffee-mode)
        (coffee-newline-and-indent)
      (newline-and-indent))))
0
On

I found the solution.

Evil-mode actually uses coffee-indent-line. The problem comes from coffee-indent-line which doesn't indent correctly. Evil-mode works correctly after patching it to behave like coffee-newline-and-indent:

(defadvice coffee-indent-line (after wants-indent activate)
  (let ((tabs-needed (- (/ (coffee-previous-indent) coffee-tab-width) 1)))
    (when (> tabs-needed 0)
      (insert-tab tabs-needed)))
  (when(coffee-line-wants-indent)
    (insert-tab)))
6
On

Here's my attempt. It should work, but I don't really like it.

(add-hook
 'coffee-mode-hook 
 (lambda ()
   (defalias 
       'newline-and-indent 
       (lambda()
         (interactive)
         (if (eq major-mode 'coffee-mode)
             (coffee-newline-and-indent)
           (delete-horizontal-space t)
           (newline)
           (indent-according-to-mode))))))

I wish I could use something more elegant that just copying the source of newline-and-indent, but make-variable-buffer-local doesn't work for this case, and I couldn't get a deep copy for symbol-function either. I'd be happy to see a better method.

0
On

if you want to remap a func, but only if some major mode is active - create a func which defines an alias and run the func (A) - another func (B) calls (A) - finally, a major mode can advice the func A to set the correct func. It has to test major mode.

let's say A is define-my-indent-f then it says (defalias my-indent 'newline-and-indent) the func b runs A then run command my-indent. finally coffe mode does defadice A to say (if eq major mode coffee defalais my-indent 'coffe-newline-and-indent)

of course this is super heavy to define, but then - each major mode can add its piece - only loaded major mode will advice