Introduction
Welcome to the next lesson in our journey through Elisp. In the previous lesson, we explored lambda functions and saw a practical example of how to bind a simple, anonymous function to a key. You may recall this snippet:
(global-set-key (kbd "C-c s")
(lambda ()
"Insert a scene separator."
(interactive)
(insert "\n* * *\n\n")))
We noted that the (interactive) form was the "magic" that allowed a functionโin this case, a lambdaโto be executed directly by you, the user. Today, we're going to demystify this powerful expression.
This lesson focuses on the learning outcome: Make a function into an interactive command using the 'interactive' specifier. We will distinguish between functions meant for internal use by other code and "commands" meant for you to run. This is the crucial step that transforms a piece of Elisp logic into a tangible tool you can use to extend your Emacs workflow.
1. The Two Types of Functions: Internal vs. Interactive
In Elisp, not all functions are created equal. It's helpful to think of them in two categories:
-
Internal Functions: These are the standard functions you've been writing. They are designed to be called by other Elisp code. They take arguments, return values, and act as the building blocks of larger programs. You wouldn't typically run them directly yourself.
-
Interactive Functions (Commands): These are special functions designed to be invoked directly by you, the user. An interactive function is what Emacs calls a command. These are the functions that appear when you press
M-xand are the ones you can bind to key sequences.
The key benefits of making a function interactive are:
- Discoverability: It appears in the list of commands available through
M-x. - Usability: It can be bound to a key.
- User Input: It can prompt you for arguments, a topic we'll explore in depth in the next lesson.
To get a clear overview of this distinction, please watch the following segment from the "System Crafters" channel.
Defining Functions and Commands - Learning Emacs Lisp #3
This video clearly explains the concept of interactive functions, or commands, and highlights why they are central to customizing the Emacs user experience.
Watch from 36:02 to 38:57. Focus on the distinction between a normal function and a command, and the benefits of making a function interactive.
2. The interactive Specifier
So, how do you tell Emacs that your function is a command? You use the (interactive) specifier.
The rule is simple: (interactive) must be the first expression in the body of your function. If you have a docstring (which you always should!), it goes right after the docstring.
Let's see the transformation.
Step 1: A Regular Function
Open your *scratch* buffer and define this simple function. Evaluate it using C-x C-e.
(defun say-hello ()
"Display a greeting in the echo area."
(message "Hello from Elisp!"))
Now, try to run it. Press M-x and type say-hello. You'll find nothing. This is an internal function; Emacs doesn't consider it a user-facing command.
Step 2: An Interactive Command
Now, let's add the magic ingredient. Modify the function like this and re-evaluate it:
(defun say-hello ()
"Display a greeting in the echo area."
(interactive)
(message "Hello from Elisp!"))
Try again. Press M-x and type say-hello. This time, it appears in the list! Select it and press Enter. You'll see "Hello from Elisp!" in your echo area. You have just created your first interactive command.
The following video segment demonstrates this exact process and also shows how Emacs's own help system recognizes the difference.
Defining Functions and Commands - Learning Emacs Lisp #3
This clip walks through the process of adding (interactive) to a function and shows the immediate effect it has on its availability via M-x.
Watch from 38:57 to 41:00. Notice how the function becomes available in the M-x command list and how the output of describe-function (C-h f) changes.
For a textual reinforcement of this concept, the following article provides a concise example.
Introduction to Emacs 3 - On Emacs-Lisp
This blog post by Leonardo Tamiano includes a simple, practical function that refreshes the current file. It's a great example of a useful command.
Read the short section titled "Some Functions". Pay attention to the refresh-current-file example and the author's explanation of why (interactive) is necessary.
3. Your Turn: A Practical Command for Creative Writing
Let's build a command tailored to your background in creative writing and speculative fiction. A common need is to quickly jot down a new story idea. We can create a command that inserts a simple template into the current buffer.
Here is the full function definition. Copy it into your *scratch* buffer.
(defun new-story-idea ()
"Insert a template for a new story idea.
Includes fields for Title, Logline, Characters, and Notes."
(interactive)
(insert "# Title: \n\n# Logline: \n\n# Characters: \n\n# Notes: \n"))
Let's break it down:
(defun new-story-idea () ...): We define a function namednew-story-ideathat takes no arguments."Insert a template...": A multi-line docstring explaining what the command does. This is what you see when you useC-h f.(interactive): The crucial part. This tells Emacs, "This is a command for the user."(insert "..."): The body of the function, which inserts our template string into the current buffer. The\ncharacters create new lines.
Now, do the following:
- Place your cursor after the final parenthesis of the
defunblock and pressC-x C-eto evaluate and install the function. - Press
M-xand start typingnew-story-idea. You should see it appear as a callable command. - Press
Enter. The template will be inserted wherever your cursor is.
This is a simple but powerful example of building a tool for your specific workflow.

4. What About Functions with Arguments?
Our new-story-idea command is simple because it requires no input from the user. But what happens when an interactive function needs arguments?
Consider this function:
(defun greet-person (name)
"Display a personalized greeting."
(interactive)
(message "Hello, %s!" name))
If you evaluate this and run M-x greet-person, Emacs will raise an error, likely saying "Wrong number of arguments: (0 for 1)".
Why? We've told Emacs the function is interactive, but we haven't told it how to get a value for the name argument in an interactive context. Should it prompt the user? Should it use the text currently selected? The simple (interactive) form doesn't provide this information.
This is where the true power of the interactive specifier comes in, and it's the subject of our next lesson. It can take its own argumentsโspecial character codes in a stringโthat tell Emacs exactly how to supply values to your function's parameters when run by a user.
Conclusion
You've now mastered a fundamental concept in Emacs Lisp: turning a piece of logic into an executable command. This is the bridge between writing code and extending the Emacs environment in a meaningful way.
Key Takeaways:
- Emacs distinguishes between internal functions (for code to call) and interactive commands (for users to run).
- The
(interactive)specifier, placed after the docstring in a function's definition, is what turns it into a command. - Interactive commands are automatically discoverable via
M-x, making them an integral part of the Emacs user experience. - Simple commands require just
(interactive), but commands that need arguments require a more advanced form, which we will cover next.
Preview of the Next Lesson
In the next lesson, we will unlock the full potential of interactive. You'll learn how to use interactive codes to prompt the user for different types of inputโstrings, numbers, existing files, regions of text, and more. This will allow you to build sophisticated and genuinely useful commands for your personal workflow.