I don't like typing underscores in code in languages that use underscores heavily like php and python. I was trying to come up with a way to swap the underscore and dash keys in emacs when editing code . Couldn't figure out a solution I was happy with but recently I just came across this bit of lisp code that seems pretty cool. It intelligently decides whether to type a dash or underscore depending on the context.

The newest version is available at http://malsyned.net/smart-dash.html

Old version:
From http://paste.lisp.org/display/73509

smart-dash.el:

;; Smart-Dash minor mode
;; (C) 2008 Dennis Lambe Jr.

;; This is a simple minor mode which causes the dash key to insert an
;; underscore within C identifiers and a dash otherwise.  This allows
;; you to type all_lowercase_c_identifiers as comfortably as you would
;; lisp-style-identifiers.
;;
;; While Smart-Dash mode is active, you can type "C-q -" or use the
;; dash on the numeric keypad to override it and insert a dash after a
;; C identifier character.  You might need to do this if you want to
;; type a cramped-looking expression like x-5.
;;
;; If Smart-Dash mode is activated while in a C-like mode (c-mode,
;; c++-mode, and objc-mode by default, customizable with
;; SMART-DASH-C-MODES) it will also activate Smart-Dash-C mode, which
;; allows you to type "_>" and it will be translated to "->"
;; automatically so that struct pointer member access isn't made more
;; difficult by Smart-Dash mode's tendency to insert underscores at
;; the tail ends of identifiers whether you want it to or not.

(defcustom smart-dash-c-modes '(c-mode c++-mode objc-mode)
  ; Remove definition with (makunbound 'smart-dash-c-modes)
  "List of major modes in which _> should be replaced by the ->
struct pointer member access operator")

(defun smart-dash-in-regular-code-p ()
  (let* ((syntax-ppss (syntax-ppss))
         (in-string (nth 3 syntax-ppss))
         (in-comment (nth 4 syntax-ppss)))
    (and (not in-string)
         (not in-comment))))

(defun smart-dash-insert ()
  "Insert an underscore following [A-Za-z0-9_], a dash otherwise."
  (interactive)
  (let* ((prev-char (char-before)))
    (if (and (smart-dash-in-regular-code-p)
             prev-char
             (string-match "[A-Za-z0-9_]" (string prev-char)))
        (insert ?_)
      (insert ?-))))

(defun smart-dash-insert-dash ()
  "Insert a dash regardless of the preceeding character."
  (interactive)
  (insert ?-))

(defun smart-dash-insert-gt ()
  "Insert a greater-than symbol.  If the preceeding character is
an underscore, replace it with a dash.

This behavior is desirable in order to make struct pointer member
access comfortable."
  (interactive)
  (let ((prev-char (char-before)))
    (if (and (smart-dash-in-regular-code-p)
             prev-char
             (= prev-char ?_))
        (progn
          (delete-backward-char 1)
          (insert "->"))
      (insert ?>))))

;; I tried also mapping "_" to the inverse operation, but it made it
;; much more awkward to type double-underscored identifiers like
;; __attribute__.  The default Emacs C-q escape works almost as well
;; and doesn't have nasty interactions with common cases.
;; <kp-subtract> on the numeric keypad can also be used to always
;; insert a dash.
(easy-mmode-defmap smart-dash-mode-keymap
   ; Remove definition with (makunbound 'smart-dash-mode-keymap)
   `(("-" . smart-dash-insert)
     ,(cons (kbd "<kp-subtract>")  'smart-dash-insert-dash))
   "Key map for `smart-dash-mode'")

(define-minor-mode smart-dash-mode
  "Set the dash key to call insert-dash-or-underscore."
  nil "" smart-dash-mode-keymap
  (if (memq major-mode smart-dash-c-modes)
      (if smart-dash-mode
          (smart-dash-c-mode 1)
        (smart-dash-c-mode 0))))

(easy-mmode-defmap smart-dash-c-mode-keymap
   ; Remove definition with (makunbound 'smart-dash-c-mode-keymap)
   '((">" . smart-dash-insert-gt))
   "Key map for smart-dash-mode when in a C-like major mode")

(define-minor-mode smart-dash-c-mode
  "Set the > key to call smart-dash-insert-gt."
  nil "" smart-dash-c-mode-keymap)

Comments

malsyned’s picture

I'm the author of this code. I've made many improvements to this module since I posted it on #emacs for comments and suggestions a year ago.

The project is now hosted on bitbucket and has a homepage here: http://malsyned.net/smart-dash.html

I would appreciate it if you would replace this old code listing with a link to the project's new homepage. Especially since you're the top google result for "smart dash mode" right now.

Thanks!

axel’s picture

Thank for this tool! I included it into a new Drupal + Emacs integration project.