4 ### Author: Frank Terbeck <ft@bewatermyfriend.org>
7 ### generate grml zsh refcard.
12 ### #A#: abbreviations
16 ### consider these lines in zshrc:
17 ### #a3# execute \kbd{apt-cache policy}
18 ### alias acp='apt-cache policy'
20 ### Now this script will add a new description for 'acp' into
21 ### the replacement list created by the @@INSERT-aliases-debian@@
24 ### @@INSERT-aliases-default@@ == @@INSERT-aliases@@
25 ### @@INSERT-aliases-all@@ will create a sorted list of _all_
26 ### aliases from all subsections.
28 ### @@INSERT-other-foobar@@ is special, just does text replaces
29 ### without any special formatting, useful for:
30 ### \command{umask @@INSERT-other-umask@@}{...
31 ### 'other' does not have -default nor -all.
33 ### you may specify certain subsections like this:
34 ### #a3#, which will put the input in the into the
35 ### @@INSERT-aliases-debian@@ tag.
37 ### See the @secmap array below for section numbers.
38 ### Yes, this could be done with real names instead of numbers.
39 ### But names tend to be rather long. I don't want that.
44 my $refin = "./grml-zsh-refcard.tex.in";
45 if (defined($ARGV[0]) && $ARGV[0] =~ m!^[^+]!) {
50 if (defined($ARGV[0])) {
51 $verbose = length($ARGV[0]);
65 $inc, # global counter for input lines
68 %other, # @@INSERT-other-*@@
69 %splits # if lists get long, we might need to split them. HoA
71 my $splitstring="\\commandlistend\n\\pagebreak\n\\commandlistbegin";
76 if ($verbose < 5) { return; }
77 xprint(5, " --- Data ---\n");
78 foreach $key (sort keys(%other)) {
79 xprint(5, " \@\@INSERT-other-$key\@\@ -> $other{$key}\n");
81 foreach $key (sort keys(%data)) {
82 xprint(5, " \@\@INSERT-$key\@\@ =>\n");
83 foreach $entry (sort @{ $data{$key} }) {
84 xprint(5, "$entry\n");
87 foreach $key (sort keys(%splits)) {
88 xprint(5, " List-Splitting Offset for $key:\n");
89 foreach $entry (@{ $splits{$key} }) {
90 xprint(5, "$entry\n");
93 xprint(5, " --- Dump ---\n");
98 if ($verbose >= $level) {
103 sub escape_string($) {
105 $in =~ s!([\\\{\}\*\&~\$_])!\\$1!g;
109 sub demystify_keys($) {
110 # what an ugly hack :-)
112 my @tok = split(/(\\e[^\^]|\^.)/, $keys);
117 if ($k eq '') { next; }
118 if ($k =~ m!^[^\\\^]!) {
124 $k =~ s!\^[jJmM]!return!g;
134 my $linenum=shift; my $cat=shift; my $sec=shift;
136 if ($sec eq '') { $sec = 'default'; }
137 if (!defined($data{"$cat-$sec"})) {
138 warn("Unknown insertion tag in line $linenum (\@\@INSERT-$cat-$sec\@\@). IGNORING.\n");
141 xprint(1, "inserting: category($cat) section($sec), line: $linenum\n");
143 foreach $entry (sort @{ $data{"$cat-$sec"} }) {
145 foreach $is (@{ $splits{"$cat-$sec"} } ) {
147 print("$splitstring\n");
156 sub handle_hashdir($$) {
157 my $sec = shift ; my $desc = shift;
159 if ($sec eq '') { $sec=0; }
160 xprint(1, "Handling hashed dir (section: $secmap[$sec]) in line $ln ($desc)\n");
163 if ($input[$ln] =~ m!^\s*\#d[0-9]*\#!) {
164 xprint(1, "Ending hashed dir handling in line $ln.\n");
168 if ($input[$ln] =~ m!\s*hash\s+-d\s+([^=]+)=(.*)!) {
169 $dir=$1; $value=&escape_string($2);
170 push(@{ $data{"hasheddirs-$secmap[$sec]"} }, "\\command\{$dir\}\{$value\}");
173 warn("Broken hashed dir in line $ln. IGNORING.\n");
179 sub handle_abbrev($$) {
180 my $sec = shift ; my $desc = shift;
181 my ($abbrev, $value, $doc);
182 if ($sec eq '') { $sec=0; }
183 xprint(1, "Handling abbreviation (section: $secmap[$sec]) in line $ln ($desc)\n");
185 while ($ln <= $i) { # the global $i
186 if ($input[$ln] =~ m!^\s*\#A[0-9]*\#!) {
187 xprint(1, "Ending abbreviation handling in line $ln.\n");
192 if ($input[$ln] =~ s!\s+\#d\s*([^#]*)$!!) { $doc = $1; }
193 if ($input[$ln] =~ m!\s*['"]([^"']*)['"]\s\$?['"]([^"']*)['"]!) {
194 $abbrev = $1; $value = &escape_string($2);
195 xprint(2, "ab: $abbrev -> $value ($doc);\n");
196 push(@{ $data{"abbrev-$secmap[$sec]"} }, "\\command\{$abbrev\}\{\\kbd\{$value" . ($doc ne '' ? "\}\\quad $doc" : "\}") . "\}");
199 warn("Broken abbreviation in line $ln. IGNORING.\n");
205 sub handle_function($$) {
206 my $sec = shift ; my $desc = shift;
207 if ($sec eq '') { $sec=0; }
208 xprint(1, "Handling function (section: $secmap[$sec]) in line $ln ($desc)\n");
210 if ($input[$ln] =~ m!\s*(function)?\s*([^(\s]*)!) {
211 xprint(2, " - $2()\n");
212 push(@{ $data{"functions-$secmap[$sec]"} }, "\\command\{$2()\}\{$desc\}");
215 warn("Parsing function line $ln ($input[$ln]) failed. IGNORING.\n");
219 sub handle_alias($$) {
220 my $sec = shift ; my $desc = shift;
222 if ($sec eq '') { $sec=0; }
223 xprint(1, "Handling alias (section: $secmap[$sec]) in line $ln ($desc)\n");
225 if ($input[$ln] =~ m!\s*alias (-[haocC] +)*([^=]*)=["'](.*)["']!) {
226 $alias=$2; $value=&escape_string($3);
227 $desc =~ s!\@a\@!$value!;
228 push(@{ $data{"aliases-$secmap[$sec]"} }, "\\command\{$alias\}\{$desc\}");
231 warn("Parsing alias line $ln ($input[$ln]) failed. IGNORING.\n");
235 sub handle_other($$) {
236 my $sec = shift ; my $desc = shift;
237 $desc =~ m!([^\s]+)\s+(.*)!;
238 xprint(1, "Handling 'other' tag in line $ln ($1 -> $2))\n");
243 sub handle_keybinding($$) {
244 my $sec = shift ; my $desc = shift;
246 if ($sec eq '') { $sec=0; }
247 xprint(1, "Handling keybinding (section: $secmap[$sec]) in line $ln ($desc)\n");
249 if ($input[$ln] =~ m!^.*bindkey\s+[^'"]*(.*)['"]\s+([\w-]*)\#?.*!) {
250 $value=&escape_string($2);
254 $kbd=&demystify_keys($kbd);
255 $desc =~ s!\@k\@!$value!;
256 #xprint(0, "!-> DEBUG: kbd: $kbd - value: $value - desc: $desc\n");
257 push(@{ $data{"keybindings-$secmap[$sec]"} }, "\\command\{$kbd\}\{$desc\}");
260 warn("Parsing keybinding line $ln ($input[$ln]) failed. IGNORING.\n");
264 sub handle_variable($$) {
265 my $sec = shift ; my $desc = shift;
267 if ($sec eq '') { $sec=0; }
268 xprint(1, "Handling variable (section: $secmap[$sec]) in line $ln ($desc)\n");
270 if ($input[$ln] =~ m!^.*\s+(\w*)=(.*)$!) {
271 $var = $1 ; $value = $2;
272 $value =~ s!^\$\{\w*:-(.*)\}!$1!;
275 $value = &escape_string($value);
276 push(@{ $data{"variables-$secmap[$sec]"} }, "\\command\{$var\}\{\\kbd\{$value" . ($desc ne '' ? "\}\\quad $desc" : "\}") . "\}");
279 warn("Parsing variable line $ln ($input[$ln]) failed. IGNORING.\n");
283 sub handle_manual($$$) {
284 # this is different than the other handle_*() subs.
285 my $code = shift ; my $key = shift ; my $value = shift;
287 xprint(1, "Handling manual entry (code: $code) in line $ln ($key -> $value)\n");
288 $sec = ( (length($code) > 1) ? substr($code, 1) : 0);
289 if (substr($code, 0, 1) eq 'a') {
290 push(@{ $data{"aliases-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
292 elsif (substr($code, 0, 1) eq 'A') {
293 push(@{ $data{"abbrev-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
295 elsif (substr($code, 0, 1) eq 'd') {
296 push(@{ $data{"hasheddirs-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
298 elsif (substr($code, 0, 1) eq 'f') {
299 push(@{ $data{"functions-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
301 elsif (substr($code, 0, 1) eq 'k') {
302 push(@{ $data{"keybindings-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
304 elsif (substr($code, 0, 1) eq 'o') {
305 push(@{ $data{"other-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
307 elsif (substr($code, 0, 1) eq 'v') {
308 push(@{ $data{"variables-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
311 warn("Unknown doc-definition character in manual-line $ln ($1). IGNORING.\n");
318 my $optstring = shift;
321 if ($optstring =~ m!([a-zA-Z0-9_-]+)\s+(.*)!) {
324 if ($opt eq 'split') {
325 if ($val =~ m!([a-zA-Z0-9_-]+)\s+(.*)!) {
328 xprint(2, " splitting values (for $what): " . join(' ', split(/,/, $when)) . "\n");
329 @{ $splits{"$what"} } = split(/,/, $when);
332 warn("Parsing split option failed in line $ln. IGNORING.\n");
336 warn("Unknown option ($opt) in line $ln. IGNORING.\n");
340 warn("Parsing option in line $ln failed. IGNORING.\n");
347 ### {{{ handling stdin
349 $input[0]='index==linenumber :-)';
352 if ($i > $MAX_INPUT) {
353 die "Sorry dude, input lines exeeded maximum ($MAX_INPUT)}\n";
360 if ($input[$ln] =~ m!^\#\@\#\s*(.*)$!) {
364 if ($input[$ln] =~ m!^\s*\#([a-zA-Z])([0-9]*)\#\s*(.*)$!) {
366 &handle_alias($2, $3);
369 &handle_abbrev($2, $3);
372 &handle_hashdir($2, $3);
375 &handle_function($2, $3);
378 &handle_keybinding($2, $3);
381 &handle_other($2, $3);
384 &handle_variable($2, $3);
388 $arg =~ m!^\s*([a-zA-Z][0-9]*)\s+(\S+)\s+(.*)!;
389 &handle_manual($1, $2, $3);
392 warn("Unknown doc-definition character in line $ln ($1). IGNORING.\n");
404 open(IN, "<$refin") or die "could not open $refin: $!\n";
406 while (<IN>) { #{{{ output loop
408 while (m!\@\@INSERT-other-[^@]+\@\@!) {
409 s!\@\@INSERT-other-([^@]+)\@\@!$other{$1}!;
410 xprint(2, "Inserting \@\@INSERT-other-$1\@\@ -> $other{$1}\n");
412 if (m!^\@\@INSERT-([^-]*)-?(.*)\@\@!) {
414 die "malformed insertion tag in line $i ($_). ABORT\n";