(or emacs irrelevant)

C++ - a dot inserts last var plus dot

It is very much in the spirit of C++ to pull an object into existence with e.g. a constructor definition and then poke and prod it with various method calls. Most of the time, the dot will have the object name on the left. So why not automatically insert the object name each time I press the dot? Below, I'll show a code that does exactly that.

The dot command

(defun c++-smart-dot ()
  "Insert a dot or an object name plus dot when appropriate."
  (interactive)
  (let (var-name)
    (if (and (looking-back "^[ \t]*")
             (setq var-name (c++-get-recent-var)))
        (insert var-name ".")
      (insert "."))))

This one is pretty simple: if we are at the beginning of the line, optionally with some spaces or (ugh) tabs before the point, then try to insert the object name along with a dot.

Here's how to bind it:

(eval-after-load "cc-mode"
  `(define-key c++-mode-map "." 'c++-smart-dot))

How to get the recent variable

This code doesn't aim to be thorough, it's just a hack that works reasonably well.

(defconst c++-var-regex "[A-Za-z][A-Za-z0-9_]*"
  "The regex for C++ variable name.")

(defun c++-get-recent-var ()
  "Return the closest thing that looks like an object.
The search is performed backwards through code."
  (save-excursion
    (when (or
           ;; variable dot chain
           (looking-back
            (format " \\(%s\\)\\.%s.*\n[\t ]*"
                    c++-var-regex
                    c++-var-regex))
           ;; variable constructor init
           (looking-back
            (format "[\t ]+\\(%s\\)\\(?:([^)]*)\\)?;[\t\n ]*"
                    c++-var-regex))
           ;; variable dot, first on line
           (re-search-backward
            (format "^[ \t]*\\(%s\\)\\." c++-var-regex) nil t))
      (match-string-no-properties 1))))

If you're a stickler for performance and you don't want to call format a bunch of times, you can amend the code like this:

(defalias 'c++-get-recent-var
    (byte-compile
     `(lambda ()
        (save-excursion
          (when
              (or
               ;; variable dot chain
               (looking-back
                ,(format
                  " \\(%s\\)\\.%s.*\n[\t ]*"
                  c++-var-regex
                  c++-var-regex))
               ;; variable constructor init
               (looking-back
                ,(format
                  "[\t ]+\\(%s\\)\\(?:([^)]*)\\)?;[\t\n ]*"
                  c++-var-regex))
               ;; variable dot, first on line
               (re-search-backward
                ,(format "^[ \t]*\\(%s\\)\\." c++-var-regex) nil t))
            (match-string-no-properties 1)))))
  "Return the closest thing that looks like an object.
The search is performed backwards through code.")

The thing above looks slightly ugly. I'm open to suggestions to make it look nicer.

The sample application

For the happy people that have never seen C++:

DataOut<dim> data_out;
data_out.attach_dof_handler(dof_handler);
data_out.add_data_vector(solution, "u");
data_out.build_patches();

Here, after defining an object data_out, I insert it subsequently with just ..