Emacs: Friend or Foe?
Now, what about bindings involving multiple keys? For example, I like to use the key sequence C-d C-d to delete a line (somewhat like its vi counterpart), and C-d g to delete text from point to the end of the buffer. The second argument to global-set-key can include multiple keys, but the problem is that C-d already has a meaning. We want to use C-d as a “prefix” key for the commands C-d C-d and C-d g, so first we have to unbind C-d. Here's what we do:
; Various keys for nuking text (global-unset-key "\C-d") (global-set-key "\C-d g" 'my-nuke-to-end) (global-set-key "\C-d\C-d" 'my-nuke-line)
We simply use global-unset-key to unbind C-d, and then bind new meanings to C-d g and C-d C-d. However, these functions are bound to the mysterious functions my-nuke-to-end, and my-nuke-line, which the astute among you will notice aren't standard Emacs functions. We have to define them.
Defining an Emacs LISP function is rather simple. Of course, Emacs functions can be quite powerful and complex, but in this case we're going to use the function to call a short sequence of other functions, which isn't so frightening. In general, if you need a key binding to call several functions in sequence, you must define a new function to wrap the sequence in.
Here is the definition of my-nuke-to-end, which should be placed above the corresponding call to global-set-key, which uses it, in the .emacs file.
(defun my-nuke-to-end () "Nuke text from here to end of buffer." (interactive "*") (kill-region (point) (point-max)))
The defun function takes as arguments the function name to define, a list of arguments (which, here, is empty), followed by the body of the function. Note that the first line of the body is a string constant, which is a short description of the function. This string is displayed when describe-key or describe-function is used to display information about my-nuke-to-end.
The second line of the body is a call to the interactive function. This is required for functions that are bound to keys. It simply tells Emacs how to execute the function interactively (that is, when called from a key sequence). The argument to interactive, “*”, indicates that the function should not be executed within a read-only buffer. Check out the documentation for interactive if you want the gritty details. (See the sidebar “Getting the Emacs LISP Manual” for information on obtaining this documentation.)
The last line of the body uses the Emacs internal function kill-region to delete a region of text. The two functions point and point-max return the current location of point, and the position of the end of the buffer, respectively. kill-region deletes the text between these two locations.
The definition for my-nuke-line is somewhat more involved, because there is no single Emacs function that this operation maps to. Here it is:
(defun my-nuke-line (arg) "Nuke a line." (interactive "*p") (beginning-of-line nil) (kill-line arg) (if (= (point) (point-max)) (progn (forward-line -1) (end-of-line nil) (kill-line arg) (beginning-of-line nil))))
First of all, we see that this function now takes an argument, which we have called arg. Many Emacs key functions take a single numeric argument, which you can specify by prefixing the key with C-u, followed by a number. (That is, unless you've rebound C-u, as we have.) This numeric argument changes the behavior of certain functions. Here, arg is passed along to kill-line, used on lines 4 and 9 of the function body.
my-nuke-line is essentially a wrapper for kill-line, but takes care of a special case for the last line in the buffer. In this case, we want to delete the newline before the last line, which causes the last line to be clipped out altogether (otherwise, Emacs deletes the line, but leaves a blank one in its place). After interactive is called (with the “*p” argument, which causes arg to be converted to a number), beginning-of-line moves point to (surprise!) the beginning of the line. kill-line is then invoked. Note that kill-line only kills text from point to the end of the line; not the entire line.
Next, we compare the cursor position (point) with the end-of-buffer position (point-max). If they are equal, then we are trying to delete the last line of the buffer, and want to kill the previous terminating newline. We move back a line (using forward-line with an argument of -1), move to the end of that line, kill the rest of the line (which consists only of the terminating newline), and move back to the beginning of the line. All of this results in the last line of the buffer being deleted.
I'm sure that there are Emacs gurus out there that can find much better ways to accomplish the same thing; please bear with me. I've been brainwashed by vi. One of Emacs' better features is that there are many ways to modify its behavior.
|Dynamic DNS—an Object Lesson in Problem Solving||May 21, 2013|
|Using Salt Stack and Vagrant for Drupal Development||May 20, 2013|
|Making Linux and Android Get Along (It's Not as Hard as It Sounds)||May 16, 2013|
|Drupal Is a Framework: Why Everyone Needs to Understand This||May 15, 2013|
|Home, My Backup Data Center||May 13, 2013|
|Non-Linux FOSS: Seashore||May 10, 2013|
- Dynamic DNS—an Object Lesson in Problem Solving
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Using Salt Stack and Vagrant for Drupal Development
- New Products
- Validate an E-Mail Address with PHP, the Right Way
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- The Secret Password Is...
- RSS Feeds
- New Products
- All the articles you talked
38 min 19 sec ago
- All the articles you talked
41 min 26 sec ago
- All the articles you talked
42 min 46 sec ago
5 hours 7 min ago
- Keeping track of IP address
6 hours 58 min ago
- Roll your own dynamic dns
12 hours 11 min ago
- Please correct the URL for Salt Stack's web site
15 hours 23 min ago
- Android is Linux -- why no better inter-operation
17 hours 38 min ago
- Connecting Android device to desktop Linux via USB
18 hours 7 min ago
- Find new cell phone and tablet pc
19 hours 5 min ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi
It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?