5

I've looked through a number of other questions and el files looking for something i could modify to suit my needs but I'm having trouble so I came to the experts.

Is there anyway to have a key behave differently depending on where in the line the cursor is?

To be more specific I'd like to map the tab key to go to the end of the line if I'm in the middle of the line but work as a tab normally would if my cursor is positioned at the beginning of the line.

So far I have braces and quotes auto-pairing and re-positioning the cursor within them for C++/Java etc. I'd like to use the tab key to end-of-line if for example a function doesn't have any arguments.

kladd
  • 159
  • 1
  • 9

2 Answers2

3

Behaving differently depending on where point is in the line is the easy bit (see (if (looking-back "^") ...) in the code). "[Working] as a tab normally would" is the harder bit, as that's contextual.

Here's one approach, but I was thinking afterwards that a more robust method would be to define a minor mode with its own binding for TAB and let that function look up the fallback binding dynamically. I wasn't sure how to do that last bit, but there's a solution right here:

Emacs key binding fallback

(defvar my-major-mode-tab-function-alist nil)

(defmacro make-my-tab-function ()
  "Return a major mode-specific function suitable for binding to TAB.
Performs the original TAB behaviour when point is at the beginning of
a line, and moves point to the end of the line otherwise."
  ;; If we have already defined a custom function for this mode,
  ;; return that (otherwise that would be our fall-back function).
  (or (cdr (assq major-mode my-major-mode-tab-function-alist))
      ;; Otherwise find the current binding for this mode, and
      ;; specify it as the fall-back for our custom function.
      (let ((original-tab-function (key-binding (kbd "TAB") t)))
        `(let ((new-tab-function
                (lambda ()
                  (interactive)
                  (if (looking-back "^") ;; point is at bol
                      (,original-tab-function)
                    (move-end-of-line nil)))))
           (add-to-list 'my-major-mode-tab-function-alist
                        (cons ',major-mode new-tab-function))
           new-tab-function))))

(add-hook
 'java-mode-hook
 (lambda () (local-set-key (kbd "TAB") (make-my-tab-function)))
 t) ;; Append, so that we run after the other hooks.
Community
  • 1
  • 1
phils
  • 71,335
  • 11
  • 153
  • 198
  • Thanks a lot for the help I really appreciate the thorough answer. I'll test out both approaches. – kladd Sep 10 '11 at 21:50
  • I recommend also having a look at http://www.masteringemacs.org/articles/2011/02/08/mastering-key-bindings-emacs/ as well, which will de-mystify the many layers and precedence rules that apply to key-bindings in Emacs. – phils Sep 11 '11 at 00:06
  • That's very nice! One small edit: if you put the comments on the 2nd and third lines of your macro in quotes `"` instead of behind semicolons `;`, your comment becomes a doc string. You can then see your description when you ask for help - `C-h f make-my-tab-function` – Tyler Sep 13 '11 at 12:24
  • For sure. Those comments weren't intended as a docstring mind, but you're right, it ought to have had one. Fixed (along with my curious typo of `add-to-list` instead of `add-hook`). – phils Sep 13 '11 at 13:40
1

This page of Emacs Wiki lists several packages (smarttab, etc.) which make TAB do different things depending on the context. You can probably modify one of them to do what you want.

Tom
  • 7,515
  • 7
  • 38
  • 54