5

I want to write an emacs function for debug purposes in c++ code. Basically I'm fed up typing the following:

std::cout << "variable is: " << variable << std::endl;

Instead I want to define an emacs function called say "td" for temp debug such that I do

M-x td RETURN
foo

And it will print

std::cout << "foo is: " << foo << std::endl;

I want it to behave like M-x goto-line whereby I type M-x goto-line and press enter then it prompts me for an input, in my case I want my input to be the variable name and something like td instead of goto-line.

Open to other suggestions, but I'd like to know how to code this type of function for future reference anyway.

6
  • 2
    Try looking at the source to goto-line to see if you can figure it out. Use C-h f goto-line RET and click on the link that says simple.el to see the source.
    – nanny
    Nov 7, 2014 at 16:43
  • 1
    Here are a couple of useful functions which you can combine to get the functionality you're after. See read-minibuffer and format in the manual. (And, for good measure here's the intro to elisp you can reference as well.)
    – Dan
    Nov 7, 2014 at 16:47
  • 2
    Have you looked into yasnippet
    – Ryan
    Nov 7, 2014 at 18:52
  • 1
    The "expand <something> into <something else>" concept is called abbrevs in Emacs, and might be worth looking in to. emacswiki.org/AbbrevMode Nov 8, 2014 at 7:56
  • 1
    I'd do that kind of thing with a C++ macro. That way you can easily tell the temporary debug code (DBG(foo)) from the normal output, and disable the debug code in production. Nov 12, 2014 at 4:57

2 Answers 2

9

The interactive special form provides the easiest way to get input from a user.

(defun td (variable)
  (interactive "sVariable:")
  (insert (format "std::cout << \"%s is: \" << %s << std::endl;" variable variable)))

Here "sVariable:" consists of the "s" code character (read a string) and the prompt. (See Using interactive in the Emacs Lisp Manual for more.)

In addition to using a string with with code characters, the interactive special form can use a lisp form as its argument descriptor; this form should evaluate to a list of arguments.

This lets an interactive command compute its arguments from the context, record argument history, and so on.

read-from-minibuffer supports both setting the initial value and recording history; with its help we can make td remember what was entered and offer it upon next invocation.

(defun td (stream variable)
  (interactive
   (list
    (read-from-minibuffer "Stream: "
                          (when (boundp 'td-history) (car td-history))
                          nil nil 'td-history)
    (read-from-minibuffer "Variable: ")))
  (insert (format "%s << \"%s is: \" << %s << std::endl;" stream variable variable)))

PS: Since you are debugging C++ code, you can add __FILE__ and __LINE__ macros, to get something similar to

(defun td (variable)
  (interactive "sVariable:")
  (insert (format "std::cout << \"file \" << __FILE__ << \" line \" << __LINE__ << \" %s is: \" << %s << std::endl;" variable variable)))
4
  • Thanks. That's great. Works really nicely. I modified it to also allow me to specify the stream, e.g. std::err or std::cout etc. So I have defun td(stream variable) etc. I would like to know if I can make stream default to the last one I used. In the same way that regexp-search does if you invoke it twice?
    – Joey O
    Nov 14, 2014 at 14:46
  • This is how you should do it. But being C++, for maintainability, you'll probably want to format with an error macro (can't use a function of the FILE and LINE macros won't expand right).
    – Andy
    Nov 16, 2014 at 9:03
  • #define error(v) do { if (debug) std::cerr << "file " << __FILE__ << " line " << __LINE__ << " " #v " is: " << v << std::endl; } while(true)
    – Andy
    Nov 16, 2014 at 9:09
  • Dang it, past five minutes. I meant while(0) I really did.
    – Andy
    Nov 16, 2014 at 9:17
5

Like this

(defun example(name)
  (interactive "sWhat's your name: ")
  (message "Hello, %s" name))

The key part is the "s" prefix. Use s for plain strings, b for buffers, etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.