http://www.perlmonks.org?node_id=119901


in reply to Learning Emacs

Hi,
if I hadn't my highly personalized xemacs I wouldn't know how to survive. Acutally XEmacs, xterm, mozilla ruby and perl make up at least 95% of my work time :)

Anyway... Lemme get to the fun stuff.

Skeletons

First I'd like to sent you to my node (X)Emacs Skeletons and Auto-Insert, where I show off some skeletons. You need to know that skeletons are extremely powerful templates. I abandoned all the keyboard macros I once recorded and organized plus any abbrevs that may have been there in favour of skeletons because they're just _it_.

An Explanation Plus An Example

(define-skeleton ska-skel-perl-sub "Insert a perl subroutine with arguments." "Subroutine name: " "sub " str " {" \n "my (" ("Argument name: " "$" str ", ") -2 ") = @_;" "\n" \n _ \n "}" '(progn (indent-according-to-mode) nil) \n)
This defines an elisp function called ska-skel-perl-sub which then inserts a perl sub template. You can bind this function to a key in the usual way(s), e.g.:
(local-set-key '[(control b) (control s)] 'ska-skel-perl-sub)
(keep in mind that this must be called from the appropriate hook - see below).

The overall structure of a skeleton is:
(define-skeleton ska-skel-perl-sub This defines the name to use
"Insert a perl subroutine with arguments." A documentation string, which gets prepended to the general skelton docs when you call C-h f ska-skel-perl-sub
"Subroutine name: " This is a prompt for a string (without any TAB completion). The string you put in here is later available as str, but if you don't need any user information you might as well put nil here.
All later stuff is either inserted or interpreted.

Special Sequences

There are several special strings in a skeleton:
str
The string the user gave at the prompt
\n
Insert current line according to mode and newline (this doesn't work always correctly)
>
indent current line
_
position the cursor shall be when skeleton is done. I sometimes encounter problems with this, too
- num
delete num chars leftwards
& and |
logical and and or. When the preceding command has moved the point & will do the next thing whereas | does the usual logical or stuff (like you know from the shell...)
Of course there is even more. For example an opening brace introduces a new recursive skeleton which may ask for a string again (used in the above example), or you may execute some lisp code (usually by putting it into a progn statement, and returning </code>nil</code>!) and whatevermore.

See C-h f skeleton-insert for docs and sh-script.el or skeleton.el for examples (I think the ada-mode contained some examples, too)

Hooks

The main emacs way of customizing modes is by using the appropriate hooks. A hook is a piece of code that get's executed (e.g.) when a mode connected with that hook is entered. A Perl Mode Hook may look like this:
(setq cperl-mode-hook '(lambda () ;; my keybindings (ska-coding-keys cperl-mode-map) (ska-cperl-mode-keys) (auto-fill-mode 1) ;; if you don't want tabs ;;(setq indent-tabs-mode nil) ;; full featured mode: (setq cperl-hairy t) ;; alternatively: ;;(setq cperl-auto-newline-after-colon t) ;;(setq cperl-electric-parens "({[") (setq cperl-auto-newline t) (setq cperl-electric-linefeed t) ))
Here I call a function that sets up some functions available for all modes I use (ska-coding-keys), the special perl keybindings, turn on the auto-fill which breaks lines at a certain column (C-h v fill-column) and make the perl mode very active so that it inserts all kinds of stuff automatically (this is definitely a matter of taste! I hate it in C-Mode but in perl for me it's fine).

Just to make this posting kind of complete I provide (some of) the missing function and offer to sent you my complete emacs setup per email (drop me a /msg with your adress)

Update: Added READMORE tag (taking into account what has been said :)

If you want (almost) all code:

;;{{{ Programming Keys For All Modes ;;---------------------------------- (defun ska-coding-keys (map) "Sets the key bindings which shall be available in all programming languages. Argument MAP is the local keymap (e.g. cperl-mode-map)." (define-key map '[(return)] 'newline-and-indent) (define-key map '[(control b) (d)] 'chb-insert-debug-output +) (define-key map '[(control b) (\;)] 'chb-comment-region-or-l +ine) (define-key map '[(control b) (\:)] 'chb-uncomment-region-or +-line) (define-key map '[(control b) (c)] 'chb-copy-and-comment-re +gion-or-l ) ;;}}} ;;{{{ Perl Mode ;;------------- (require 'ska-skel-perl) (defun ska-cperl-mode-keys () "Setting local keybindings for major mode: perl." (local-set-key '[(meta tab)] 'hippie-expand) (local-set-key '[(control b) (control b)] 'executable-interpret) ;; skeletons and makros MIGHT use C-b C-s as prefix if they get too +many (local-set-key '[(control b) (control f)] 'ska-skel-perl-file-loop) (local-set-key '[(control b) (control s)] 'ska-skel-perl-sub) (local-set-key '[(control b) (control i)] 'ska-skel-perl-prog-id) (local-set-key '[(control b) (control o)] 'ska-skel-perl-options) ) ;;}}} (require 'skeleton) (define-skeleton ska-skel-perl-file-loop "Insert a typical perl file loop construct." "Variable name: " "my $" str " = new IO::File(\"" (let ((fname (read-string "Filename-expression: "))) (concat fname "\") or die \"Couldn't open " fname ": $!\";")) \n "while(my $line=<$" str ">) {" \n "chomp($line);" \n "next if $line=~m/^\\s*$/;" \n "next if $line=~m/^\\#/;" "\n" \n _ \n "}" '(progn (indent-according-to-mode) nil) \n "$" str "->close();" \n) ;; any other way to get a time format string? (require 'time-stamp) (define-skeleton ska-skel-perl-prog-id "Insert perl program identification." (nil) (insert-char ?# 60) \n "#" (insert-char ? 18) "PROGRAMM IDENTIFICATION" (insert-char ? 17) "#"\n (insert-char ?# 60) \n "my $program = \"" (file-name-nondirectory (file-name-sans-extension bu +ffer-file "\";"\n "my $filedate=\"" (time-stamp-strftime "%y-%m-%d") "\";"\n "my $fileversion=\"0.01\";"\n "my $copyright = \"Copyright (C) " (substring (current-time-string) +-4) " by Stefan Kamphausen\";"\n "my $title = \"$program $fileversion, $filedate - $copyright\";" ) (define-skeleton ska-skel-perl-options "Insert perl program getopt stuff." (nil) (save-excursion (if (re-search-backward "^use" (beginning-of-buffer) t) (progn (end-of-line) (newline-and-indent)) (progn (beginning-of-buffer) (while (string-match "^#" (char-to-string (ch +ar-after) (forward-line)))) (insert "use Getopt::Long;") (indent-according-to-mode) (insert "\n") nil) (insert-char ?# 60) \n "#" (insert-char ? 26) "OPTIONS" (insert-char ? 25) "#"\n (insert-char ?# 60) \n "my $opt_help = 0;"\n "my $opt_version = 0;"\n "my $ret = GetOptions("\n "\"help!\","\n "\"version!\""\n ");"\n ) ;; This is the copyright holder (if (boundp 'my-copyright-holder) (setq auto-insert-copyright my-copyright-holder) (setq auto-insert-copyright (user-full-name))) (setq auto-insert-alist '( ((perl-mode . "Perl Program") nil "#! /usr/bin/perl -w\n\n" "# File: " (file-name-nondirectory buffer-file-name) +"\n" "# Time-stamp: <>\n#\n" "# Copyright (C) " (substring (current-time-string) - +4) " by " auto-insert-copyright "\n#\n" "# Author: "(user-full-name) "\n#\n" (progn (save-buffer) (shell-command (format "chmod +x %s" + (buffer-file-name))) "") "# Description:\n# " _ "\n" ) ;;}}} ;;{{{ Ruby Programm ((ruby-mode . "Ruby Program") nil "#! /usr/bin/env ruby\n\n" "# File: " (file-name-nondirectory buffer-file-name) +"\n" "# Time-stamp: <>\n#\n" "# Copyright (C) " (substring (current-time-string) - +4) " by " auto-insert-copyright "\n#\n" "# Author: "(user-full-name) "\n#\n" "# Description: " _ "\n#\n\n" "class " (replace-in-string (upcase-initials (file-name-nondire +ctory + (file-name-sans-extension buffer-file-name))) "_" "") "\n" "def initialize()" (progn (ruby-indent-command) "") "\nend" (progn (ruby-indent-command) "") "\n end" (progn (ruby-indent-command) "") ) )) --- chb-utils missing here!!

I hope I have copy'n'pasted it all correctly here. If you got problems, contact me.

Have fun!!

Regards... Stefan
you begin bashing the string with a +42 regexp of confusion