Intermediate Emacs ================== Now that you've had a little introduction to Emacs and some of its keystrokes, you may be able to appreciate this comic. .. image:: imgs/real_programmers.jpg :align: center You haven't gotten much chance to experience the true power of emacs yet, though. Unfortunately we won't really be firing up the warp engines; there's plenty online if you want to delve deeper. Please have a look at this page: `A Tour of Emacs `_ You'll notice that we've talked about several of the commands you see there. But there is MUCH more. Emacs has a built-in programming language which let's you write functions and programs which you can bind to keystrokes. Let's look at just a few more features before we leave our introduction to Emacs. Customization: The ``.emacs`` Startup File ------------------------------------------ When Emacs starts, it looks for a file in your home directory called *hidden* file called: ``.emacs``. This file contains commands written in the Emacs programming language called `*Lisp* `_ (more specifically it is *Emacs Lisp* --a variation of *Lisp*). You can customize Emacs to alter its behavior to your liking. For example, when Emacs started up before, we clicked on the line that said ``Dismiss this startup screen`` Actually that text was linked to a Lisp function which wrote the following text in your ``.emacs`` file. :: '(inhibit-startup-message t) Open a shell window (if you don't have one open). Type **ls -a** (or better you *alias* **la**) for a listing of *all files. You should see ``.emacs`` in the list. Have a look at it with **less**. You should see something like this: :: ;; .emacs (custom-set-variables ;; custom-set-variables was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. '(diff-switches "-u") '(inhibit-startup-screen t)) This may look a bit terrifying, but here's a quick example of the kind of thing you can do. Try this: Edit your ``.emacs`` file in Emacs (type: **emacs .emacs**), and add the following line to the bottom :: (display-time) Then save the ``.emacs`` config file, the next time you start emacs, you will see something like this: .. image:: imgs/emacsDisplayTime.jpg The time is now displayed in the *mode-line*. Not going to change your life, but at least you see how the customizations work. Consult the web for more customization ideas. | Find and Replace ---------------- Let's do a simple task which might come up while you are editing. It might seem stupid, but it will lead us into a more advanced topic. Open Emacs by typing: **emacs** at the prompt. | With no filename (new or existing) give, Emacs start on a buffer called ``*scratch*`` that looks like this: :: ;; This buffer is for notes you don't want to save, and for Lisp evaluation. ;; If you want to create a file, visit that file with C-x C-f, ;; then enter the text in that file's own buffer. -UUU:----F1 *scratch* All L5 (Lisp Interaction)----10:32AM 0.51-------- For information about GNU Emacs and the GNU system, type C-a. If you want a clean new file in which to put text, you either need to supply a *filename* on the command line when you start emacs, or "*visit*" the file by asking emacs to *open a file* with **C-x C-f**, and giving it a name. So, let's call this file, ``cat.txt``. Copy the text fragment below into the buffer :: The brown cat is fat The fat cat is old Therefore, the brown cat is old. Let's substitute "``dog``" for "``cat``" in this file. Easy enough. Make sure the cursor is at the beginning of the file (on the first character of the first line). You do this so that everything below will be subject to the Search/Replace. Click on " **Edit->Replace->Replace String** in the *Toolbar*. .. image:: imgs/emacsReplace.jpg This will make Emacs prompt you in the mini-buffer with the words: ``Query replace: ``. .. image:: imgs/emacsReplaceModeline.jpg In the mini-buffer type: **cat** then **RETURN**. .. image:: imgs/emacsReplaceCat.jpg (Remember if anything goes wrong--you can always "Abort" with **C-g** or the Toolbar->Red (X), and then start over). The mini-buffer responds with: ``Query replace cat with: `` .. image:: imgs/emacsReplaceCatWith.jpg Type: **dog** then **RETURN** .. image:: imgs/emacsReplaceCatWithDog.jpg Emacs highlights the next instance of ``cat``, and waits for your input. .. image:: imgs/emacsReplaceBuffer.jpg Also the mini-buffer has changed to: ``Query replacing cat with dog: (? for help)`` .. image:: imgs/emacsReplaceMiniBuffer.jpg To *accept* this Replacement (i.e. *cat->dog*), just hit the **Spacebar** . Emacs *replaces* ``cat`` with ``dog``, jumps to the next ``cat`` and waits for your choice on the next occurance of ``cat``: .. image:: imgs/emacsReplaceCat2Dog.jpg This time, hit the "**n**" key (for *No*, do not replace this occurance) instead of *Spacebar*. Emacs will skip that replacement and jump to the next ``cat``. Hit the **Spacebar** on this next one. Emacs says: "``Replaced 2 occurances``", which is what it did. Now you should have the following text in your emacs buffer: :: The brown dog is fat The fat cat is old Therefore, the brown dog is old. | **The Text-mode way** Let's change these "dogs" back to "cats". But this time we'll do it the Text-mode way. Put the cursor at the beginning of the file. You may have noticed when you clicked *Edit-Replace-Replace String* in the Toolbar, that to the right of the menu item was the character string: *M-%*. This is the *Text-mode key binding* for the *Query/Replace* command (``query-replace``). Type: **M-%** (Yeah: **ESC** followed by "**%**". Understand the XKCD comic better now?) This initiates a "Query/Replace" command, just like you did above with your mouse in the GUI Toolbar. This time, since you just previously did a *Query/Replace*, Emacs offers the same replacement strings as the "*Default*". .. image:: imgs/emacsReplaceDefaultPrev.jpg If you just hit **RETURN**, you will accept the *Default*: replacing ``cat`` with ``dog`` again. Since we skipped one ``cat`` (the "fat cat") in the previous execise, there should be one ``cat`` left to transform to a ``dog``. Go ahead and hit **RETURN**. Emacs will jump to that occurance of ``cat`` and wait for you to hit **Spacebar** to *accept* the swap. Now, the text should be all about *dogs*. | Let's practice one more time, and change all the *dogs* back to *cats*. Put the cursor at the beginning of the text. Type: **M-%** In the mini-buffer, after "``Query replace (Default: cat - >dog): ``", type **dog** Then after "``with:``", type **cat** Emacs jumps to the first instance of "``dog``". | This time, let's just do them all at once--we don't want to go through each instance of "``dog``" and answer with "**Spacebar**" or "**n**". Simply type **!** (an exclaimation symbol). Emacs will change all occurances of "``dog``" to "``cat``" throughout the file. | Let's summarize Query/Replace: | ================================= ==================================================== **Query (Search) / Replace** (``query-replace``) ---------------------------------------------------------------------------------------- GUI (menu/mouse) Mode *Edit->Replace->Replace String* Text Mode type: **M-%** ================================= ==================================================== | =============== =========================== *Replacement Choices* --------------------------------------------- **Spacebar** to accept replacement **n** to regect the change **!** to accept all replacements **?** for help =============== =========================== | Regular Expression Matching --------------------------- Try this; in Emacs, open a new file ``regexp.txt`` and copy the following text into it. :: zzz1234 zyx2345 zzz5555 uuu9845 u6638v v3948w w8395x x7730y y2349z Let's suppose this is data from some log file, and you need to extract the numbers from each line. You *could* do it *by hand*, i.e. move around and use *Backspace* and *Delete*. Yuk. You *could* do *six Query/Replace* operations: replacing the characters ``u,v,w,x,y,z`` with empty replacement strings (""), i.e. just hit RETURN when asked for the Replace string: :: "u" -> "" "v" -> "" ... "y" -> "" "z" -> "" That would do it, but it's a lot of different Query/Replace operations. Yuk, again. ---------------------- | There's a really cool way to do it using *Regular Expressions*: a match *pattern* rather than an *exact* match, like ``cat``. What we want to do is to remove all the alphabet characters (a-z) and leave the numbers (0-9). So we need a pattern that will only match alphabet characters. | *Make sure your cursor is at the top of the text window*. Emacs will (for now) only search *Forward* for matches. So, if you start the Query/Replace with the cursor at the end of the text, it will not find anything. You can quickly move the cursor to the beginning of the buffer by typing: **C-HOME** (Ctrl-HOME). Similarly, **C-END** takes you to the end of the buffer. | To invoke a **Query/Replace using a Regular Expression** (``query-replace-regexp``), we can either use + the GUI method: *Edit->Replace-Replace Regexp...* + or the Text-mode keyboard sequence: **M-C-%** Yup: that's **ESC** followed by **Ctrl-%**, including the *SHIFT* key needed to get the *%*. Unless you're pretty dextrous, just use the GUI way: .. image:: imgs/emacsQueryRegexpGUI.jpg :align: center | In the *mini-buffer* you see the prompt for the ``regexp``, the *Regular Expression* (and because I didn't close my Emacs window since the last Query/Replace, you see the ``default: cat -> dog`` from before). Emacs is now asking for a ``regexp``--a *PATTERN* to use for matching. Type: **[a-z]+** then **RETURN** .. image:: imgs/emacsQueryRegexpString.jpg The *pattern* is ``[a-z]+``. Here's what the parts mean: + ``[ ]`` says to match *any* of the character inside the brackets + ``a-z`` means any letter between ``a`` and ``z`` (if you wanted ANY letter, including CAPs you would do ``[A-Za-z]``) + ``+`` means match *one or more* of "these" When you hit *RETURN* above, Emacs is now waiting for you to supply the text to replace the thing matched (zzz, zxy, etc.) .. image:: imgs/emacsQueryRegexpString2.jpg If you simply hit **RETURN** again, meaning replace with *nothing* (the empty string), Emacs highlights *everything* that matches the *regular expression pattern* ``[a-z]+``. .. image:: imgs/emacsQueryRegexpHighlight.jpg Hit the **!** key, and *voila!*, all the letter characters are removed and your data is scrubbed clean. .. image:: imgs/emacsQueryRegexpClean.jpg | Like many topics in this course, this example is just to let you know that *Regular Expression Substitution* can be very useful. In addition to match a *pattern*, you can also *save* the *match data* and put it in the substituion string. For example, with one Query/Replace/Regexp command you could make the following substitution: :: zzz\ **1**\ abc -> filename\ **1**\ .dat zyx\ **2**\ cba -> filename\ **2**\ .dat qxz\ **3**\ bac -> filename\ **3**\ .dat There are many online resources to learn about *Emacs Regular Expressions*. Try: + `http://www.emacswiki.org/emacs/RegularExpression `_ + `http://www.gnu.org/software/emacs/tour/ `_ | *Regular Expressions* are used in most advanced programming languages, Python, PERL, Java, Javascript, PHP, etc. If you continue to develop your scientific programming skills, you will encounter them again. | ------------------------------------------- | In the above discussion, I have tried to always include the *emacs command* for each action. If you look back at the summaries, you see things like: ================= ==================== ==================== Action Emacs Command Keybinding ----------------- -------------------- -------------------- To open a file ``(find-file)`` **C-x C-f** To kill a buffer ``(kill-buffer)`` **C-x C-k** Paste Text ``(yank)`` **C-y** ...hundreds more ================= ==================== ==================== Here's a small sample of some of the Emacs `commands `_ | **Emacs: execute-extended-command (M-x)** If you happen to know the *Emacs command* for an *action*, you can have Emacs initiate that action by typing **M-x**, then typing the command in the mini-buffer. | Let's try it. If you don't have an open Emacs window running, start Emacs. Now *visit* a file ("visit" is the Emacs lingo for openning a file in a buffer), using the usual keyboard way: type **C-x C-f** Emacs responds with :: Find file: ~/ in the mini-buffer. You could continue by typing the name of a file to edit, like ``stairway.txt``. However, we don't need to edit the file. So, *abort* the action by typing **C-g** (or clicking the Red (X) in the toolbar. | Once you see ``Quit``, indicating that the action was aborted, type: **M-x** (ESC-x) The mini-buffer shows simply :: M-x Emacs is waiting for you to type a command. Type **find-file** and hit **RETURN** Emacs response with: :: Find file: ~/ the same as it did above, when you typed **C-x C-f**. You've just learned *yet another way* to make Emacs do things, by using the ``(execute-extended-command)`` command, which is bound to the keystrokes **M-x**. | A command I use often is the ``(goto-line)`` command. Suppose you programming and the compiler says you have a bug in your code at line 972. You can open the program file in Emacs and type **M-x**. Emacs responds with ``M-x`` in the mini-buffer. To this you type **goto-line** and **RETURN**. Emacs responds with: ``Goto line: `` You type: **972 RETURN** and Emacs jumps to line 972 in your program file so that you can edit out your syntax error. | This would be written in "Emacs lingo" as **M-x goto-line**. Of course there is a keyboard shortcut way to do this too: **M-g g** (ESC g g), but I find it easier to remember **M-x goto-line**. | Emacs Windows and Buffers ------------------------- Like most windowed (GUI) applications, you can resize the Emacs window by dragging the corner to make it bigger. You can also open several files/buffers in one emacs session. This is useful when you want to cut and paste across buffers, compare them, or use a host of other | **Emacs "modes"** | Here's an example of a useful mode, do this: **M-x calendar** This should pop up a second buffer in a smaller window at the bottom of your emacs window. This buffer will be in "Calendar mode" and thus responds to various keystrokes differently than a normal buffer. For example, if you click on a date that is not today's, the cursor moves there. Typing a period "**.**" takes the cursor back to today's date. Just a very small example of the behavior of Emacs modes. Now how do you get rid of the calendar? Well, you know how to kill a buffer: **C-x k** If your cursor is in the calendar window and you type the above keystroke **C-x k**, you will delete the calendar buffer. Go ahead and try it . You may see another buffer in it's place, like ***messages*** or another emacs' "operating buffers". You can kill that one too with **C-x k**. But what about the *Window*? Even though you killed the buffer the window is still there. | **To manipulate windows:** If your cursor is in the window you want to keep , you type **C-x 1** (think "*keep this ONE*"). If you want to delete the window your cursor is in , you type **C-x 0** (think "*this buffer is a ZERO*"). If you have two windows open, you can jump to the other window, by typing **C-x o** (*that's an "oh" for "other"*). Or you can just click in it, which will take your cursor there as well. If you have only one window and want to split your screen, type **C-x 2**. Note that in each window you can type **C-x C-f** to open a separate file in each. Of course you can also use the Toolbar. Finally, you can drag the *mode-line* (the info-bar between buffers) up or down to make the windows bigger/smaller. | Let's practice: In Emacs, type **C-x 2** to split the screen into two windows. Drag the mode-line in the middle of the screen to resize the windows. Type **C-x C-f** to visit a file. Any file will do. In fact, when you get ``Find File: ``, hit the **TAB** key, *twice*. This will list all the files in the current directory. You can click on one with the mouse. Hitting **TAB** again will scroll to the next page if there are more files than fit on one screen. | **Window control summary**: ================================ ======================= Action Keystrokes -------------------------------- ----------------------- Close this window **C-x 0** Close *all but* this window **C-x 1** Split current window into two **C-x 2** Split window *horizontally* **C-x 3** Jump to other window **C-x o** Compare text in two windows **M-x compare-windows** ================================ ======================= | Dired ----- One last useful trick. You can open a **directory** in Emacs: In an shell terminal, type **emacs .** (i.e. open "the current directory"). This will open Emacs with a long listing of your files. .. image:: imgs/emacsDired.jpg For more info on dired mode see: `GNU Emacs Manual/Dired `_ This is ``dired mode`` (*DIR*\ ectory *ED*\ it). There are many handy things you can do in dired mode. For example, you can **mark files for deletion** by typing **d** with the cursor on the line for a each file. After marking a number of files, typing **x** will "*expunge*" (delete) all marked files. Similarly, you can mark files to be *moved, copied*, etc. in bulk. This is handy if you need to do operations on a large number of files. Sure, you can do this easily by *Ctrl-Clicking* to mark a number of files in the GUI File Explorer, but if you are logged into a machine on the other side of the world through a terminal window (i.e. you DON'T have GUI access), this can be a very powerful way to do things that you take for granted in your desktop environment. Some Emacs Fun -------------- People with too much time on their hands have written some pretty silly Emacs modes. Open Emacs and try these (remember **C-x k** will kill the buffer): **M-x tetris** (do you guys know this ancient game?) **M-x doctor** Read: `Conway's Game of Life `_. Then do **M-x life** | This has given you a little taste of what Emacs can do. Homework ======== Homework 4 is `here `_