Hints for editing with Emacs

Quick Tips

Recursive editing

If you are in the middle of a query-replace operation and you realize that your regular expression was not precise enough and did too many substitutions, you don't need to stop the replace operation to correct the one or two occurencies, where the replacement was not wanted: Instead you type C-r and you can start editing, as you would do if you aborted the operation with C-g, but after you've done with these minor changes or adjustments you can continue, where you interrupted the query-replace. To switch back from recursive editing to the replace operation you just type M-C-c. Usually you are already at the next matching phrase, when you realize that something went wrong with the last one so like SPACE or n there is a single character command that implement this third option: The caret ^ skips back one match.

If the minor changes that you planned to make during recursive editing take a little bit longer it happens often enough, that you forget that you are in a recursive session. Fortunately the mode line indicates the level of recursion at which you are with square brackets around the major and minor mode labels. If you see too many brackets there, it might be a good idea, to get back to normal state with M-x top-level.

Using Filters on Regions in an Emacs Buffer

The command 'shell-command-on-region' with the keystroke 'M-|' sends the current region as input to the command that you specify in the minibuffer. Normally the output goes to the special buffer '*Shell Command Output*', but if you give the keystroke a prefix (the universal prefix C-u is enough for that), the output replaces the input, that is the currently selected region. So

C-u M-| uniq"pipe region through unix tool uniq"

removes duplicated line from the current region.
To process the whole buffer you only have to select the buffer before, which is most easily done with the keystrokes 'C-x h', the usual binding for 'mark-whole-buffer'.

Actually the key sequence Control-u Esc-AltGr-< is terrible with a german keyboard layout. The vi (and its plain vi, not vim) implementation of this function is clear and simple: : !uniq especially as its cousin "insert only the output of the command" :r !uniq is the same except for the r. To be fair we have to admit that simple : ! is only working if you changed from Visual mode (capital V) directly to :ex mode. And only in newer vi's (elvis, vim, nvi) and not in the traditional vi. In vi's without Visual mode you have to explicitly specify a region of lines (,$ or ,+5 or %) that should be used for piping through the external command.

Often I use the command C-u M-| sed "/match/d" with sed to delete the lines that match on a regular expression. Doing this with the builtin query-replace-regexp is complicatd because I have to think very hard to find a regular expression that matches for all occurances that I want to delete the whole line. And even then the replace process will only delete the contents on the line, but the line will continue to exist as an empty line. Again in vi you just put the same expression that you give to sed on the :ex command line.

The proper emacs way to do this is to avoid query-replace-regexp and use delete-matching-lines or flush-lines instead. Yes, you need to know that these commands exists ... but most tutorials don't mention them.

Shell commands and character encoding

... needs to be done ...

Using etags

To create a tags table for all source and header files in the current directory and its subdirectories, use a combination of find and etags.

find . -name "*.[ch]" -print | etags -

Getting help (man pages) with F1

To retrieve the man pages of the word currently under the cursor use the manual-entry function of the man.el package and bind it to a Function Key.
Note: This works only on UNIX systems as the man package runs the man command in the background.

(global-set-key [(f1)] 
  (lambda () (interactive) (manual-entry (current-word)) ))

EMACS LISP programming

One of the main issues in macro programming is using variables and defining a scope for this variables. In most cases variables do not need to exist outside of the function that you are currently setting up. Elisp behaves much like Perl or Visual Basic: whenever a variable is used it starts to exist and behaves like a global variable. To prevent this behaviour you can define variables and their scope explicitely:
  (let ((var1 value1) (var2 value2) ...) statements)
This is basically the same as the (progn ... ) function to setup a block of statements, but additionaly you can access the local variables that you have defined in the variable list following directly on "let".

;; Getting input arguments from the user
(defun any-func (first second count)
   "Function description that is displayed after C-h f any-func"
   (interactive "sReplace string: \nsReplace %s with: \nnHow often: ")
   (let ((something "nothing"))
       :
     (setq something (first))
       :
     (while (< i count)
       :
     )
   )
) ;end of function

;; Start and End point of region as input parameter pair
(defun using-region (start end)
  "Demo for using region points as input parameter pair."
  (interactive "r")     ; r  is for region
   ...
  (setq something (start))
     :
  (if (< something 26)
      (message "Condition 'something less than 26' is true")
    ;; false-block follows
    (goto-char (point-max))
    (message "Condition evaluated to false")
  )
)

Minor Modes

A minor mode needs a buffer local variable that indicates if the minor mode is activated or not. And a command that activates or de-activates the mode.

(defvar myname-mode nil
  "Description for this mode variable")
(make-variable-buffer-local 'myname-mode)

(defun myname-mode (&optional arg)
  "A special minor mode"
  (interactive "P")
  (setq myname-mode
        (if (null arg)
            (not myname-mode)
          (> (prefix-numeric-value arg) 0) ))
  (if myname-mode
      (... stuff to turn the mode on ...)
    (... turn it off ...))
)

Furthermore you should specify a label for your minor mode that will be displayed in the mode line.

(setq minor-mode-alist
      (cons '(myname-mode " Clever-name") minor-mode-alist))

Normally you would first test if your new minor mode is not already part of the currently active minor modes, before adding it to the list.

Other helpful lisp constructs:
Test functions: bolp read it as beginning of line point ? tests if the cursor is currently at the end of a line. Similarly there are eolp, bobp, eobp where the last b is for buffer.
As you're mostly working with text in files/buffers one common task is to copy a portion of text from the buffer in a string variable. This is obviously not a user command as (yank), so it is hard to find in the online help as you have no starting point. (buffer-string) and (buffer-substring 23 45) for copying the complete buffer or the specified range of it, is what we need. Another copying function is (match-string N), that copies/returns the string of the last regular expression search. N can be between 1 and 9 and refers to the same paranthesis group as \3 in the replace argument of query-replace-regexp.

Working with CVS

As cvs uses always a vendor tag or name, the structure inside the archive will always be something like gnu/diff or myself/HelloWorld. Because you probably don't need to have this two level structure reflected in your workspace, you can specify a certain directory, where the working files should go with the -d option.

cvs checkout -d SockTest rundev/SockTest

will create a new directory ./SockTest with all the files of this project in it. Without the -d option, it would have created ./rundev/SockTest.

Of course as long as you only want to get rid of the vendor name as an additional directory it's better to define a module alias in the repository. In the above case you would only have to append the line

SockTest    rundev/SockTest

and all the registered files below the directory rundev/SockTest in the repository will be created in a directory ./SockTest if you do a checkout, but now on the module not on the directory:

cvs checkout SockTest

CVS treats the module just like it would treat a given directory. This implies that you are now bound to the module name as the directory name. No suprise the -d option is also allowed for modules, so that you can check out the above module to a subdirectory SockTest_branch3 for example. You do not have to worry that CVS maybe unable to refer to the correct repository files since the directory name is different. While checking out, all the necessary information is stored in the files in the ubiquious CVS subdirectories.

By the way, 'appending the line' doesn't mean: edit the file 'modules' directly. But checkout this single file with checkout CVSROOT/modules, make your changes and check it in again.