4 ### Author: Frank Terbeck <ft@bewatermyfriend.org>
6 ### This file is free software: you can redistribute it and/or modify
7 ### it under the terms of the GNU General Public License as published
8 ### by the Free Software Foundation, either version 3 of the License,
9 ### or (at your option) any later version.
11 ### This file is distributed in the hope that it will be useful,
12 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ### GNU General Public License for more details.
16 ### generate grml zsh refcard.
21 ### #A#: abbreviations
25 ### consider these lines in zshrc:
26 ### #a3# execute \kbd{apt-cache policy}
27 ### alias acp='apt-cache policy'
29 ### Now this script will add a new description for 'acp' into
30 ### the replacement list created by the @@INSERT-aliases-debian@@
33 ### @@INSERT-aliases-default@@ == @@INSERT-aliases@@
34 ### @@INSERT-aliases-all@@ will create a sorted list of _all_
35 ### aliases from all subsections.
37 ### @@INSERT-other-foobar@@ is special, just does text replaces
38 ### without any special formatting, useful for:
39 ### \command{umask @@INSERT-other-umask@@}{...
40 ### 'other' does not have -default nor -all.
42 ### you may specify certain subsections like this:
43 ### #a3#, which will put the input in the into the
44 ### @@INSERT-aliases-debian@@ tag.
46 ### See the @secmap array below for section numbers.
47 ### Yes, this could be done with real names instead of numbers.
48 ### But names tend to be rather long. I don't want that.
50 ### This scripts works on quite some global variables, which is *not*
51 ### a good idea most of the time. Thank god it's just a ~500 line script. :)
56 my $refin = "./grml-zsh-refcard.tex.in";
57 if (defined($ARGV[0]) && $ARGV[0] =~ m!^[^+]!) {
64 if (defined($ARGV[0])) {
65 $verbose = length($ARGV[0]);
79 $inc, # global counter for input lines
82 %other, # @@INSERT-other-*@@
83 %splits # if lists get long, we might need to split them. HoA
86 my $splitstring="\\commandlistend\n\\pagebreak\n\\commandlistbegin";
93 if ($verbose < 5) { return; }
94 xprint(5, " --- Data ---\n");
96 foreach $key (sort keys(%other)) {
97 xprint(5, " \@\@INSERT-other-$key\@\@ -> $other{$key}\n");
100 foreach $key (sort keys(%data)) {
101 xprint(5, " \@\@INSERT-$key\@\@ =>\n");
102 foreach $entry (sort @{ $data{$key} }) {
103 xprint(5, "$entry\n");
107 foreach $key (sort keys(%splits)) {
108 xprint(5, " List-Splitting Offset for $key:\n");
109 foreach $entry (@{ $splits{$key} }) {
110 xprint(5, "$entry\n");
113 xprint(5, " --- Dump ---\n");
119 if ($verbose >= $level) {
124 sub escape_string { #{{{
127 $in =~ s!([\\\{\}\*\&~\$_])!\\$1!g;
131 sub demystify_keys { #{{{
132 # what an ugly hack :-)
136 @tok = split(/(\\e[^\^]|\^.)/, $keys);
143 if ($k =~ m!^[^\\\^]!) {
148 $k =~ s!\^[jJmM]!return!g;
158 my ($linenum, $cat, $sec) = @_;
165 if (!defined($data{"$cat-$sec"})) {
166 warn("Unknown insertion tag in line $linenum (\@\@INSERT-$cat-$sec\@\@). IGNORING.\n");
170 xprint(1, "inserting: category($cat) section($sec), line: $linenum\n");
173 foreach $entry (sort @{ $data{"$cat-$sec"} }) {
176 foreach $is (@{ $splits{"$cat-$sec"} } ) {
178 print("$splitstring\n");
187 sub set_option { #{{{
188 my ($optstring) = @_;
192 if ($optstring =~ m!([a-zA-Z0-9_-]+)\s+(.*)!) {
195 if ($opt eq 'split') {
196 if ($val =~ m!([a-zA-Z0-9_-]+)\s+(.*)!) {
199 xprint(2, " splitting values (for $what): " . join(' ', split(/,/, $when)) . "\n");
200 @{ $splits{"$what"} } = split(/,/, $when);
202 warn("Parsing split option failed in line $ln. IGNORING.\n");
205 warn("Unknown option ($opt) in line $ln. IGNORING.\n");
208 warn("Parsing option in line $ln failed. IGNORING.\n");
214 # name: hashdir, abbrev etc.
215 # wfuncref: reference to the function, that does the work
216 # sec: section number
217 # desc: description string
218 my ($name, $wfuncref, $sec, $desc) = @_;
224 xprint(1, "Handling $name (section: secmap[$sec]) in line $ln ($desc)\n");
227 if (!$wfuncref->($sec, $desc)) {
228 warn("Broken $name in line $ln. IGNORING.\n");
232 sub handle_manual { #{{{
233 # this is different than the other handle_*() subs.
234 my ($code, $key, $value) = @_;
237 xprint(1, "Handling manual entry (code: $code) in line $ln ($key -> $value)\n");
239 $sec = ( (length($code) > 1) ? substr($code, 1) : 0);
240 if (substr($code, 0, 1) eq 'a') {
241 push(@{ $data{"aliases-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
242 } elsif (substr($code, 0, 1) eq 'A') {
243 push(@{ $data{"abbrev-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
244 } elsif (substr($code, 0, 1) eq 'd') {
245 push(@{ $data{"hasheddirs-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
246 } elsif (substr($code, 0, 1) eq 'f') {
247 push(@{ $data{"functions-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
248 } elsif (substr($code, 0, 1) eq 'k') {
249 push(@{ $data{"keybindings-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
250 } elsif (substr($code, 0, 1) eq 'o') {
251 push(@{ $data{"other-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
252 } elsif (substr($code, 0, 1) eq 'v') {
253 push(@{ $data{"variables-$secmap[$sec]"} }, "\\command\{$key\}\{$value\}");
255 warn("Unknown doc-definition character in manual-line $ln ($1). IGNORING.\n");
261 sub handle_other { #{{{
262 # a very simple handler
263 my ($sec, $desc) = @_;
265 $desc =~ m!([^\s]+)\s+(.*)!;
266 xprint(1, "Handling 'other' tag in line $ln ($1 -> $2))\n");
272 my ($sec, $desc) = @_;
273 my ($abbrev, $value, $doc);
275 xprint(1, "$ln, $i\n");
276 while ($ln <= $i) { # the global $i
277 if ($input[$ln] =~ m!^\s*#A[0-9]*#!) {
278 xprint(1, "Ending abbreviation handling in line $ln.\n");
284 if ($input[$ln] =~ s/\s+\#d\s*([^#]*)$//) {
288 if ($input[$ln] =~ m!^\s*['"]([^"']*)['"]\s+\$?['"]([^"']*)['"]!) {
289 $abbrev = $1; $value = &escape_string($2);
290 xprint(2, "ab: $abbrev -> $value ($doc);\n");
291 push(@{ $data{"abbrev-$secmap[$sec]"} }, "\\command\{$abbrev\}\{\\kbd\{$value" . ($doc ne '' ? "\}\\quad $doc" : "\}") . "\}");
293 xprint(0, "Line didn't look like abbreviation in abbreviations section: " . $input[$ln] . "\n");
301 my ($sec, $desc) = @_;
304 if ($input[$ln] =~ m!\s*alias (-[haocC] +)*([^=]*)=["'](.*)["']!) {
305 $alias=$2; $value=&escape_string($3);
306 $desc =~ s!\@a\@!$value!;
307 push(@{ $data{"aliases-$secmap[$sec]"} }, "\\command\{$alias\}\{$desc\}");
315 sub __function { #{{{
316 my ($sec, $desc) = @_;
318 if ($input[$ln] =~ m!\s*(function)?\s*([^(\s]*)!) {
319 xprint(2, " - $2()\n");
320 push(@{ $data{"functions-$secmap[$sec]"} }, "\\command\{$2()\}\{$desc\}");
329 my ($sec, $desc) = @_;
334 if ($input[$ln] =~ m/^\s*\#d[0-9]*\#/) {
335 xprint(1, "Ending hashed dir handling in line $ln.\n");
340 if ($input[$ln] =~ m!\s*hash\s+-d\s+([^=]+)=(.*)!) {
341 $dir=$1; $value=&escape_string($2);
342 push(@{ $data{"hasheddirs-$secmap[$sec]"} }, "\\command\{$dir\}\{$value\}");
352 sub __keybinding { #{{{
353 my ($sec, $desc) = @_;
356 if ($input[$ln] =~ m!^.*bindkey\s+[^'"]*(.*)['"]\s+([\w-]*)\#?.*!) {
357 ($kbd, $value) = ($1, $2);
358 $value=&escape_string($value);
361 $kbd=&demystify_keys($kbd);
362 $desc =~ s!\@k\@!$value!;
364 #xprint(0, "!-> DEBUG: kbd: $kbd - value: $value - desc: $desc\n");
366 push(@{ $data{"keybindings-$secmap[$sec]"} }, "\\command\{$kbd\}\{$desc\}");
367 } elsif ($input[$ln] =~ m!^.*bind2maps\s+([^-])+--\s+(.*)!) {
368 my ($maps, $rest) = ($1, $2);
369 my (@a) = split /\s+/, $rest, 2;
370 if ($a[0] ne q{-s}) {
371 push(@{ $data{"keybindings-$secmap[$sec]"} },
372 "\\command\{$a[0]\}\{$desc\}");
377 if ($rest =~ m!^'([^']+)'\s+!) {
379 } elsif ($rest =~ m!^"([^"]+)"\s+!) {
384 $seq = demystify_keys($seq);
385 push(@{ $data{"keybindings-$secmap[$sec]"} }, "\\command\{$seq\}\{$desc\}");
393 sub __variable { #{{{
394 my ($sec, $desc) = @_;
397 if ($input[$ln] =~ m/\s*(\S+)=(.+)$/) {
398 $var = $1 ; $value = $2;
399 $value =~ s!^\$\{\w*:-(.*)\}!$1!;
402 $value = &escape_string($value);
403 push(@{ $data{"variables-$secmap[$sec]"} }, "\\command\{$var\}\{\\kbd\{$value" . ($desc ne '' ? "\}\\quad $desc" : "\}") . "\}");
416 ### read our input from stdin {{{
418 $input[0]='index==linenumber :-)';
421 if ($i > $MAX_INPUT) {
422 die "Sorry dude, input lines exeeded maximum ($MAX_INPUT)}\n";
428 # work on the lines in memory (jumping back and forth is simple this way)
431 if ($input[$ln] =~ m/^\#\@\#\s*(.*)$/) {
436 if ($input[$ln] =~ m/^\s*\#([a-zA-Z])([0-9]*)\#\s*(.*)$/) {
438 &handle("alias", \&__alias, $2, $3);
439 } elsif ($1 eq 'A') {
440 &handle("abbreviation", \&__abbrev, $2, $3);
441 } elsif ($1 eq 'd') {
442 &handle("hashed dir", \&__hashdir, $2, $3);
443 } elsif ($1 eq 'f') {
444 &handle("function", \&__function, $2, $3);
445 } elsif ($1 eq 'k') {
446 &handle("keybinding", \&__keybinding, $2, $3);
447 } elsif ($1 eq 'v') {
448 &handle("variable", \&__variable, $2, $3);
449 } elsif ($1 eq 'o') {
450 &handle_other($2, $3);
451 } elsif ($1 eq 'm') {
453 $arg =~ m!^\s*([a-zA-Z][0-9]*)\s+(\S+)\s+(.*)!;
454 &handle_manual($1, $2, $3);
456 warn("Unknown doc-definition character in line $ln ($1). IGNORING.\n");
467 # read the .in file and put in stuff we gathered from stdin earlier
468 open(IN, "<$refin") or die "could not open $refin: $!\n";
474 while (m!\@\@INSERT-other-[^@]+\@\@!) {
475 s!\@\@INSERT-other-([^@]+)\@\@!$other{$1}!;
476 xprint(2, "Inserting \@\@INSERT-other-$1\@\@ -> $other{$1}\n");
479 if (m!^\@\@INSERT-([^-]*)-?(.*)\@\@!) {
481 die "malformed insertion tag in line $i ($_). ABORT\n";