From: Mischa POSLAWSKY Date: Tue, 5 Mar 2024 23:00:08 +0000 (+0100) Subject: index: release v1.18 with only altgr index linked X-Git-Url: http://git.shiar.nl/sheet.git/commitdiff_plain/HEAD?hp=194cffeee825787e5ac61e3919681d19b9109aaf index: release v1.18 with only altgr index linked --- diff --git a/.gitignore b/.gitignore index 5c53b31..8815520 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,16 @@ # downloaded data and generated includes /data +/word/put.js -# derived contents +# derived or compiled contents /sitemap.xml /light.css +/UPDATE +/plan.plp +/word/*.min.js + +# optional cache files +/source/*.html # site owner tag for google webmaster tools /google????????????????.html diff --git a/.htaccess b/.htaccess index 41f82b4..90f32b4 100644 --- a/.htaccess +++ b/.htaccess @@ -1,28 +1,47 @@ -Options -MultiViews +Options -MultiViews -Indexes DirectoryIndex index.plp +DirectorySlash Off +AddCharset utf-8 .txt RewriteEngine on RewriteBase / -# redirect from old vim-only subdomain -RewriteCond %{HTTP_HOST} ^vim?\.shiar\.\w+$ +# redirect from deprecated domain names +RewriteCond %{HTTP_HOST} ^vim?\.shiar\.\w+$ [OR] +RewriteCond %{HTTP_HOST} =sheet.shiar.net RewriteRule ^(vi(?=m$)|.*) http://sheet.shiar.nl/$1 [R=301] # redirect old locations -RewriteRule ^vim$ /vi [R=301] -RewriteRule ^cc$ /countries [R=301] +RewriteRule ^vim$ /vi [R=301] +RewriteRule ^cc$ /countries [R=301] + +# forward to https protocol if requested +RewriteCond %{HTTPS} =off +RewriteCond %{HTTP:Upgrade-Insecure-Requests} =1 +RewriteCond %{HTTP_HOST} =sheet.shiar.nl +RewriteRule (.*) https://%{HTTP_HOST}/$1 [L] # serve vim commands when requesting /digraphs.ex as well -RewriteRule ^(digraphs)\.ex(/.*)?$ $1.vim$2 +RewriteRule ^(digraphs)\.ex(/.*)?$ $1.vim$2 # add .plp if a file exists with .plp appended (topdir only) -RewriteCond %{REQUEST_FILENAME}.plp -f -RewriteRule ^/*([^/]+)(.*) $1.plp$2 +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{DOCUMENT_ROOT}/$1.plp -f +RewriteRule ^/*([^/]+)(.*) $1.plp$2 + +# replace jpeg images by webp alternatives if supported +RewriteCond %{HTTP_ACCEPT} \bimage/webp +RewriteCond %{DOCUMENT_ROOT}/$1.webp -f +RewriteRule (.*)\.jpg$ $1.webp -# allow browsers to cache for upto a month +# allow browsers to cache static assets for upto a month - + +Header set Cache-Control "max-age=2592000" + + Header set Cache-Control "max-age=2592000" +Header set Access-Control-Allow-Origin "*" diff --git a/Makefile b/Makefile index a2b2846..df6cbe5 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,7 @@ -all: sitemap.xml light.css data/digraphs.inc.pl data/unicode-cover.inc.pl data/countries.inc.pl data/browser data/termcol-xcolor.inc.pl data/digraphs-xorg.inc.pl -more: all +all: sitemap.xml light.css plan.plp UPDATE data cache -download: data/DerivedAge.txt data/rfc1345.txt data/xorg-compose data/countryInfo.txt data/browser/caniuse data/browser/usage-wm.tsv data/xcolors data/unicode-sampler -.PHONY: download +.PHONY: force # applied to download after 2 hours +download := $(shell [ -z $$(find data/download -mmin -120) ] && (touch data/download && echo force)) # atomically create file by command cmdsave = @echo '$1' $2 \>$@; mispipe '$1 $2' 'ifne sponge $@' @@ -17,13 +16,29 @@ sitemap.xml: tools/mksitemap light.css: tools/stripcss base.css $(call cmdsave,$^) -data/DerivedAge.txt: +plan.plp: TODO + kramdown $< >$@ + +UPDATE: $(download) + $(call cmdsave,git log -1 --date=short --pretty="%ad %s") + +cache: $(patsubst %.inc.pl,data/%.json,$(wildcard charset-*.inc.pl) $(wildcard keyboard/altgr/*.inc.pl) writing-latn.inc.pl) +word: word/put.min.js data/wordlist.en.json data/wordlist.nl.json data/wordlist.ru.json data/wordpairs.json + +word/put.js: $(download) + tools/wget-ifmodified https://github.com/kriszyp/put-selector/raw/master/put.js $@ +word/%.min.js: word/%.js + uglifyjs -m '' $< -o $@ + +data: data/digraphs.json data/unicode-cover.inc.pl data/countries.inc.pl data/browser data/termcol-xcolor.inc.pl data/digraphs-xorg.json data/unicode-sampler word + +data/DerivedAge.txt: $(download) tools/wget-ifmodified http://www.unicode.org/Public/UNIDATA/$(@F) $@ data/unicode-age.inc.pl: tools/mkcharver data/DerivedAge.txt $(call cmdsave,$^) -data/rfc1345.txt: +data/rfc1345.txt: $(download) tools/wget-ifmodified http://www.ietf.org/rfc/$(@F) $@ data/digraphs-rfc.inc.pl: tools/mkdigraphs-rfc data/rfc1345.txt @@ -32,34 +47,56 @@ data/digraphs-rfc.inc.pl: tools/mkdigraphs-rfc data/rfc1345.txt data/digraphs-shiar.inc.pl: tools/mkdigraphs-shiar shiar.inc.txt $(call cmdsave,$^) -data/xorg-compose: - tools/wget-ifmodified http://cgit.freedesktop.org/xorg/lib/libX11/plain/nls/en_US.UTF-8/Compose.pre $@ - -data/digraphs-xorg.inc.pl: tools/mkdigraphs-xorg data/xorg-compose +data/xorg-compose: $(download) + tools/wget-ifmodified http://gitlab.freedesktop.org/xorg/lib/libx11/-/raw/master/nls/en_US.UTF-8/Compose.pre $@ +data/keysymdef.h: $(download) + tools/wget-ifmodified http://gitlab.freedesktop.org/xorg/proto/xorgproto/-/raw/master/include/X11/$(@F) $@ +data/keysymdef.json: tools/mkxkeysymdef data/keysymdef.h + $(call cmdsave,$^) +data/digraphs-xorg.json: tools/mkdigraphs-xorg data/xorg-compose data/keysymdef.json $(call cmdsave,$^) data/digraphs-vim.inc.pl: tools/mkdigraphs-vim $(call cmdsave,$<) -data/digraphs.inc.pl: tools/mkdigraphlist data/digraphs-rfc.inc.pl data/digraphs-vim.inc.pl data/digraphs-shiar.inc.pl data/unicode-char.inc.pl +data/digraphs-plan9.txt: + tools/wget-ifmodified https://9fans.github.io/usr/local/plan9/lib/keyboard $@ +data/digraphs-plan9.inc.pl: tools/mkdigraphs-plan9 data/digraphs-plan9.txt + $(call cmdsave,$^) + +data/digraphs.json: tools/mkdigraphlist data/digraphs-rfc.inc.pl data/digraphs-vim.inc.pl data/digraphs-shiar.inc.pl data/unicode-char.inc.pl $(call cmdsave,$<) data/unicode-char.inc.pl: tools/mkcharinfo data/digraphs-rfc.inc.pl data/digraphs-shiar.inc.pl data/unicode-age.inc.pl unicode-table.inc.pl $(call cmdsave,$<) -data/font/%.inc.pl: tools/mkttfinfo data/font/%.ttf +data/font/%.inc.pl: tools/mkttfinfo data/font/%.ttf #TODO ttc $(call cmdsave,$^) || true -data/unicode-sampler: +data/unicode-sampler: $(download) $(call gitsave,git://git.shiar.nl/unicode-sampler) data/xcolors/themes: data/xcolors -data/xcolors: +data/xcolors: $(download) $(call gitsave,https://github.com/tlatsas/xcolors) data/termcol-xcolor.inc.pl: tools/mktermcol-xcolor data/xcolors/themes $(call cmdsave,$^/*) +data/wordlist.version.txt: force + @[ -e $@ ] || date -Is >$@ + tools/lastword $@ || true + +data/wordlist.%.inc.pl: tools/mkwordlist data/wordlist.version.txt + $(call cmdsave,$< $*) +data/word%.json: data/word%.inc.pl + $(call cmdsave,tools/mkjson $<) +data/%.json: %.inc.pl + $(call cmdsave,tools/mkjson $<) + +data/wordpairs.inc.pl: data/wordlist.version.txt + tools/wordpairs >$@ + .SECONDARY: data/font/%.ttf data/font/%.ttf: find /usr/share/fonts/truetype/ ~/.fonts/ -iname "$(@F)" | head -1 | xargs -i ln -sf {} $@ @@ -74,7 +111,7 @@ data/font/droidserif.ttf: data/font/free%.ttf: find /usr/share/fonts/truetype/freefont/ -iname "$(@F)" | head -1 | xargs -i ln -sf {} $@ data/font/roboto.ttf: - ln -sf /usr/share/fonts/truetype/roboto/Roboto-Regular.ttf $@ + ln -sf /usr/share/fonts/truetype/roboto/unhinted/RobotoTTF/Roboto-Regular.ttf $@ data/font/noto%.ttf: find /usr/share/fonts/truetype/noto/ -iname "Noto$(*F)-Regular.ttf" | head -1 | xargs -i ln -sf {} $@ @@ -93,10 +130,10 @@ data/font/all-other: data/font/unifont.inc.pl data/font/code2000.inc.pl data/fon # $< unifont.ttf $@ # $< --headless unifont_upper.ttf >>$@ -data/unicode-cover.inc.pl: tools/mkfontinfo data/font $(patsubst data/font/%.ttf,data/font/%.inc.pl,$(wildcard data/font/*.ttf)) +data/unicode-cover.inc.pl: tools/mkfontinfo data/font # $(wildcard data/font/*.inc.pl) $(call cmdsave,$<) -data/countryInfo.txt: +data/countryInfo.txt: $(download) tools/wget-ifmodified http://download.geonames.org/export/dump/$(@F) $@ data/countries.inc.pl: tools/mkcountries-geonames data/countryInfo.txt @@ -104,21 +141,22 @@ data/countries.inc.pl: tools/mkcountries-geonames data/countryInfo.txt data/browser: data/browser/support.inc.pl data/browser/usage-wm.inc.pl +data/browser/caniuse/fulldata-json/data-2.0.json: data/browser/caniuse data/browser/caniuse/data.json: data/browser/caniuse -data/browser/caniuse: +data/browser/caniuse: $(download) $(call gitsave,https://github.com/Fyrd/caniuse.git) -data/browser/support.inc.pl: tools/mkcaniuse data/browser/caniuse/data.json +data/browser/support.inc.pl: tools/mkcaniuse data/browser/caniuse/fulldata-json/data-2.0.json $(call cmdsave,$^) -data/browser/usage-wm.tsv: +data/browser/usage-wm.tsv: $(download) tools/wget-ifmodified https://analytics.wikimedia.org/datasets/periodic/reports/metrics/browser/all_sites_by_browser_family_and_major_percent.tsv $@ data/browser/usage-wm.inc.pl: tools/mkusage-wikimedia data/browser/usage-wm.tsv $(call cmdsave,$^) clean: - -rm data/digraphs.inc.pl + -rm data/digraphs.json -rm data/unicode-char.inc.pl -rm data/unicode-age.inc.pl -rm -rf data/font/ @@ -126,8 +164,3 @@ clean: -rm data/browser/support.inc.pl -rm data/browser/usage-wm.inc.pl -.SECONDEXPANSION: - -data/writing-latn.inc.pl: tools/perlinc-static $$(@F) - $(call cmdsave,$^) - diff --git a/Shiar_Sheet/DB.pm b/Shiar_Sheet/DB.pm new file mode 100644 index 0000000..e978d80 --- /dev/null +++ b/Shiar_Sheet/DB.pm @@ -0,0 +1,24 @@ +package Shiar_Sheet::DB; + +use 5.014; +use warnings; +use DBIx::Simple; + +our $VERSION = '1.00'; + +my @dbinfo = ( + 'DBI:Pg:dbname=sheet;host=localhost', 'sheetadmin', 'fairuse', +) or die "database not configured\n"; +our $db; + +sub connect { + return $db if $db and $db->dbh->ping; + $db = DBIx::Simple->new(@dbinfo[0..2], { + RaiseError => 1, + pg_enable_utf8 => 1, + }); + $db->abstract->{array_datatypes}++; + return $db; +} + +1; diff --git a/Shiar_Sheet/FormRow.pm b/Shiar_Sheet/FormRow.pm new file mode 100644 index 0000000..03f1c22 --- /dev/null +++ b/Shiar_Sheet/FormRow.pm @@ -0,0 +1,65 @@ +package Shiar_Sheet::FormRow; + +use 5.014; +use warnings; +use PLP::Functions 'EscapeHTML'; + +our $VERSION = '1.00'; + +sub input { + my ($row, $col, $attr) = @_; + my $val = $row->{$col} // ''; + my $html = ''; + $html .= qq( $_="$attr->{$_}") for sort grep {!/^-/} keys %{$attr // {}}; + + if (my $options = $attr->{-select}) { + $options = $options->(@_) if ref $options eq 'CODE'; + $options->{$val} //= "unknown ($val)"; # preserve current + return ( + sprintf('', + ); + } + elsif ($attr->{type} eq 'textarea') { + return ( + (map { + sprintf('', $col, $_) + } $attr->{-label} // ()), + sprintf('', + $col, $html, EscapeHTML($val) + ), + ); + } + elsif ($attr->{type} eq 'checkbox') { + $html .= ' checked' if $val; + return sprintf( + join('', + '', + ), $col, $html, $attr->{-label} + ); + } + else { + my $multiple = ref $val eq 'ARRAY' || $attr->{-multiple}; + return ( + (map { + sprintf('', $col, $_) + } $attr->{-label} // ()), + $multiple ? '' : (), + (map { + sprintf('', $col, EscapeHTML($_)) + } ref $val eq 'ARRAY' ? @{$val} : ()), + sprintf('', + $col, $multiple ? '' : EscapeHTML($val), $html + ), + $multiple ? '' : (), + ); + } +} + +1; diff --git a/Shiar_Sheet/FormatChar.pm b/Shiar_Sheet/FormatChar.pm index c93a48a..f471497 100644 --- a/Shiar_Sheet/FormatChar.pm +++ b/Shiar_Sheet/FormatChar.pm @@ -8,7 +8,7 @@ use utf8; use Data::Dump 'pp'; use PLP::Functions 'EscapeHTML'; -our $VERSION = '1.08'; +our $VERSION = '1.10'; our $uc = do 'data/unicode-char.inc.pl'; @@ -17,14 +17,25 @@ sub new { bless { anno => ['di', 0], style => 'di' }, $class; } -sub glyph_info { +sub glyph_mkinfo { my ($self, $codepoint) = @_; - return $uc->{chr $codepoint} || eval { + # attempt to get unicode character information + my $info = eval { require Unicode::UCD; - if (my $fullinfo = Unicode::UCD::charinfo($codepoint)) { - return [@$fullinfo{qw/category name - string/}]; - } - } || []; + Unicode::UCD::charinfo($codepoint) + || { category => 'Xn', name => '' }; + } or return; + my $string; + if ($info->{combining}) { + # overlay combining diacritics + $string = chr(9676) . chr($codepoint); + } + return [@$info{qw( category name )}, undef, $string]; +} + +sub glyph_info { + my ($self, $codepoint) = @_; + return $uc->{chr $codepoint} || $self->glyph_mkinfo($codepoint) || []; } sub glyph_html { @@ -34,7 +45,7 @@ sub glyph_html { my ($class, $name, $mnem, $entity, $string) = @$info; my $cell = EscapeHTML($string || $char); - my $title = sprintf 'U+%04X%s', $codepoint, !!$name && " ($name)"; + my $title = sprintf 'U+%04X%s', $codepoint, !!$name && " $name"; $cell = "$cell" if $class and $class =~ /\bZs\b/; $cell = ' ' if $cell eq ''; @@ -61,6 +72,31 @@ sub glyph_cell { return sprintf('%s', $self->glyph_html($char)); } +sub glyph_level_univer { + my ($self, $input) = @_; + if ($input =~ /\p{age=unassigned}/) { + # check include for assignments after unicode 6.0 (perl v5.14) + state $agemap = do 'data/unicode-age.inc.pl'; + my $version = $agemap->{ord $input}; + return $version ? 'l2' : 'l1'; + } + elsif ($input =~ /^\p{in=1.1}*$/) { + return 'l5'; # first release 1993 + } + elsif ($input =~ /^\p{in=3.0}*$/) { + return 'l4'; # 20th century + } + elsif ($input =~ /^\p{in=4.1}*$/) { + return 'l4'; # over 10 years ago + } + elsif ($input =~ /^\p{in=6.0}*$/) { + return 'l3'; # before 2012 + } + else { + return 'l2'; # more recent + } +} + sub cell { my ($self, $input, $html) = @_; my (@class, $title, $cell, $mnem, $entity); @@ -81,33 +117,13 @@ sub cell { $input =~ s/^\\//; # escaped char ($cell, $title, my $class, $mnem, $entity) = $self->glyphs_html($input); - my $codepoint = ord $input; if ($self->{style} eq 'univer') { - if ($input =~ /\p{age=unassigned}/) { - # check include for assignments after unicode 6.0 (perl v5.14) - state $agemap = do 'data/unicode-age.inc.pl'; - my $version = $agemap->{$codepoint}; - push @class, $version ? 'l2' : 'l1'; - } - elsif ($input =~ /^\p{in=1.1}*$/) { - push @class, 'l5'; # first release 1993 - } - elsif ($input =~ /^\p{in=3.0}*$/) { - push @class, 'l4'; # 20th century - } - elsif ($input =~ /^\p{in=4.1}*$/) { - push @class, 'l4'; # over 10 years ago - } - elsif ($input =~ /^\p{in=6.0}*$/) { - push @class, 'l3'; # before 2012 - } - else { - push @class, 'l2'; # more recent - } + push @class, $self->glyph_level_univer($input); next; } + my $codepoint = ord $input; if ($self->{style} eq 'di') { if ($mnem and $mnem =~ /…/) { # incomplete representation, usually partial diff --git a/Shiar_Sheet/ImagePrep.pm b/Shiar_Sheet/ImagePrep.pm new file mode 100644 index 0000000..328cb4f --- /dev/null +++ b/Shiar_Sheet/ImagePrep.pm @@ -0,0 +1,92 @@ +package Shiar_Sheet::ImagePrep; + +use 5.020; +use warnings; +use experimental 'signatures'; + +our $VERSION = '1.03'; + +sub new ($class, $target) { + bless \$target, $class; +} + +sub download ($target, $download) { + # copy changed remote url to local file + unlink $$target if -e $$target; + defined $download or return 1; + require LWP::UserAgent; + my $ua = LWP::UserAgent->new; + $ua->agent('/'); + my $status = $ua->mirror($download, $$target); + $status->is_success + or die "Download from $download failed: ".$status->status_line."\n"; +} + +sub dimensions ($imgpath) { + require IPC::Run; + IPC::Run::run( + [identify => -format => '%w %h', $$imgpath], + '<' => \undef, '>&' => \my $xy + ) or die ["Image dimensions could not be determined.", $$imgpath]; + return split /\s/, $xy, 3; +} + +sub generate ($imgpath, $thumbpath, $opt) { + if (not -e $$imgpath) { + return !-e $thumbpath || unlink $thumbpath; + } + my @cmds = @{$opt->{convert} // []}; + unshift @cmds, -area => $_ for $opt->{crop32} || (); + $imgpath->convert($thumbpath, \@cmds, '300x200') and # low-res cover + $imgpath->convert($thumbpath =~ s/\.jpg$/.webp/r, + [@cmds, -quality => 40], '600x400' # higher dpi tradeoff + ); +} + +sub convert ($imgpath, $thumbpath, $cmds, $xyres = 0) { + #my ($w, $h) = $imgpath->dimensions; + #my $aspect = 3/2; # $xyres + my @cmds = @{$cmds}; + if (my ($cmdarg) = grep { $cmds[$_] eq '-area' } 0 .. $#cmds) { + # replace option by permillage crop + my @dim = map { $_ / 1000 } split /\D/, $cmds[$cmdarg + 1]; + $dim[$_] ||= 1 for 2, 3; # optional end + push @dim, $dim[2 + $_] - $dim[$_] for 0, 1; # add width, height + splice @cmds, $cmdarg, 2, ( + #crop="%[fx:floor(w*$ratio)]x%[fx:floor(h*$ratio)]" + #crop="$crop+%[fx:ceil((w-w*$ratio)/2)]+%[fx:ceil((h-h*$ratio)/2)]" + -set => 'option:distort:viewport' => sprintf( + '%%[fx:%s]x%%[fx:%s]+%%[fx:%s]+%%[fx:%s]', + "w*$dim[4]", "h*$dim[5]", # width x height + #"max(w*$dim[4], h*$dim[5]*$aspect)", # width + #"max(h*$dim[5], w*$dim[4]/$aspect)", # height + "w*$dim[0]", "h*$dim[1]", # x+y offset + ), + -distort => SRT => 0, # noop transform to apply viewport + ); + } + @cmds = ( + 'convert', + $$imgpath, + -delete => '1--1', -background => 'white', + '-strip', -quality => '60%', -interlace => 'plane', + -gravity => defined $cmds ? 'northwest' : 'center', + @cmds, + $xyres ? (-resize => "$xyres^", -extent => $xyres) : (), + $thumbpath + ); + + $imgpath->runcommand(@cmds); +} + +sub runcommand ($, @cmds) { + require IPC::Run; + my $output; + IPC::Run::run(\@cmds, '<' => \undef, '>&' => \$output) or die [ + "Failed to convert source image.", + "@cmds\n" . + ($output || ($? & 127 ? "signal $?" : "error code ".($? >> 8))), + ]; +} + +1; diff --git a/Shiar_Sheet/Keyboard.pm b/Shiar_Sheet/Keyboard.pm index 98c5a40..c7e455b 100644 --- a/Shiar_Sheet/Keyboard.pm +++ b/Shiar_Sheet/Keyboard.pm @@ -6,7 +6,7 @@ use warnings; no warnings 'uninitialized'; # save some useless checks for more legible code use Carp; -our $VERSION = '2.07'; +our $VERSION = '2.10'; my @casedesc = (undef, qw/shift ctrl meta/, 'shift meta'); my @rowdesc = qw(numeric top home bottom); @@ -56,6 +56,7 @@ sub escapeclass { s/\+/_m/g; s/\[/_sbo/g; s/\]/_sbc/g; + s/\\/_b/g; s/^$/_/; return $_; } @@ -110,18 +111,18 @@ sub print_key { if (not defined $flags) { $flags = $key eq '^0' ? 'ni' : 'no'; } - elsif ($flags =~ s/^=//) { # alias - $desc = $self->{sign}->{alias}; - $desc .= $flags eq "\e" ? 'esc' : $flags; - $flags = $self->keyunalias($flags) . ' alias'; + elsif ($flags =~ s/^=(\S+)\s?//) { # alias + my $ref = $1; + $desc = $self->{sign}->{alias} . ($ref eq "\e" ? 'esc' : $ref); + $flags = join ' ', $self->keyunalias($ref), 'alias', $flags; } if (my $txt = $self->{key}->{$mode.$key}) { ($desc, $mnem) = split /\n/, $self->escapedesc($txt); } my $keytxt = $self->print_letter($key, $mode); - $keytxt .= $self->{sign}->{$1} while $flags =~ s/(?:^| )(arg[a-ln-z]?)\b//; # arguments $keytxt .= "$self->{sign}->{motion}" if $flags =~ s/ ?\bargm\b//; # motion argument + $keytxt .= $self->{sign}->{$1} while $flags =~ s/(?:^| )(arg[a-ln-z]?)\b//; # arguments my $keyhint = defined($mnem) && qq{ title="$mnem"}; $keytxt = "$keytxt"; $keytxt .= ' '.$desc if defined $desc; @@ -130,6 +131,8 @@ sub print_key { ' onclick="setmode(%s)"', $1 eq '' ? '' : sprintf(q{'mode%s'}, escapeclass($1)) ); + $flags =~ s/\bx\w+/ext/; + $flags =~ s/\bv\d+/new/; $flags .= ' chr'.ord(substr $key, -1) if $key ne '^0'; print qq{\t\t$keytxt}; @@ -147,11 +150,16 @@ sub print_rows { ); my @modes = sort keys %{ $self->{def} }; - print ''."\n\n"; + printf '
'."\n\n", $self->{tableclass} // 'keys'; +print_row: for (my $row = -1; $row <= $#{ $keyrows{$self->{map}} }; $row++) { my $keyrow = $row < 0 ? [["\e"]] : $keyrows{$self->{map}}->[$row]; +# grep { +# defined $self->{def}->{''}->{$_} or defined $self->{def}->{g}->{$_} +# } map { @{$_} } @{$keyrow} or next; + printf qq{\n}, $row+1; for my $basemode (@modes) { my @moderows = split /\s+/, @@ -160,8 +168,8 @@ sub print_rows { for my $submode (@moderows ? @moderows : '') { my $mode = $basemode . $submode; - my @caserows = $mode =~ s/(\d+)(?:-(\d+))?$// - ? (map {$_ - 1} split //, $row == 0 && $2 || $1) # user override + my @caserows = $mode =~ s/(\d+)(?:-(\d*))?$// + ? (map {$_ - 1} split //, $row == 0 ? $2 // $1 : $1) # user override : @$defrows; # default my $modekeys = $self->{def}{$mode}; @@ -199,44 +207,12 @@ sub print_legend { my ($class, $flags) = @_; say qq{\t\t
}; - printf("\t\t".'
%s'."\n\t\t\t".'
%s'."\n", + printf("\t\t".'
%s'."\n\t\t\t".'
%s
'."\n", $_, map { $self->escapedesc($_) } @{ $self->{flag}->{$_} || ["($_)", '...'] } ) for @$flags; say "\t\t
"; } -sub print_legends { - my $self = shift; - my ($input) = @_; - - say "
\n"; - say '
'; - - say "\t", '
'; - my @groups = sort grep {/^g\d/} keys %{ $self->{flag} }; - $self->print_legend('legend-types', \@groups); - say "\t
\n"; - - say "\t", '
'; - my @attr = sort grep {!/^g\d/} keys %{ $self->{flag} }; - $self->print_legend('legend-options', \@attr); - say ''; - - say "\t\t", '
    '; - - say "\t\t
  • keyboard map is ", - ($input->{map} ? 'set to ' : ''), "$self->{map}"; - say "\t\t
  • keys are ", - "", ($self->{showkeys} ? 'always shown' : 'hidden if unassigned'), "", - (!defined $self->{showkeys} && ' by default'); - say "\t\t
  • default style is ", - (defined $input->{style} && 'set to '), "$self->{style}"; - - say "\t\t
"; - say "\t
\n"; - say "
\n"; -} - 1; =head1 NAME @@ -267,7 +243,7 @@ Shiar_Sheet::Keyboard - Output HTML for key sheets =head1 DESCRIPTION -Used by http://sheet.shiar.nl to display keyboard sheets. +Used by https://sheet.shiar.nl to display keyboard sheets. Assumes specific stylesheets and javascript from this site, so probably not of much use elsewhere. diff --git a/Shiar_Sheet/KeyboardChars.pm b/Shiar_Sheet/KeyboardChars.pm new file mode 100644 index 0000000..d0e84c8 --- /dev/null +++ b/Shiar_Sheet/KeyboardChars.pm @@ -0,0 +1,82 @@ +package Shiar_Sheet::KeyboardChars; + +use 5.020; +use warnings; +use utf8; +use experimental 'signatures'; +use parent 'Exporter'; +use Unicode::Normalize qw( NFKD ); +use Text::Unidecode (); +use Shiar_Sheet::FormatChar; + +our $VERSION = '1.04'; +our @EXPORT = qw( kbchars kbmodes ); + +my $uc = Shiar_Sheet::FormatChar->new; + +our %unaccent = qw( + ⍺ a ⍵ w ∊ E ⍷ E ⍴ r ⍳ i ⍸ i ○ O ⍥ O ⌿ / ⍟ (*) ⊕ (+) + Ʊ U ǝ e Ǝ E ʌ vA Ʌ VA ɥ h ʘ O ɰ mw ɯ mw Ɯ MW ə @ae Ə @AE + ɸ PF ʎ yl ɔ co Ɔ CO ɛ 3E ƣ q Ƣ Q ∀ A ∃ E ∪ u ∩ n ≠ != + ≈ =~ ∅ /0 ∘ o ⋅ . ∫ s ≝ =d ″ " ≤ < ≥ > √ rV ∛ 3V ∜ 4V + Α A Β B Γ G Δ D Ε E Ζ Z Η H Θ CQ Ι I Κ K Λ L Μ M + Ν N Ξ X Ο O Π P Ρ R Σ S Τ T Υ YU Φ F Χ CX Ψ Y Ω W + α a β b γ g δ d ε e ζ z η h θ cq ι i κ k λ l μ m + ν n ξ x ο o π p ρ r σ s τ t υ yu φ f χ cx ψ y ω w + ς sc ϑ cq µ mu +); + +sub unidecode { + return $unaccent{$_[0]} // Text::Unidecode::unidecode($_[0]); +} + +sub kbchars ($rows) { + return kbmodes({'' => $rows}); +} + +sub kbmodes ($modes) { + my %g; # present group classes + my %info = ( + tableclass => 'keys big', + rows => [1, 0], + ); + for my $lead (keys %{$modes}) { + if ($lead ne '') { + $info{def}->{''}->{$lead} = "g1 mode$lead"; + $g{g1} = 1; + $info{mode}->{$lead} //= "mode $lead"; + $info{def}->{$lead}{$lead} = 'g1 mode'; # back + } + while (my ($k, $v) = each %{ $modes->{$lead} }) { + my ($glyph, $title) = $uc->glyph_html($v); + $info{key}{$lead.$k} = join "\n", $glyph, $title; + my $c = $k =~ s/\A[+^](?=.)//r; # trim modifier indicator + + my $class = ( + !defined $v || $c eq $v ? 'no' # identical + : $v =~ /\A\p{Mn}+\z/ ? 'g9' # combining accent + : NFKD($v) =~ /\A\Q$c\E\p{Mn}*\z/ ? 'g2' # decomposed equivalent + : unidecode($v) =~ /\Q$c\E+/i ? 'g4' # transliterated + : $v =~ /\A[\p{Sk}\p{Lm}]+\z/ ? 'g8' # modifier symbol + : $v =~ /\A[\pM\pP]+\z/ ? 'g7' # mark + : $v =~ /^\p{Latin}/ ? 'g5' # latin script + : 'g6' + ); + $g{$class} = 1 unless $class eq 'no'; + $info{def}{$lead}{$k} //= $class; + } + } + $info{flag} = {%{{ + g1 => ['mode' => "switch to an alternate set of keys"], + g2 => ['accented', "decomposes to the original letter with a combining accent"], + g4 => ['similar', "transliterates (mostly) into the unmodified letter"], + g5 => ['latin', "a different (accented) latin letter"], + g6 => ['symbol', "other character not directly deducible from key"], + g7 => ['punctuation', "(punctuation) mark"], + g8 => ['mark', "modifier letter or mark (spacing diacritic)"], + g9 => ['combining', "diacritical mark to be combined with a following character"], + }}{keys %g}}; + return \%info; +} + +1; diff --git a/TODO b/TODO index 4f44428..43eacb3 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,8 @@ +# ToDo + - style for .undo (maybe just some css3-only shadow) -- fix mode switching in konq (used to work) - only when s present?! use browser sniffing to force ?ascii=0 :( +- fix mode switching in konq (used to work) + only when \s present?! use browser sniffing to force ?ascii=0 :( - safari loading bug? - multiple stylesheets selectable - ghosting option documented and default @@ -18,6 +20,77 @@ - footer options clickable to change (javascript) - change options dynamically if possible (at least ?style) - footer style option to top position/button? -- top-left header (logo to root)? +- top-left header (logo to root)? conflicts with Esc key positioning - /browser history +- word + - interactive quiz + - image multiple choice from translation + - given image (options or free) + - memory (find groups) + - match pairs + - distinctive male/female plumage + - young age (actors, animals) + - marriages + - plant tree/leaf/fruit/flower + - duplicates + - mirrored duplets + - remember order (progressive amount) + - 20 questions + - captcha quiz (confirm several options for question) + - alternate aspect ratios + - subcategories + - food + - sumac + - animal species + - photoshop cover image + - dog breeds + - cat kinds + - ducks + - birbs + - mushrooms + - spiders + - distinct eyes (quiz linked animals) + - match collective nouns + - mythological + - hybrid creatures + - greek deities + - roman + - media + - tv series + - known characters + - sesame street muppets + - international variants linked to countries + - video games + - screenshots + - characters + - silhouette + - maps + - famous people + - historic hotornot + - movie actors +characters + - country leaders (↓) + - nobel price winners + - clothing + - traditional (+regions) + - dress code + - fashion + - costumes + - cosplay +characters + - jewelry + - construction materials + - technical + - connectors (plug+port) + - removable media + - computer processors (blur identifiers for quiz) + - font families + - cocktails + - moscow mule + - car brands + - countries + - flags + - capital buildings + - traditional dress + - representative cuisine + - national animal/mascot + - api diff --git a/apl.inc.pl b/apl.inc.pl index 3559372..3683d54 100644 --- a/apl.inc.pl +++ b/apl.inc.pl @@ -1,5 +1,5 @@ use utf8; -( # dyadic, monadic +[ # dyadic, monadic # arithmetic ["+\n-", "add\nSum of A and B", "conjugate\nNo change to B"], @@ -122,4 +122,4 @@ undef, ["⍤\nJ", "rank\nApply function successively to the sub-arrays in B specified by k"], ["⍥\nO", "coax"], -); +]; diff --git a/apl.plp b/apl.plp index 9ca9970..302a55d 100644 --- a/apl.plp +++ b/apl.plp @@ -27,9 +27,7 @@ EOT use Shiar_Sheet::FormatChar; my $glyphs = Shiar_Sheet::FormatChar->new; - -my @ops = do 'apl.inc.pl'; -@ops > 1 or die "cannot open operator include: $@\n"; +my $ops = Data('apl'); :>

APL Symbols

@@ -49,7 +47,7 @@ my @ops = do 'apl.inc.pl';
<: -for my $op (@ops) { +for my $op (@{$ops}) { $op or do { say ''; next; @@ -70,9 +68,9 @@ for my $op (@ops) { [defined $entity ? 'l4' : $ascii ? 'l5' : 'l1', $entity // "#$codepoint"], ); printf( - defined $_ ? '%s' : ''; } diff --git a/base.css b/base.css index f20f167..e4ed58d 100644 --- a/base.css +++ b/base.css @@ -33,6 +33,8 @@ caption aside { margin-left: 1ex; font-weight: normal; display: inline; + font-size: 91%; /* 100% */ + margin-top: .3ex; /* align with 110% baseline */ } hr { @@ -99,8 +101,10 @@ ul { } pre { - display: inline-block; text-align: left; + margin: 2ex auto; + white-space: pre-wrap; + overflow-wrap: break-word; } body > pre { width: 78ch; @@ -109,27 +113,56 @@ body > pre { padding: 0 1em; border-width: 0 1px; border-style: solid; + white-space: pre; + font-size: 1.9vmin; /* cover full width at most */ +} +code { + white-space: nowrap; } +h1 small, h2 small { position: absolute; /* side note; do not influence alignment */ margin-left: 1em; + font-weight: normal; + font-size: 50%; /* 1rem */ + padding-top: 1.75ex; /* align baseline with container */ +} +h2 small { + font-size: 90.9%; + padding-top: .17ex; } -dl > dt { - float: left; - width: 50%; +.section dl { + display: grid; + grid: auto-flow / 1fr 1fr; + clear: both; +} +.section dl > dt { + grid-column: 1; text-align: right; } +dt code { + white-space: normal; +} dl > dd { + grid-column: 2; text-align: left; padding-left: 1em; - overflow: hidden; + margin: 0 0 .5ex; +} +@media (max-width: 42em) { + .section dl { + grid: auto-flow / minmax(8em, 1fr) minmax(20em, 1fr); + } + dl > dd { + margin-bottom: 1ex; /* distinguish rows more as dts can wrap */ + } } /* "keyboard" (list of keys) */ -#rows {margin-top: -5ex} /* top (esc) row fits besides header */ +.row0 {margin-top: -5ex} /* top (esc) row fits besides header */ .row2 {margin-left: 7em} /* row offsets relative to ~6em key width */ .row3 {margin-left: 8em} .row4 {margin-left: 10em} /* should actually align to next key on row1 */ @@ -152,20 +185,18 @@ h3 {display: none} /* semantic details (non-css/js) */ table.keys { display: block; - width: 82.5em; /* 12 * td(2px + 1px + 6.2em + 1px + 2px) + 8em */ -// padding-right: 72px; border-spacing: 0; border-collapse: collapse; -} -table.keys > * { - margin-right: -72px; + white-space: nowrap; + text-align: left; } /* individual keys */ dl.legend dt, .keys td { - float: left; + display: inline-block; + white-space: normal; width: 6.2em; line-height: 2.25ex; /* a little terser (seems to be gecko's default anyway) */ height: 4.5ex; /* 2 lines */ @@ -215,6 +246,49 @@ dl.legend dt, font-weight: normal; /* nice and subtle */ } +/* enlarged keys */ + +.keys.big td { + width: 1em; + min-width: auto; + height: 2.25ex; + font-size: 200%; + font-size: calc(7vmin - 4px); /* fit 12 keys to page */ + overflow: visible; + position: relative; + padding: 0; + margin: 0 .2vw -1px; +} + +/* override row alignments */ +.keys.big tbody { + font-size: calc(1.4vmin); /* enlarged td conversion */ +} +.keys.big .row2 {margin-left: 7em} +.keys.big .row3 {margin-left: 8em} +.keys.big .row4 {margin-left: 10em} +.keys.big .row0 { + display: none; /* headerless */ +} + +.keys.big td b { + position: absolute; /* overlay */ + z-index: 1; + top: -1.2ex; /* halfway over shift */ + left: 0; + right: 0; + font-size: 50%; + opacity: .5; + color: #FFF; + line-height: 2.25ex; +} +.keys.big.cmp td b, +.keys.big .ctrl td b, +.keys.big .meta td b, +.keys.big .shift td b { + display: none; +} + /* tables */ table { @@ -243,6 +317,12 @@ td.joinl { border-left: none; } +thead { + position: sticky; + top: 0; + background: #DDD8; +} + /* character table */ .glyphs thead th, .glyphs td { @@ -276,6 +356,10 @@ thead td { .glyphs thead td { width: auto; /* no glyph cells in header */ } +.glyphs caption { + margin-left: 2.2em; /* 1ex + offset head column (1.6em + 0.4em) / 110% */ + /* adjusted insignificant -.2em to fit wide contents on /charset/mac */ +} th { padding: 0 0.2em; } @@ -436,10 +520,10 @@ table.dimap { .u-invalid {background: #BBB} /* invalid, impossible */ /* foreground representation */ -#digraphs .u-l3 {color: #080} /* partial */ -#digraphs .u-l3.ex {color: #4C0} /* experimental */ -#digraphs .u-l2 {color: #A44; color: rgba(128, 0, 0, .6)} /* unofficial proposal */ -#digraphs .u-l1 {color: #D00; color: rgba(255, 0, 0, .8)} /* minimal or invalid */ +#digraphs .u-l4 {color: #080} /* partial */ +#digraphs .u-l5 {color: #4C0} /* experimental */ +#digraphs .u-l2 {color: #A44; color: rgba(128, 0, 0, .6)} /* unofficial */ +#digraphs .u-l1 {color: #D00; color: rgba(255, 0, 0, .8)} /* missing */ /* support percentage (browser cells) */ .p0 {opacity: .6} @@ -464,10 +548,10 @@ table.dimap { /* code syntax */ .sy-comment { color: #888 } .sy-constant { color: #008 } -.sy-type, .sy-identifier { color: #804 } .sy-statement { } .sy-preProc { } +.sy-type, .sy-special { color: #408 } .sy-error { font-weight: bold; background-color: #F00; color: #FFF } .sy-todo { background-color: #FF0 } @@ -511,8 +595,8 @@ table.dimap { .l3:hover {background: #FF8} .l4:hover {background: #CF8} .l5:hover {background: #8F8} -.u-l3:hover {outline: 1px solid #080} -.u-l3.ex:hover {outline: 1px solid #8F0} +.u-l4:hover {outline: 1px solid #080} +.u-l5:hover {outline: 1px solid #8F0} .u-l2:hover {outline: 1px solid #800} .u-l1:hover {outline: 1px solid #F00} @@ -569,12 +653,13 @@ dl.legend dt.more:hover, .keys td.more:hover b { text-shadow: #F20 0 0 0.5em, #FC0 0 0 0.2em; } -dl.legend dt.ext, -.keys td.ext { - border-style: dashed; -} dl.legend dt.new, .keys td.new { + border-style: dashed; +} +.ext, +dl.legend dt.ext, +.keys td.ext { opacity: .6; } @@ -650,6 +735,128 @@ ul.legend-set li { padding: 0 0.2em; } +/* images */ + +figure { + margin: 0; + position: relative; +} +figure img { + vertical-align: bottom; + width: 100%; +} + +@media (min-width: 60em) { + figcaption { + padding: 0 1em; + color: #000; + background: rgba(255, 255, 255, .66); + position: absolute; + right: 0; + bottom: 0; + max-width: 100%; + box-sizing: border-box; + } + .gallery li.parent:hover > figure > figcaption, + .gallery figure:hover > figcaption { + /* highlight title of current and parents */ + font-size: 175%; + right: 50%; + bottom: 50%; + transform: translate(50%, 50%); + margin-left: -60%; /* keep width */ + } +} + +/* image gallery */ + +.gallery { + display: grid; + grid: auto-flow dense / repeat(auto-fit, minmax(200px, 1fr)); + grid-gap: 1px; +} +.gallery li, .gallery ul { + display: contents; +} +.gallery figure { + overflow: hidden; + box-sizing: border-box; + hyphens: auto; + max-width: 900px; +} +.gallery figcaption > small { + display: inline-block; +} + +@media (min-width: 403px) and (min-height: 266px) { + /* able to fit 2 cells of 200x133 */ + .gallery li.large > figure { + grid-row: span 2; + grid-column: span 2; + } +} +@media (min-width: 603px) and (min-height: 400px) { + /* fit 3 cells of 200x133 */ + .gallery > li:first-child > figure, + .gallery li.huge > figure { + grid-row: span 3; + grid-column: span 3; + } +} + +.gallery figure, .gallery figcaption { + transition: all .5s ease-in; +} +.gallery figure:hover ~ ul figcaption { + /* mark all children */ + color: #FFF; + background: rgba(0, 0, 0, .5); +} + +.gallery figure[data-sup]:after { + position: absolute; + right: 0; + content: attr(data-sup); + color: #FFF; + background: #0006; + border-radius: 1em; + padding: .1ex .4em; + margin: .4em; +} +.gallery .expand > figure[data-sup]:after { + content: '+' attr(data-sup); + background: #0008; + font-size: 150%; + border: 2px solid #FFF8; +} + +/* specialised galleries */ + +body#word { + margin: 8px 1px; +} + +table.gallery { + grid-auto-flow: row; + grid-template-columns: repeat(auto-fit, minmax(2em, max-content)); /* 1fr */ +} +table.gallery tbody, +table.gallery tr { + display: contents; +} +table.gallery tr > :first-child { + grid-column: 1; + -grid-row: span 6; + margin: auto; /* vertical-align: middle */ +} +table.gallery tr > :nth-child(2) { + grid-column: 2; /* in case 1st is missing */ +} +table.gallery td { + border: 0; /* does not collapse */ + outline: 1px solid #888; /* over grid-gap */ +} + /* page-specific */ #browser td > a { @@ -713,6 +920,69 @@ nav > .section { margin-top: 1em; } +.units tbody tr:hover:not(.race) { + background: #EEE; +} +.unit-gas { + color: #040; +} +.unit-min, .unit-min a:not(:hover) { + color: #004; +} +.unit-supply { + color: #080; +} +.unit-o {color: #C08} /* organic */ +.unit-u {color: #44C} /* mechanic */ +.unit-p {color: #0A8} /* psionic */ +.unit-composed { + color: #C88; +} +.unit-air { + color: #08C; +} +.unit-x {color: #888} +.unit-s {color: #890} +.unit-m {color: #C70} +.unit-l {color: #D22} +.unit-h {color: #804} +.magic-opt:before, +.magic-opt:after { + color: #000; +} +.hurtrel, .units .hurtrel { + color: #778; +} +tbody .unit-shield { + color: #64A; +} +.unit-pdd { + color: #A8C; +} +.unit-splash { + color: #4A0; +} +.hurt-a { + color: #036; +} +.hurt-g { + color: #063; +} +.unit-massive { + color: #D88; +} +.unit-detect::before { + color: #0A8; +} +.unit-jump { + color: #8A4; +} +body .magic-perma { + text-decoration-color: #8C0; + -moz-text-decoration-color: #8C0; + -webkit-text-decoration-color: #8C0; +} + /* printing hints */ @page { @@ -726,10 +996,19 @@ nav > .section { /* terse optimisation */ +@media (min-height: 112ex) and (min-width: 90em) { + .keys td { + padding: 1ex 0 1ex .1em; + width: 7em; + } +} + @media (max-width: 79em) { .keys td { position: relative; /* hides overflow */ width: 4.5em; + min-width: 6.5vw; + min-width: calc(7.7vw - 8px); } .keys td b, .keys .meta td b, @@ -743,13 +1022,26 @@ nav > .section { color: #FFF; } - table.keys { - width: 62.1em; /* 82.5em - 12 * Δtd(6.2em - 4.5em) */ - } .row2 {margin-left: 5.3em} /* 7em / Δtd(6em : 4.5em) */ .row3 {margin-left: 6em} /* 8em / Δtd */ .row4 {margin-left: 7.5em} /* 10em / Δtd */ + /* letter scripts columns to rows */ + .legend .glyphs:first-child td { + display: table-row; + vertical-align: baseline; + } + .legend .glyphs td > table { + width: auto; + display: inline; + margin-left: 1ex; + } + .legend .glyphs:first-child td td { + margin: 2px; + display: inline-block; + width: auto; + } + @media (max-width: 61em) { .keys td { width: 3em; @@ -763,13 +1055,34 @@ nav > .section { line-height: 4ex; } - table.keys { - width: 37em; /* (12 * td(3em + 6px) + 8em) * 80% */ - } .row2 {margin-left: 3.5em} /* 7em / Δtd(6em : 3em) */ .row3 {margin-left: 4em} /* 8em / Δtd */ .row4 {margin-left: 5em} /* 10em / Δtd */ } + + @media (max-width: 42em) { + /* flatten right legend column on mobile */ + .help > * { + display: table-row; + width: auto; + } + ul.legend-set { + clear: left; + } + .right dl.legend { + margin-right: 0; + margin-left: 6.4em; + } + .right dl.legend dt { + margin-right: 0; + margin-left: -6.4em; + float: left; + clear: left; + } + .right dl.legend dd { + float: left; + } + } } /* @@ -779,8 +1092,6 @@ nav > .section { margin-top: 1ex; transform: rotate(90deg); transform-origin: top left; - width: 68em; - height: 37em; margin-left: 40em; margin-bottom: 30em; font-size: 80%; diff --git a/base.plp b/base.plp index f1ed06c..a68a71f 100644 --- a/base.plp +++ b/base.plp @@ -2,7 +2,7 @@ Html({ title => 'number bases', - version => '1.1', + version => '1.2', description => [ "Cheat sheets summarising various software programs and standards.", ], @@ -15,20 +15,53 @@ Html({ my @cols = (2, 6, 8, 9, 10, 12, 16, 18, 20); my @morecols = (2 .. 6, 8, 9, 10, 12, 16, 18, 20, 24, 32, 36, 64); my @char = (0..9, 'A'..'Z', 'a'..'z'); +my %RADIXNAME = ( + 2 => 'binary', + 3 => 'ternary', + #4 => 'quaternary', + #5 => 'quinary', + 6 => 'senary', + 8 => 'octal', + #9 => 'nonary', + 10 => 'decimal', + 12 => 'dozenal', # duodecimal + 16 => 'hexadecimal', + 20 => 'vigesimal', + #36 => 'double-senary', + 60 => 'sexagesimal', + #64 => 'double-octal', +); :>

Number bases

Radix economy

-
', - map { !!$_->[1] && qq( title="$_->[1]"), $_->[0] } - [map { EscapeHTML($_) } split /\n/, $_, 2] + '%s', + map { defined ? (!!$_->[1] && qq( title="$_->[1]"), $_->[0]) : (' class=Xi', '') } + $_ && [map { EscapeHTML($_) } split /\n/, $_, 2] ) for $monad, $dyad; say '
+
<: +sub showcolhead { + print ''; + my @spans; + $spans[ $_ > 10 ]++ for @_; + print "" for @spans; + print ''; +} + sub radix_economy { my ($val, $radix) = @_; return $radix * int(log($val) / log($radix) + 1); } use List::Util 'sum'; -print '
'; + for (@_) { + print '', $_ < 36 ? $char[$_] : $char[35].'+'.$char[$_ - 35]; + print " ($_)" for join(', ', + $RADIXNAME{$_} // (), + $_ >= 10 ? "base$_" : (), + ) || (); + } + say '
'; -print '', $_ for @morecols; + +showcolhead(@morecols); + for my $max (100, 255, 1024) { print '
⍳', $max; for my $radix (@morecols) { @@ -39,11 +72,8 @@ for my $max (100, 255, 1024) { :>

Reciprocal fractions (n⁻¹)

- +
<: -print '' if $n % 8 == 1; print ''; print '
'; -print '', $_ for @cols; - use Math::BigFloat; my $count = 40; @@ -80,7 +110,10 @@ ADD_DIGITS: printf '%s', $class && qq( class="$class"), $out; } +showcolhead(@cols); + for my $n (2 .. $count) { + print '
', $n; for my $radix (@cols) { @@ -88,6 +121,7 @@ for my $n (2 .. $count) { Math::BigFloat->accuracy($accuracy); showfrac(scalar Math::BigFloat->new(1)->bdiv($n, $accuracy+1), $radix); } + say ''; } :>
@@ -95,7 +129,7 @@ for my $n (2 .. $count) {

Duplication (2ⁿ)

- +
<: sub showint { my ($int, $radix) = @_; @@ -109,16 +143,19 @@ sub showint { } @cols = grep { not $_ ~~ [2,8,16] } @cols, 36; -print ''; + next; + } print ''; print '"; for my $browser (@browsers) { for my $span (@{ $versions{$browser} }) { my $lastver = first { - !defined $caniuse->{agents}->{$browser}->{verrelease}->{$_} # stable + $caniuse->{agents}->{$browser}->{version_list}->{$_}->{release_date} # stable } reverse @{$span}; printf('
'; -print '', $_ for @cols; +showcolhead(@cols); -for my $n (3 .. 16, 18, 20, 24, 30, 32, 36, 40, 48, 50, 60, 64) { +for my $n (0, 3 .. 16, 0, 18, 20, 24, 30, 32, 36, 40, 48, 50, 60, 64) { + if (!$n) { + print '
', $n; for my $radix (@cols) { print '', showint(2 ** $n, $radix); } - print '', { + say '', { 4 => 'nibble', 8 => 'octet', 16 => '2o', diff --git a/browser.plp b/browser.plp index 1c5bb85..6d75d4a 100644 --- a/browser.plp +++ b/browser.plp @@ -4,7 +4,7 @@ no if $] >= 5.018, warnings => 'experimental::smartmatch'; Html({ title => 'browser compatibility cheat sheet', - version => '1.5', + version => '1.6', description => [ "Compatibility table of new web features (HTML5, CSS3, SVG, Javascript)", "comparing support and usage share for all popular browser versions.", @@ -20,14 +20,7 @@ Html({ say "

Browser compatibility

\n"; -my $caniuse = do 'data/browser/support.inc.pl' or die $@ || $!; -$_->{verrelease} = { - # mark last three (future) versions as unreleased, ensure current isn't - map { - $_->[-1] => 0, $_->[-2] => 0, $_->[-3] => 0, - $_->[-4] => undef, - } $_->{versions} -} for values %{ $caniuse->{agents} }; +my $caniuse = Data('data/browser/support'); my %CSTATS = ( 'n' => 'l1', @@ -36,11 +29,14 @@ my %CSTATS = ( 'p d' => 'l2', 'a d' => 'l2', 'y' => 'l5', + 'y #' => 'l4', 'y x' => 'l5 ex', + 'y x #' => 'l4 ex', 'a' => 'l3', 'a x' => 'l3 ex', 'p' => 'l2', 'u' => 'l0', + 'u d' => 'l2', ); my %DSTATS = ( u => 'unknown', @@ -53,7 +49,7 @@ my %DSTATS = ( join(' ', 'with prefix', map {"-$_-"} - ($caniuse->{agents}->{$_[0]}->{prefix_exceptions} // {})->{$_[1]} + $caniuse->{agents}->{$_[0]}->{version_list}->{$_[1]}->{prefix} // $caniuse->{agents}->{$_[0]}->{prefix} // (), ); }, @@ -77,14 +73,14 @@ my %CSTATUS = ( ); my %versions; while (my ($browser, $row) = each %{ $caniuse->{agents} }) { - $versions{$browser} = [ - sort { paddedver($a) cmp paddedver($b) } grep { defined } - @{ $row->{versions} } - ]; + $versions{$browser} = [@{ $row->{versions} }]; } -print <<''; -

Alternate rendition of Fyrd's when can I use... page +my $ref = showlink('Can I use', 'https://caniuse.com/'); +$ref =~ s/(?=>)/ title="updated $_"/ + for map { s/[\sT].*//r } $caniuse->{-date} || (); +$ref = "Fyrd's $ref page"; +say '

Alternate rendition of '.$ref; my ($canihas, $usage); my $minusage = $get{threshold} // 1; @@ -98,15 +94,15 @@ given ($get{usage} // 'wm') { 'Identifier must be alphanumeric name or 0.', ]); } - $canihas = do "data/browser/usage-$_.inc.pl" or do { - Alert('Browser usage data not found', $@ || $!); + $canihas = eval { Data("data/browser/usage-$_") } or do { + Alert('Browser usage data not found', $@); break; }; $usage = $_; my $ref = $canihas->{-title} || 'unknown'; $ref = showlink($ref, $_) for $canihas->{-site} || $canihas->{-source} || (); - $ref .= " $_" for $canihas->{-date} || (); + $ref =~ s/(?=>)/ title="updated $_"/ for $canihas->{-date} || (); print "\nwith $ref browser usage statistics"; } @@ -195,7 +191,10 @@ $canihas ||= { # score multiplier for percentage of all browser versions my $usagepct = 99.99 / sum( - map { $_->{-total} // values %{$_} } values %{$canihas} + map { $_->{-total} // values %{$_} } + map { $canihas->{$_} } + grep { !/^-/ } + keys %{$canihas} ); $_->{usage} = featurescore($_->{stats}) * $usagepct @@ -234,13 +233,15 @@ print "\n

%s', join(' ', sprintf('%.1f%%', sum(@{ $canihas->{$browser} }{ @{$span} }) * $usagepct), 'version ' . showversions(@{$span}, undef), - $span->[-1] eq $lastver ? () : '(development)', + (map { + $_ ? sprintf('(released %d)', $_/3600/24/365.25 + 1970) : '(development)' + } $caniuse->{agents}->{$browser}->{version_list}->{$lastver}->{release_date}), ), !defined $lastver && ' class="ex"', showversions($lastver // $span->[0]), @@ -270,9 +271,12 @@ sub featurescore { if ($canihas) { while (my ($browser, $versions) = each %$row) { ref $versions eq 'HASH' or next; - while (my ($version, $status) = each %$versions) { + my $prev; + for my $version (@{ $caniuse->{agents}->{$browser}->{versions} }) { + my $status = $versions->{$version} // $prev; $status =~ s/\h\#\d+//g; $rank += ($canihas->{$browser}->{$version} || .001) * $PSTATS{$status}; + $prev = $status; } } return $rank; @@ -304,6 +308,7 @@ sub formatnotes { s/(?<= [^.\n]) $/./gmx; # consistently end each line by a period Entity($_); s{ ` ([^`]*) ` }{$1}gx; + s{ \(\K (?: \Qhttps://caniuse.com\E )? (?: /? \#feat= | / ) }{#}gx; s{ \[ ([^]]*) \] \( ([^)]*) \) }{$1}gx; } return @html; @@ -372,9 +377,9 @@ sub saybrowsercols { my $data = $feature->{stats}->{$browser}; if (ref $data eq 'ARRAY') { # special case for unsupported - my $release = $caniuse->{agents}->{$browser}->{verrelease}; $data = { - map { $_ => defined $release->{$_} ? 'u' : 'n' } keys %$release + map { $_ => 'n' } + keys %{ $caniuse->{agents}->{$browser}->{version_list} } }; } @@ -383,15 +388,15 @@ sub saybrowsercols { my $compare = ( !defined $ver ? undef : # last column if nameless ref $data ne 'HASH' ? '' : # unclassified if no support hash - $data->{ $ver->[-1] } // $prev # known or inherit from predecessor - // (grep { defined } @{$data}{ map { $_->[0] } @{ $versions{$browser} } })[0] - ~~ 'n' && 'n' # first known version is unsupported + (first { defined } @{$data}{ reverse @{$ver} }) # last known version + // $prev # inherit from predecessor || 'u' # unsure ); - unless (!defined $prev or $prev ~~ $compare) { - my @vercover = (map { @{$_} } @span); + if (defined $prev and not $prev ~~ $compare) { + # different columns + my @vercover = (map { @{$_} } @span); # accumulated conforming versions for ($ver ? @{$ver} : ()) { - $data->{$_} eq $data->{$vercover[-1]} or last; + last if defined $data->{$_}; # until different push @vercover, $_; # matches from next span start } my $usage = sum(@{ $canihas->{$browser} }{@vercover}); @@ -413,6 +418,7 @@ sub saybrowsercols { )); $title .= "\n$_" for notestotitle(@notes); + $prev .= ' #' if @notes and $prev =~ /^y/; printf('%s', join(' ', X => $CSTATS{$prev}, @@ -423,12 +429,16 @@ sub saybrowsercols { ), scalar @span, $title, - showversions($span[0]->[0], @span > 1 ? $span[-1]->[-1] : ()), + showversions($span[0]->[0], @span > 1 && defined $ver ? $span[-1]->[-1] : ()), ); undef $prev; @span = (); } - push @span, $ver && [ grep { $data->{ $_ } eq $data->{ $ver->[-1] } } @{$ver} ]; + if ($ver) { + my $startversion = first { defined $data->{ $ver->[$_] } } + reverse 0 .. $#{$ver}; # compare index + push @span, [ @{$ver}[ $startversion .. $#{$ver} ] ]; + } $prev = $compare; } } @@ -457,7 +467,7 @@ sub paddedver { # normalised version number comparable as string (cmp) $_[0] =~ m/(?:.*-|^)(\d*)(.*)/; # matched (major)(.minor) of last value in range (a-B) - return sprintf('%02d', length $1 ? $1 : 99) . $2; + return sprintf('%03d', length $1 ? $1 : 999) . $2; } sub showversions { @@ -474,6 +484,7 @@ sub showversions {
supported + annotated partial optional missing diff --git a/chars.plp b/chars.plp index 04420cd..91df3b8 100644 --- a/chars.plp +++ b/chars.plp @@ -2,7 +2,7 @@ Html({ title => 'character support sheet', - version => '1.1', + version => '1.2', keywords => [qw' unicode glyph char character reference common ipa symbol sign mark table digraph '], @@ -22,7 +22,7 @@ EOT use Shiar_Sheet::FormatChar; my $glyphs = Shiar_Sheet::FormatChar->new; -my $groupinfo = do 'data/unicode-cover.inc.pl' or die $@ || $!; +my $groupinfo = Data('data/unicode-cover'); my @ossel = @{ $groupinfo->{osdefault} }; my @fontlist = map { $_->{file} } @@ -30,11 +30,10 @@ my @fontlist = map { $_->{file} } my %font; for my $fontid (@fontlist) { - my ($fontmeta, @fontrange) = do "data/font/$fontid.inc.pl"; - $fontmeta or next; + my $fontmeta = eval { Data("data/font/$fontid") } or next; $font{$fontid} = { (map { (-$_ => $fontmeta->{$_}) } keys %{$fontmeta}), - map { (chr $_ => 1) } @fontrange + map { (chr $_ => 1) } @{ $fontmeta->{cover} } }; } @@ -62,8 +61,7 @@ my $query = eval { say "

$title

"; if (!$query) { - Alert('Unicode group not specified', $@); - exit; + Abort(["Unicode group not found", $@], '404 no matches'); }; for ($parent || 'Unicode range') { @@ -82,15 +80,16 @@ for ($parent || 'Unicode range') { my @chars; for (map { split /[^\d-]/ } $query) { my @range = split /-/, $_, 2; - m/^[0-9]+$/ or die "Invalid code point $_ in query $query\n" for @range; + m/^[0-9]+$/ or Abort("Invalid code point $_ in query $query", 400) + for @range; push @chars, chr $_ for $range[0] .. ($range[1] // $range[0]); } -@chars or die "No match for query $query\n"; +@chars or Abort("No match for query $query", '404 no results'); -@chars <= 1500 or die sprintf( - 'Too many matches (%d) for query %s'."\n", - scalar @chars, $query, +@chars <= 1500 or Abort( + sprintf('Too many matches (%d) for query', scalar @chars), + '403 not allowed', $query ); # output character list diff --git a/charset-encoding.inc.pl b/charset-encoding.inc.pl index 92330ab..8e748ed 100644 --- a/charset-encoding.inc.pl +++ b/charset-encoding.inc.pl @@ -9,7 +9,7 @@ use utf8; ebcdic => [qw( cp37 cp500 cp1047 posix-bc cp1026 cp875 )], iso => [map {"iso-8859-$_"} 1 .. 11, 13 .. 16], dos => [qw( cp437 cp865 cp861 cp860 cp863 cp850 cp857 cp852 cp775 - cp737 cp869 cp866 cp855 cp862 cp864 )], + cp737 cp869 cp866 MIK cp855 cp862 cp864 )], aix => [qw( cp1006 )], win => [qw( cp1252 cp1250 cp1254 cp1257 cp1258 cp1253 cp1251 cp1255 cp1256 cp874 )], mac => [qw( MacRoman MacRomanian MacRumanian MacCroatian MacCentralEurRoman MacTurkish MacIcelandic MacSami @@ -22,7 +22,7 @@ use utf8; norteur => [qw( baltic nordic )], baltic => [qw( iso-8859-4 iso-8859-13 cp1257 cp775 )], nordic => [qw( iso-8859-10 cp865 cp861 MacIcelandic MacSami )], - cyrillic => [qw( koi8-r koi8-u koi8-f iso-8859-5 cp1251 MacCyrillic cp866 cp855 + cyrillic => [qw( koi8-r koi8-u koi8-f iso-8859-5 cp1251 MacCyrillic cp866 MIK cp855 +400 +2DE0 +A640-A69F +500-52F )], # MacUkrainian is broken arabic => [qw( iso-8859-6 cp1256 MacArabic cp864 cp1006 MacFarsi +600 +8A0-8BF+8E0 +750-77F )], @@ -71,8 +71,9 @@ use utf8; }, }, 'adobesymbol' => {inherit => ['symbol' => '20-7F+A0', '' => '20-7F+A0']}, # minor differences, irrelevant except for different '€' - 'wingdings' => {inherit => ['' => '20'], setup => sub { - $_[0]->{table} = [(map {chr} 0 .. 0x20), qw( + 'wingdings' => { + inherit => ['' => '20'], + table => [(map {chr} 0 .. 0x20), qw( 🖉 ✂ ✁ 👓 🕭 🕮 🕯 🕿 ✆ 🖂 🖃 📪 📫 📬 📭 📁 📂 📄 🗏 🗐 🗄 ⌛ 🖮 🖰 🖲 🖳 🖴 🖫 🖬 ✇ ✍ 🖎 ✌ 👌 👍 👎 ☜ ☞ ☝ ☟ 🖐 ☺ 😐 ☹ 💣 ☠ 🏳 🏱 ✈ ☼ 💧 ❄ 🕆 ✞ 🕈 ✠ ✡ ☪ ☯ ॐ ☸ ♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏ ♐ ♑ ♒ ♓ 🙰 🙵 ● 🔾 ■ □ 🞐 ❑ ❒ ⬧ ⧫ ◆ ❖ ⬥ ⌧ ⮹ ⌘ 🏵 🏶 🙶 🙷  @@ -80,10 +81,11 @@ use utf8; ▪ ⚪ 🞆 🞈 ◉ ◎ 🔿 ▪ ◻ 🟂 ✦ ★ ✶ ✴ ✹ ✵ ⯐ ⌖ ⟡ ⌑ ⯑ ✪ ✰ 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 ⮰ ⮱ ⮲ ⮳ ⮴ ⮵ ⮶ ⮷ 🙪 🙫 🙕 🙔 🙗 🙖 🙐 🙑 🙒 🙓 ⌫ ⌦ ⮘ ⮚ ⮙ ⮛ ⮈ ⮊ ⮉ ⮋ 🡨 🡪 🡩 🡫 🡬 🡭 🡯 🡮 🡸 🡺 🡹 🡻 🡼 🡽 🡿 🡾 ⇦ ⇨ ⇧ ⇩ ⬄ ⇳ ⬀ ⬁ ⬃ ⬂ 🢬 🢭 🗶 ✔ 🗷 🗹  - )]; - }}, - 'wingdings2' => {inherit => ['' => '20'], setup => sub { - $_[0]->{table} = [(map {chr} 0 .. 0x20), qw( + )], + }, + 'wingdings2' => { + inherit => ['' => '20'], + table => [(map {chr} 0 .. 0x20), qw( 🖊 🖋 🖌 🖍 ✄ ✀ 🕾 🕽 🗅 🗆 🗇 🗈 🗉 🗊 🗋 🗌 🗍 📋 🗑 🗔 🖵 🖶 🖷 🖸 🖭 🖯 🖱 🖒 🖓 🖘 🖙 🖚 🖛 👈 👉 🖜 🖝 🖞 🖟 🖠 🖡 👆 👇 🖢 🖣 🖑 🗴 ✓ 🗵 ☑ ☒ ☒ ⮾ ⮿ ⦸ ⦸ 🙱 🙴 🙲 🙳 ‽ 🙹 🙺 🙻 🙦 🙤 🙥 🙧 🙚 🙘 🙙 🙛 ⓪ ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⓿ ❶ ❷ ❸ ❹ ❺ ❻ ❼ ❽ ❾ ❿  @@ -91,10 +93,11 @@ use utf8; ■ ◼ ⬛ ⬜ 🞑 🞒 🞓 🞔 ▣ 🞕 🞖 🞗 ⬩ ⬥ ◆ ◇ 🞚 ◈ 🞛 🞜 🞝 ⬪ ⬧ ⧫ ◊ 🞠 ◖ ◗ ⯊ ⯋ ◼ ⬥ ⬟ ⯂ ⬣ ⬢ ⯃ ⯄ 🞡 🞢 🞣 🞤 🞥 🞦 🞧 🞨 🞩 🞪 🞫 🞬 🞭 🞮 🞯 🞰 🞱 🞲 🞳 🞴 🞵 🞶 🞷 🞸 🞹 🞺 🞻 🞼 🞽 🞾 🞿 🟀 🟂 🟄 ✦ 🟉 ★ ✶ 🟋 ✷ 🟏 🟒 ✹ 🟃 🟇 ✯ 🟍 🟔 ⯌ ⯍ ※ ⁂ - )]; - }}, - 'wingdings3' => {inherit => ['' => '20'], setup => sub { - $_[0]->{table} = [(map {chr} 0 .. 0x20), qw( + )], + }, + 'wingdings3' => { + inherit => ['' => '20'], + table => [(map {chr} 0 .. 0x20), qw( ⭠ ⭢ ⭡ ⭣ ⭦ ⭧ ⭩ ⭨ ⭰ ⭲ ⭱ ⭳ ⭶ ⭸ ⭻ ⭽ ⭤ ⭥ ⭪ ⭬ ⭫ ⭭ ⭍ ⮠ ⮡ ⮢ ⮣ ⮤ ⮥ ⮦ ⮧ ⮐ ⮑ ⮒ ⮓ ⮀ ⮃ ⭾ ⭿ ⮄ ⮆ ⮅ ⮇ ⮏ ⮍ ⮎ ⮌ ⭮ ⭯ ⎋ ⌤ ⌃ ⌥ ⎵ ⏡ ⇪ ⮸ 🢠 🢡 🢢 🢣 🢤 🢥 🢦 🢧 🢨 🢩 🢪 🢫 ← → ↑ ↓ ↖ ↗ ↙ ↘ 🡘 🡙 ▲ ▼ △ ▽ ◄ ► ◁ ▷ ◣ ◢ ◤ ◥ 🞀 🞂 🞁  @@ -102,10 +105,11 @@ use utf8; 🠇 🠈 🠊 🠉 🠋 🠠 🠢 🠤 🠦 🠨 🠨 🠪 🢜 🢝 🢞 🢟 🠮 🠰 🠲 🠴 🠶 🠸 🠺 🠹 🠻 🢘 🢚 🢙 🢛 🠼 🠾 🠽 🠿 🡀 🡂 🡁 🡃 🡄 🡆 🡅 🡇 ⮨ ⮩ ⮪ ⮫ ⮬ ⮭ ⮮ ⮯ 🡠 🡢 🡡 🡣 🡤 🡥 🡧 🡦 🡰 🡲 🡱 🡳 🡴 🡵 🡷 🡶 🢀 🢂 🢁 🢃 🢄 🢅 🢇 🢆 🢐 🢒 🢑 🢓 🢔 🢖 🢕 🢗 - )]; - }}, - 'webdings' => {inherit => ['' => '20'], setup => sub { - $_[0]->{table} = [(map {chr} 0 .. 0x20), qw( + )], + }, + 'webdings' => { + inherit => ['' => '20'], + table => [(map {chr} 0 .. 0x20), qw( 🕷 🕸 🕲 🕶 🏆 🎖 🖇 🗨 🗩 🗰 🗱 🌶 🎗 ▞ 🙼 🗕 🗖 🗗 ⏴ ⏵ ⏶ ⏷ ⏪ ⏩ ⏮ ⏭ ⏸ ⏹ ⏺ 🗚 🗳 🛠 🏗 🏘 🏙 🏚 🏜 🏭 🏛 🏠 🏖 🏝 🛣 🔍 🏔 👁 👂 🏞 🏕 🛤 🏟 🛳 🕬 🕫 🕨 🔈 🎔 🎕 🗬 🙽 🗭 🗪 🗫 ⮔ ✔ 🚲 □ 🛡 📦 🛱 ■ 🚑 🛈 🛩 🛰 🟈 🕴 ⚫ 🛥 🚔 🗘 🗙 ❓ 🛲 🚇 🚍 ⛳ 🛇 ⊖ 🚭 🗮 | 🗯 🗲  @@ -113,8 +117,8 @@ use utf8; 🕵 🕰 🖽 🖾 📋 🗒 🗓 📖 📚 🗞 🗟 🗃 🗂 🖼 🎭 🎜 🎘 🎙 🎧 💿 🎞 📷 🎟 🎬 📽 📹 📾 📻 🎚 🎛 📺 💻 🖥 🖦 🖧 🕹 🎮 🕻 🕼 📟 🖁 🖀 🖨 🖩 🖿 🖪 🗜 🔒 🔓 🗝 📥 📤 🕳 🌣 🌤 🌥 🌦 ☁ 🌧 🌨 🌩 🌪 🌬 🌫 🌜 🌡 🛋 🛏 🍽 🍸 🛎 🛍 Ⓟ ♿ 🛆 🖈 🎓 🗤 🗥 🗦 🗧 🛪 🐿 🐦 🐟 🐕 🐈 🙬 🙮 🙭 🙯 🗺 🌍 🌏 🌎 🕊 - )]; - }}, + )], + }, 'iso-8859-2' => {inherit => ['iso-8859-1' => 'A0']}, 'iso-8859-3' => {inherit => ['iso-8859-1' => 'A0']}, #TODO: also apply to iso-8859-9 @@ -161,6 +165,19 @@ use utf8; 'koi8-u' => {inherit => ['koi8-r' => '90-BF']}, 'koi8-f' => {inherit => ['koi8-u' => '90-BF']}, + 'mik' => { + inherit => ['cp437' => '80-D8', 'cp866' => 'B0'], + table => [(map {chr} 0 .. 0x7F), qw( + А Б В Г Д Е Ж З И Й К Л М Н О П + Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я + а б в г д е ж з и й к л м н о п + р с т у ф х ц ч ш щ ъ ы ь э ю я + └ ┴ ┬ ├ ─ ┼ ╣ ║ ╚ ╔ ╩ ╦ ╠ ═ ╬ ┐ + ░ ▒ ▓ │ ┤ № § ╗ ╝ ┘ ┌ █ ▄ ▌ ▐ ▀ + α ß Γ π Σ σ µ τ Φ Θ Ω δ ∞ φ ε ∩ + ≡ ± ≥ ≤ ⌠ ⌡ ÷ ≈ ° ∙ · √ ⁿ ² ■ + ), "\xA0"], + }, 'macromanian' => {inherit => ['MacRoman' => 'A0-BF+D0-DF']}, 'macrumanian' => {inherit => ['MacRomanian' => 'A0-BF+D0-DF', 'MacRoman' => 'A0-BF+D0-DF']}, @@ -206,54 +223,114 @@ use utf8; 'cp1026' => {inherit => ['cp37' => '40']}, 'cp875' => {inherit => ['cp37' => '30']}, - '' => {setup => sub { - my $row = shift; - $row->{offset} = delete $row->{startpoint}; - $row->{set} = 'Unicode characters'; - my $block = $row->{offset} >> 8; - $row->{endpoint} ||= ($block + 1 << 8) - 1; - $block == ($row->{endpoint} >> 8) or undef $block; - - $row->{table} = join '', map { chr } $row->{offset} .. $row->{endpoint}; - utf8::upgrade($row->{table}); # prevent latin1 output - - $row->{endpoint} -= $row->{offset}; - - if (defined $block) { - $row->{set} = sprintf 'Unicode block U+%02Xxx', $block; - $row->{offset} %= 0x100; - } - - return $row; - }}, - u => {setup => sub { - my $row = shift; - state $celldata = do 'charset-unicode.inc.pl' - or Alert('Table data could not be read', $@ || $!); - $row->{cell} = $celldata; - - $row->{endpoint} ||= 0x1FFF; - $row->{set} = 'Unicode ' . ( - $row->{startpoint} < 0x1000 && $row->{endpoint} < 0x1000 ? 'BMP' : - $row->{startpoint} >= 0x1000 && $row->{endpoint} < 0x2000 ? 'SMP' : - 'allocations' - ); - return $row; - }}, - uu => {setup => sub { - my $row = shift; - $row->{cell} = do 'charset-ucplanes.inc.pl' - or Alert('Table data could not be read', $@ || $!); - $row->{endpoint} ||= 0x3FF; - $row->{set} = 'Unicode planes'; - return $row; - }}, - utf8 => {setup => sub { - my $row = shift; - $row->{set} = 'UTF-8'; - $row->{cell} = do 'charset-utf8.inc.pl' - or Alert('Table data could not be read', $@ || $!); - return $row; - }}, - 'utf-8' => 'utf8', + legacy => [qw( cp437 ATASCII PETSCII MSX ZX-Spectrum ANSEL )], + 'petscii' => { + inherit => ['' => '40-7F+A0-BF'], + table => [(map {chr} 0 .. 0x3F), qw( + @ a b c d e f g h i j k l m n o p q r s t u v w x y z [ £ ] ↑ ← + 🭹 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ┼ 🮌 │ 🮖 🮘 + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +   ▌ ▄ ▔ ▁ ▏ ▒ ▕ 🮏 🮙 🮇 ├ ▗ └ ┐ ▂ ┌ ┴ ┬ ┤ ▎ ▍ 🮈 🮂 🮃 ▃ ✓ ▖ ▝ ┘ ▘ ▚ + )], + }, + 'atascii' => { + inherit => ['' => '0-1F+60-7F'], + table => [qw( + ♥ ├ 🮇 ┘ ┤ ┐ ╱ ╲ ◢ ▗ ◣ ▝ ▘ 🮂 ▂ ▖ ♣ ┌ ─ ┼ • ▄ ▎ ┬ ┴ ▌ └ ␛ ↑ ↓ ← → + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + ♦ a b c d e f g h i j k l m n o p q r s t u v w x y z ♠ | 🢰 ◀ ▶ + )], + }, + 'zx-spectrum' => { + inherit => ['' => '50-8F'], + set => 'ascii', + replace => { + ord('^') => '↑', + ord('`') => '£', + 0x7F => '© ▝▘▀▗▐▚▜▖▞▌▛▄▟▙█', + }, + }, + 'msx' => { + inherit => ['cp437' => '80-FF'], + table => [(map {chr} 0 .. 0x7F), qw( + Ç ü é â ä à å ç ê ë è ï î ì Ä Å É æ Æ ô ö ò û ù ÿ Ö Ü ¢ £ ¥ ₧ ƒ + á í ó ú ñ Ñ ª º ¿ ⌐ ¬ ½ ¼ ¡ « » à ã Ĩ ĩ Õ õ Ũ ũ IJ ij ¾ ∽ ◊ ‰ ¶ § + ▂ ▚ ▆ 🮂 ▬ 🮅 ▎ ▞ ▊ 🮇 🮊 🮙 🮘 🭭 🭯 🭬 🭮 🮚 🮛 ▘ ▗ ▝ ▖ 🮖 Δ ‡ ω █ ▄ ▌ ▐ ▀ + α ß Γ π Σ σ µ τ Φ Θ Ω δ ∞ ⌀ ∈ ∩ ≡ ± ≥ ≤ ⌠ ⌡ ÷ ≈ ° ∙ · √ ⁿ ² ■ + )], + }, + 'brascii' => { + inherit => ['' => 'D0-DF+F0-FF'], + table => [(map {chr} 0 .. 0xFF)], + replace => { + 0xD7 => 'Œ', + 0xF7 => 'œ', + }, + }, + 'ansel' => { + note => '+GEDCOM', + inherit => ['' => 'A0-CF+E0-FE'], + table => [ + (undef) x 0xA0, + undef, qw( Ł Ø Đ Þ Æ Œ ʹ · ♭ ® ± Ơ Ư ʾ ), undef, + qw( ʿ ł ø đ þ æ œ ʺ ı £ ð ), undef, qw( ơ ư ), undef, undef, + qw( ° ℓ ℗ © ♯ ¿ ¡ ), (undef) x 0x19, + (map {$_ && chr} + 0x309, 0x300, 0x0301, 0x0302, 0x0303, 0x304, 0x306, 0x307, + 0x308, 0x30C, 0x030A, 0xFE20, 0xFE21, 0x315, 0x30B, 0x310, + 0x327, 0x328, 0x0323, 0x0324, 0x0325, 0x333, 0x332, 0x326, + 0x31C, 0x32E, 0xFE22, 0xFE23, undef, undef, 0x313, undef, + ), + ], + replace => { + # GEDCOM extensions + 0xBE => '□', + 0xBF => '■', + 0xCD => 'e', # endowment? + 0xCE => 'o', # ordinance? + 0xCF => 'ß', + 0xFC => "\x{338}", + # MARC21 extensions + 0xC7 => 'ß', + 0xC8 => '€', + }, + }, + 'ti86' => { + note => 'similar to TI85', + inherit => ['', => '0-1F+80-EC'], + table => [ + undef, qw( + 𝐛 𝐨 𝐝 𝐡 ▶ ⬆ ⬇ ∫ × 𝐀 𝐁 𝐂 𝐃 𝐄 𝐅 + √ ⁻¹ ² ∠ ° ʳ ᵀ ≤ ≠ ≥ ⁻ ᴇ → ⏨ ↑ ↓ + ), + (undef) x 0x60, + qw( + ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ Á À Â Ä á à + â ä É È Ê Ë é è ê ë Í Ì Î Ï í ì + î ï Ó Ò Ô Ö ó ò ô ö Ú Ù Û Ü ú ù + û ü Ç ç Ñ ñ ´ ` ¨ ¿ ¡ α β γ Δ δ + ϵ θ λ μ π ρ Σ σ τ ϕ Ω x̅ y̅ ˟ … ◀ + ■ ∕ ‐ ² ° ³ :⃞ ➧ ⧵ 🙽 ◥ ◣ ⊸ ∘ ⋱ █ + ⇧ A⃞ a⃞ _ ⇧̲ A̲ a̲ ▒ ⬞ ˖ · ⁴ ﹦ + ), + ], + }, + 'ti89' => { + note => 'also TI92(+)', + inherit => ['', => '0-1F+7F-BE'], + table => [ + qw( + ▒ ␁ ␂ ␃ ␄ ␅ ␆ 🔔 ⌫ ⇥ ), chr(0xA), qw( ⬏ ⤒ ↵ 🔒 ✓ + ■ ◂ ▸ ▴ ▾ ← → ↑ ↓ ◀ ▶ ⬆ ∪ ∩ ⊂ ∈ + ), + (map {chr} 0x20 .. 0x7E), '◆', + qw( + α β Γ γ Δ δ ε ζ θ λ ξ ∏ π ρ ∑ σ + τ ϕ ψ Ω ω ᴇ ℯ 𝐢 ʳ ᵀ x̅ y̅ ≤ ≠ ≥ ∠ + … ¡ ¢ £ ¤ ¥ ¦ § √ © ª « ¬ ⁻ ® ¯ + ° ± ² ³ ⁻¹ µ ¶ · ⁺ ¹ º » 𝑑 ∫ ∞ ¿ + ), + ], + }, }; diff --git a/charset.inc.pl b/charset.inc.pl new file mode 100644 index 0000000..020cb2d --- /dev/null +++ b/charset.inc.pl @@ -0,0 +1,59 @@ +use 5.014; +use warnings; +use utf8; + ++{ + %{ Data('./charset-encoding') }, + + '' => {setup => sub { + my $row = shift; + $row->{offset} = delete $row->{startpoint}; + $row->{set} = 'Unicode characters'; + my $block = $row->{offset} >> 8; + $row->{endpoint} ||= ($block + 1 << 8) - 1; + $block == ($row->{endpoint} >> 8) or undef $block; + + $row->{table} = join '', map { chr =~ s/\A\p{Unassigned}\z/�/r } + $row->{offset} .. $row->{endpoint}; + utf8::upgrade($row->{table}); # prevent latin1 output + + $row->{endpoint} -= $row->{offset}; + + if (defined $block) { + $row->{set} = sprintf 'Unicode block U+%02Xxx', $block; + $row->{offset} %= 0x100; + } + + return $row; + }}, + u => {setup => sub { + my $row = shift; + state $celldata = eval { Data('charset-unicode') } + or Alert('Table data could not be read', ref $@ && $@->[1]); + $row->{cell} = $celldata; + + $row->{endpoint} ||= 0x1FFF; + $row->{set} = 'Unicode ' . ( + $row->{startpoint} < 0x1000 && $row->{endpoint} < 0x1000 ? 'BMP' : + $row->{startpoint} >= 0x1000 && $row->{endpoint} < 0x2000 ? 'SMP' : + 'allocations' + ); + return $row; + }}, + uu => {setup => sub { + my $row = shift; + $row->{cell} = eval { Data('charset-ucplanes') } + or Alert('Table data could not be read', ref $@ && $@->[1]); + $row->{endpoint} ||= 0x3FF; + $row->{set} = 'Unicode planes'; + return $row; + }}, + utf8 => {setup => sub { + my $row = shift; + $row->{set} = 'UTF-8'; + $row->{cell} = eval { Data('charset-utf8') } + or Alert('Table data could not be read', ref $@ && $@->[1]); + return $row; + }}, + 'utf-8' => 'utf8', +}; diff --git a/charset.plp b/charset.plp index e9f097d..bbab1d6 100644 --- a/charset.plp +++ b/charset.plp @@ -5,7 +5,8 @@ my @tablist = split m{/+}, $Request || 'default'; Html({ title => 'charset cheat sheet', - version => '1.1', + version => '1.3', + canonical => "/charset/$Request" . ($mode && '?compare'), description => [ "Reference sheet with all glyphs in common character encoding tables,", "and an overview of Unicode ranges and UTF-8 bytes.", @@ -14,9 +15,9 @@ Html({ charset codepage unicode ascii utf8 latin glyph character encoding reference common overview table '], - stylesheet => [qw'light'], + (stylesheet => [qw'light']) x !$mode, data => [qw( - charset-encoding.inc.pl + charset.inc.pl charset-encoding.inc.pl charset-unicode.inc.pl charset-ucplanes.inc.pl charset-utf8.inc.pl )], }); @@ -55,6 +56,7 @@ print join " •\n", ( dos => 'DOS', mac => 'Apple', ebcdic => 'EBCDIC', + legacy => 'legacy', $tablist[0] eq 'default' ? () : ('' => 'common'), ], [ @@ -78,8 +80,7 @@ use Shiar_Sheet::FormatChar; my $glyphs = Shiar_Sheet::FormatChar->new; my @request; -my $charsets = do 'charset-encoding.inc.pl' - or Alert('Encoding metadata could not be read', $@ || $!); +my $charsets = Data('charset'); sub tabinput { # generate character table(s) @@ -97,6 +98,7 @@ sub tabinput { state $visible = {'' => 1}; # all present tables my %row = (offset => 0, cols => 16); + $row{$_} = $charset->{$_} for qw( note table ); # copy metadata if (not defined $params) { my @parents = @{ $charset->{inherit} || [] }; @@ -131,7 +133,7 @@ sub tabinput { # extend earlier range my $skip = int(($row{endpoint} || $row{startpoint}) / $row{cols}); for ($skip + 1 .. (hex($+{start}) / $row{cols}) - 1) { - $row{skip}->{ $_ * $row{cols} - $row{startpoint} }++; + $row{skip}->{ $_ * $row{cols} }++; } } else { @@ -153,7 +155,7 @@ sub tabinput { if (defined $row{table} or defined $row{cell}) { $row{set} //= $input; } - elsif ($row{set} = Encode::resolve_alias($input)) { + elsif ($row{set} = Encode::resolve_alias($charset->{set} // $input)) { $row{offset} = delete $row{startpoint}; if ($charset->{varchar}) { # array of possibly multiple characters per code point @@ -169,6 +171,7 @@ sub tabinput { $row{endpoint} -= $row{offset}; $visible->{ascii}++; # assume common base + $row{set} = $input if $charset->{set}; # base override } else { Alert("Encoding $input unknown"); @@ -289,8 +292,8 @@ for my $row (@request) { printf '
', !$row->{cell} && ' charmap'; my $title = $row->{set}; - $title .= " " - for $row->{parent} || (); + $title .= " " for $row->{parent} || (); + $title .= " " for $row->{note} || (); printf '', $title; print '' x ($cols + 1); for my $section (qw{thead}) { @@ -301,13 +304,13 @@ for my $row (@request) { print ''; while ($offset <= $row->{endpoint} * $colsize) { - if ($row->{skip}->{$offset}) { + if ($row->{skip}->{$offset + $row->{offset}}) { $offset += $cols * $colsize; next; } print '
%s
'; - if (defined $row->{skip}->{$offset}) { + if (defined $row->{skip}->{$offset + $row->{offset}}) { print '⋮'; } else { @@ -340,15 +343,15 @@ for my $row (@request) { $cp == ord $glyph ? 'l4' : $row->{parent} && $glyph eq Encode::decode($row->{parent}, pack 'C', $cp) ? 'l3' : - !$class ? undef : + !defined $cell ? undef : $visible->{$glyph} ? 'l2' : 'l1' ); $visible->{$glyph}++; } - say sprintf $class ? '%s' : '', - $name, $class, $cell; + printf '%s', $class, $cell) : '>'; } continue { $offset += $colsize; diff --git a/circus.css b/circus.css index aed61fc..5844529 100644 --- a/circus.css +++ b/circus.css @@ -1,4 +1,4 @@ -@import url(light.css?1.10); +@import url(light.css?1.11); .l1 {background: #F77} .l1:hover a, .l1:hover a:visited, diff --git a/cli.plp b/cli.plp new file mode 100644 index 0000000..96cd427 --- /dev/null +++ b/cli.plp @@ -0,0 +1,60 @@ +<(common.inc.plp)><: + +Html({ + title => 'cli cheat sheet', + version => '1.0', + description => [], + keywords => [qw' + '], + data => ['data/cli.inc.pl'], +}); + +my $cmd = Data('data/cli'); +:> +

CLI options

+ + +<: +sub showoption { + my ($info, $char, $span) = @_; + my ($alias, $help) = @{ $info // [] }; + printf '
'; + $info or return; + my ($title) = $alias =~ m{--([\w-]+=?)} + or return print $char; + $title =~ s/-\K//g; + $title =~ s/deref\Kerence/./; + print $title; +} + +my @colchars = ('a'..'z', '?'); +print ''; +print qq'' for scalar @colchars; +#say ''; +for my $section (qw{thead tfoot}) { + print "<$section>'; +for my $name (sort keys %$cmd) { + my $row = $cmd->{$name}; + print '"; + $row->{$_} and showoption($row->{$_}, $_) for map {uc} @colchars; +} +say '
↳"; + print '', EscapeHTML($_) for @colchars; + say ''; +} +print '
', $name; + showoption($row->{$_}, $_, !$row->{uc $_}) for @colchars; + print "\n\t
'; +:> + +
+ +
supported + unsupported + alias +
+
diff --git a/codec-audio.inc.pl b/codec-audio.inc.pl new file mode 100644 index 0000000..330f3b5 --- /dev/null +++ b/codec-audio.inc.pl @@ -0,0 +1,142 @@ +use utf8; ++{ +intro => 'Comparison of audio compression formats.', +keywords => [qw( audio sound codec encoder encoding decode compression file format type mime )], +codec => { + mp3 => { + name => 'MP3', + available => 1991, + generation => 0, + }, + vorbis => { + name => 'Vorbis', + available => 2000, + generation => 1, + }, + opus => { + name => 'Opus', + available => 2012, + generation => 1, + }, + aac => { + name => 'AAC', + available => 1997, + generation => 1, + }, + atrac => { + name => 'ATRAC', + available => 1992, + generation => 0, + }, + mpc => { + name => 'Musepack', + abbr => 'MPC', + mime => 'audio/musepack', + available => 1997, + generation => 1, + }, +}, +feature => { + default => { + children => [qw( quality limits royalties support )], + }, + quality => { + name => 'compression quality', + children => [qw( quality_music quality_speech quality_ll )], + score => { + }, + }, + quality_music => { + name => 'music', + score => { + mp3 => 3, + atrac => 2, + vorbis => 4, + aac => 5, + opus => 5, + }, + }, + quality_speech => { + name => 'speech', + score => { + mp3 => 3, + }, + }, + quality_ll => { + name => 'lossless', + score => { + mp3 => 'n', + vorbis => 'n', + opus => 'n', + flac => 4, + }, + }, + limits => { + children => [qw( channels bitrate latency peeling )], + score => { + }, + }, + channels => { + score => { + mp3 => [3, 6, 'stereo, extended to upto 5.1'], + vorbis => [4, 255], + opus => [4, 255], + }, + }, + peeling => { + name => 'bitrate peeling', + score => { + vorbis => [3, undef, 'yes but "unusable" quality'], + mp3 => 'n', + opus => 'n', + aac => 'n', + }, + }, + latency => { + name => 'frame size (ms)', + score => { + mp3 => [3, 26, 'typical version and layer has 1152 samples at 44kHz'], + opus => [5, 2.5], + }, + }, + bitrate => { + name => 'minimal bitrate', + score => { + mp3 => [4, 8], + opus => [4, 6], + mpc => [5, 0], + }, + }, + steaming => { + name => 'Streamable', + score => { + mpc => 'y', + }, + }, + seeking => { + name => 'Fast seeking', + score => { + mpc => [5, undef, 'indexed'], + opus => [3, undef, 'bisection seeking (usually 1 physical seek required if implemented correctly)'], + }, + }, + royalties => { + score => { + mp3 => [5, undef, 'expired'], + vorbis => 5, + opus => [4, undef, 'open and free design'], + atrac => [2, undef, 'proprietary, but the original patents have expired'], + mpc => [5, undef, 'open format, bsd licensed implementation'], + }, + }, + support => { + score => { + mp3 => 5, + vorbis => 4, + aac => 4, + opus => 4, + atrac => 1, + }, + }, +}, +} diff --git a/codec-image.inc.pl b/codec-image.inc.pl new file mode 100644 index 0000000..6c138ab --- /dev/null +++ b/codec-image.inc.pl @@ -0,0 +1,561 @@ +use utf8; ++{ +intro => 'Comparison of image encoding formats, based on Cloudinary research.', +keywords => [qw( image picture codec encoder encoding decode compression file format type mime )], +codec => { + jpeg => { + name => 'JPEG', + available => 1992, + generation => 0, + }, + gif => { + name => 'GIF', + available => 1987, + generation => 0, + }, + png => { + name => 'PNG', + available => 1996, + generation => 1, + }, + jp2k => { + name => 'JPEG 2000', + available => 2000, + generation => 1, + }, + webp => { + name => 'WebP', + available => 2010, + generation => 1, + }, + heic => { + name => 'HEIC', + available => 2015, + generation => 2, + }, + avif => { + name => 'AVIF', + available => 2019, + generation => 2, + }, + jxl => { + name => 'JPEG XL', + available => 2021, + generation => 2, + }, + pnm => { + name => 'PNM', + available => 1988, + generation => 0, + }, +}, +feature => { + default => { + children => [qw( quality_photo quality_art speed limits features royalties overhead support web )], + }, + quality_photo => { + name => 'compression (photo)', + score => { + jpeg => 3, + pnm => 'n', + gif => 1, + png => 1, + jp2k => 4, + webp => 3, + heic => 5, + avif => 5, + jxl => 5, + }, + children => [qw( quality_photo_ll quality_photo_3 quality_photo_2 quality_photo_1 quality_thumbs )], + }, + quality_thumbs => { + parent => 'quality_photo', + name => 'thumbnails', + score => { + jpeg => 1, + pnm => 1, + gif => 2, + png => 3, + jp2k => 1, + webp => 2, + heic => 4, + avif => 4, + jxl => 3, + }, + }, + quality_photo_1 => { + parent => 'quality_photo', + name => 'low fidelity', + score => { + jpeg => 2, + pnm => 1, + gif => 1, + png => 1, + jp2k => 3, + webp => 4, + heic => 5, + avif => 5, + jxl => 3, + }, + }, + quality_photo_2 => { + parent => 'quality_photo', + name => 'medium fidelity', + score => { + jpeg => 3, + pnm => 1, + gif => 1, + png => 1, + jp2k => 4, + webp => 3, + heic => 4, + avif => 5, + jxl => 5, + }, + }, + quality_photo_3 => { + parent => 'quality_photo', + name => 'high fidelity', + score => { + jpeg => 3, + pnm => 1, + gif => 1, + png => 2, + jp2k => 4, + webp => 2, + heic => 3, + avif => 4, + jxl => 5, + }, + }, + quality_photo_ll => { + parent => 'quality_photo', + name => 'lossless', + score => { + jpeg => 1, + pnm => 1, + gif => 1, + png => 2, + jp2k => 4, + webp => 3, + heic => 3, + avif => 2, + jxl => 5, + }, + }, + quality_art => { + name => 'compression (other images)', + score => { + jpeg => 2, + pnm => 'n', + gif => 1, + png => 3, + jp2k => 2, + webp => 4, + heic => 3, + avif => 4.5, + jxl => 5, + }, + children => [qw( quality_art_2 quality_art_ll quality_art_mixed )], + }, + quality_art_2 => { + name => 'lossy non-photographic', + score => { + jpeg => 2, + pnm => 1, + gif => 2, + png => 3, + jp2k => 2, + webp => 4, + heic => 3, + avif => 5, + jxl => 5, + }, + }, + quality_art_ll => { + name => 'lossless non-photographic', + score => { + jpeg => 1, + pnm => 1, + gif => 1, + png => 4, + jp2k => 2, + webp => 5, + heic => 2, + avif => 3, + jxl => 5, + }, + }, + quality_art_mixed => { + name => 'mixed photo/nonphoto', + score => { + jpeg => 2, + pnm => 1, + gif => 1, + png => 2, + jp2k => 2, + webp => 3, + heic => 3, + avif => 5, + jxl => 5, + }, + }, + speed => { + score => { + jpeg => 5, + pnm => 5, + gif => 4, + png => 4, + jp2k => 3, + webp => 4, + heic => 3, + avif => 3, + jxl => 5, + }, + children => [qw( speed_encode speed_decode speed_parallel )], + }, + speed_encode => { + parent => 'speed', + name => 'single-core encode', + score => { + jpeg => 5, + pnm => 0, + gif => 3, # palette conversion + png => 3, + jp2k => 4, + webp => 4, + heic => 3, + avif => 2, + jxl => 5, + }, + }, + speed_decode => { + parent => 'speed', + name => 'single-core decode', + score => { + jpeg => 5, + pnm => 0, + gif => 5, + png => 5, + jp2k => 4, + webp => 5, + heic => 3, + avif => 3, + jxl => 5, + }, + }, + speed_parallel => { + parent => 'speed', + name => 'pararellizable', + score => { + jpeg => 2, + pnm => 0, + gif => 2, + png => 2, + jp2k => 4, + webp => 2, + heic => 4, + avif => 4, + jxl => 5, + }, + }, + limits => { + score => { + jpeg => 3, + pnm => 3, + gif => 2, + png => 4, + jp2k => 5, + webp => 2, + heic => 4, + avif => 4.5, + jxl => 5, + }, + children => [qw( max_dimensions max_bitdepth color_444 hdr max_channels )], + }, + max_dimensions => { + parent => 'limits', + name => 'maximum image dimensions', + score => { + jpeg => [3, '65k²'], # 2**16 + pnm => [5, '∞'], + gif => [3, '65k²'], # 2**16 + png => [4, '2G²'], # 2**31 + jp2k => [4, '4G²'], # 2**32 + webp => [1, '16k²'], # 2**14 + heic => [2,'8k×4k+', 'tilable, only 512×512 on Apple'], # 8193x4320 + avif => [3, '65k²+', 'tilable, 7680×4320 with Advanced profile'], # 2**16 + jxl => [4, '1G²'], # 2**30 + }, + }, + max_bitdepth => { + parent => 'limits', + name => 'precision (max. bit depth)', + score => { + jpeg => [2, 8], + pnm => [2, 8, 'unofficial PFM extension for 32-bit'], + gif => [1, 8, '256 colour palette per frame'], + png => [4, 16], + jp2k => [5, 38], + webp => [2, 8], + heic => [3, 10], #TODO 16? + avif => [3, 12, '8, 10, 12 bit'], + jxl => [5, 32, '24-bit integer or 32-bit float'], + }, + }, + color_444 => { + parent => 'limits', + name => 'chroma subsampling', + score => { + jpeg => ['y', undef, '4:2:0, 4:2:2, 4:4:4'], + pnm => [4, '✘'], + gif => [4, '✘'], + png => [4, '✘'], + jp2k => 'y', + webp => [1, '4:2:0'], + heic => [1, '4:2:0'], + avif => ['y', undef, '4:2:0, 4:2:2, 4:4:4'], + jxl => ['y', undef, 'for JPEG compatibility'], + }, + }, + hdr => { + parent => 'limits', + name => 'wide gamut/HDR', + score => { + jpeg => 'n', + pnm => 'n', + gif => 'n', + png => 'y', + jp2k => 'y', + webp => 'n', + heic => 'y', + avif => 'y', + jxl => 'y', + }, + }, + max_channels => { + parent => 'limits', + name => 'maximum number of channels', + score => { + jpeg => [3, 4, 'RGB or CMYK'], + pnm => [3, 3, 'RGB'], + gif => [3, 3, 'RGB palette'], + png => [3, 4, 'RGBA'], + jp2k => [5, 2**15], + webp => [3, 4, 'RGBA'], + heic => [3, 3, 'RGB, separate alpha and depth'], + avif => [3, 3, 'RGB, separate alpha and depth'], + jxl => [4, 4099, 'native XYB'], + }, + }, + features => { + score => { + jpeg => 2, + pnm => [2, undef, 'great for simplicity and ASCII storage'], + gif => 2, + png => 3, + jp2k => 4, + webp => 2, + heic => 4, + avif => 4, + jxl => 5, + }, + children => [qw( animation progressive alpha depthmap overlays vector authoring reencode compat_jpeg )], + }, + animation => { + parent => 'features', + name => 'supports animation', + score => { + jpeg => [2, 'MJPEG'], + pnm => 'n', + gif => 'y', + png => [4, 'APNG', 'later backwards-compatible extension'], + jp2k => [2, 'MJP2'], + webp => 'y', + heic => 'y', + avif => 'y', + jxl => 'y', + }, + }, + progressive => { + parent => 'features', + name => 'progressive decoding', + score => { + jpeg => 4, + pnm => 'n', + gif => 2, + png => 2, + jp2k => 5, + webp => 'n', + heic => 'n', + avif => 'n', + jxl => 5, + }, + }, + vector => { + parent => 'features', + name => 'vector drawing', + score => { + jpeg => 'n', + pnm => 'n', + gif => 'n', + png => 'n', + jp2k => 'n', + webp => 'n', + heic => 'n', + avif => 'n', + jxl => [2, undef, 'splines'], + }, + }, + alpha => { + parent => 'features', + name => 'alpha transparency', + score => { + jpeg => 'n', + pnm => ['n', undef, 'PAM extension'], + gif => [3, '1 bit'], + png => 'y', + jp2k => 'y', + webp => 'y', + heic => 'y', + avif => 'y', + jxl => 'y', + }, + }, + depthmap => { + parent => 'features', + name => 'depth map', + score => { + jpeg => 'n', + pnm => 'n', + gif => 'n', + png => 'n', + jp2k => 'n', + webp => 'n', + heic => 'y', + avif => 'y', + jxl => 'y', + }, + }, + overlays => { + parent => 'features', + name => 'overlays (layers)', + score => { + jpeg => 'n', + pnm => 'n', + gif => 'y', + png => 'n', + jp2k => 'n', + webp => 'n', + heic => 'y', + avif => 'y', + jxl => 'y', + }, + }, + authoring => { + parent => 'features', + name => 'authoring workflow suitability', + score => { + jpeg => 2, + pnm => 2, + gif => 2, + png => 3, + jp2k => 3, + webp => 2, + heic => 2, + avif => 2, + jxl => 5, + }, + }, + reencode => { + parent => 'features', + name => 'generation loss resilience', + score => { + jpeg => 4, + pnm => 0, + png => 0, + gif => 0, + jp2k => 3, + webp => 2, + heic => 3, + avif => 3, + jxl => 4, + }, + }, + compat_jpeg => { + parent => 'features', + name => 'lossless JPEG recompression', + score => { + jpeg => 0, + pnm => 'n', + gif => 'n', + png => 'n', + jp2k => 'n', + webp => 'n', + heic => 'n', + avif => 'n', + jxl => 'y', + }, + }, + royalties => { + name => 'royalty-free', + score => { + jpeg => 5, + pnm => 5, + gif => [5, undef, 'patented before 2003'], + png => 5, + jp2k => [3, undef, 'ISO specification not freely available'], + webp => [4, undef, 'free format, low remaining risk of patent trolls'], + heic => ['n', undef, 'heavily patented'], + avif => [4, undef, 'free format, risk of patent trolls'], + jxl => [4, undef, 'free format, risk of patent trolls'], + }, + children => [], + }, + web => { + name => 'browser support', + score => { + jpeg => [5, undef, 'ubiquitous since first inline images (1993)'], + pnm => [1, undef, 'rarely by (unix) systems'], + xbm => [2, undef, 'common before 200X'], + gif => [5, undef, 'predates the web, but unrestricted since 2004'], + png => [5, undef, 'problematic prior to IE7, currently ubiquitous'], + jp2k => [2, undef, 'just Safari'], + webp => [4, undef, 'widespread since 2020'], + heic => [1, undef, 'no browser support'], + avif => [3, undef, 'significant since 2021 (Safari 2023, no Edge yet)'], + jxl => [2, undef, 'experimental, blocked by chrome'], + }, + }, + support => { + name => 'adoption', + score => { + jpeg => [5, undef, 'standard photography'], + pnm => [2, undef, 'uncomplicated bitmap interchange'], + gif => [4, undef, 'declining due to limitations'], + png => [5, undef, 'standard illustrations'], + jp2k => [3, undef, 'limited beyond Apple'], + webp => [4, undef, 'mostly online'], + heic => [2, undef, 'stored by latest cameras, interchange unlikely'], + avif => [3, undef, 'upcoming'], + jxl => [2, undef, 'ongoing'], + }, + }, + overhead => { + name => 'container overhead (file size)', + score => { + png => [3, 67, 'upto 70 bytes for specific RGBA'], + jpeg => [2, 160, '159 bytes minimum for gray, 288 for specific colours'], + gif => [4, 35, '43 bytes for transparent'], + webp => [4, 34, 'black or transparent lossless; 44-92 bytes lossy'], + bpg => [4, 31, 'lossy 29-62 bytes, lossless 37-160'], + flif => [5, 14, 'black or transparent; 20 bytes for specific RGBA'], + pnm => [5, 8, 'monochrome text PBM; 12 bytes PPM; 69 bytes PAM'], + jxl => [5, 12, '512×256 black pixels'], + avif => [1, 282, 'container overhead; 457 bytes with alpha'], + jp2k => [2, 123, 'experimental results, likely not optimal'], + heic => [1, 386], + }, + }, +}, +} diff --git a/codec.plp b/codec.plp new file mode 100644 index 0000000..f13b93a --- /dev/null +++ b/codec.plp @@ -0,0 +1,76 @@ +<(common.inc.plp)><: + +my ($page, @feat) = split m{/+}, $Request || 'image'; +$page !~ /\W/ or Html(), Abort('Invalid codec type request', 400); +@feat or @feat = 'default'; +my $title = "$page codecs"; +my $info = eval { Data("codec-$page") }; +if ($@) { + $info = {}; +} + +Html({ + title => "$title cheat sheet", + version => '1.1', + description => $info->{intro}, + keywords => [@{ $info->{keywords} // [] }, qw' feature comparison support benchmark '], + stylesheet => [qw'light circus dark red'], + data => ["codec-$page.inc.pl"], + raw => '', +}); + +%{$info} + or Abort("Requested codec type $page not available", '404 request not found'); + +say "

\u$title

"; +say "

$_

" for $info->{intro} // (); + +my %BOOLSCORE = (y => [5, '✔'], n => [1, '✘'], 0 => [0, 'n/a']); +:> + +
+ +<: +my @codecs = sort { + $info->{codec}->{$a}->{available} <=> $info->{codec}->{$b}->{available} +} keys $info->{codec}->%*; +my @codeccols = @{$info->{codec}}{@codecs}; + +{ + print ''; + my @spans; + $spans[ $_->{generation} ]++ for @codeccols; + print "" for @spans; +} +say ''; +print ''; + +while (defined (my $feat = shift @feat)) { + my $featinfo = $info->{feature}->{$feat} or next; + unshift @feat, @{$_} for $featinfo->{children} // (); + $featinfo->{score} or next; + print '' if $featinfo->{children}; + printf ''; +} + +:>
'; +say "\t", '', $_->{name} for @codeccols; +print '
', $_->{available} for @codeccols; +say '
%s', $featinfo->{name} // $feat; + for (@codecs) { + my ($score, $data, $title) = map { ref ? @$_ : $_ } $featinfo->{score}->{$_}; + if (not defined $data) { + if (my $override = $BOOLSCORE{$score}) { + ($score, $data) = @{$override}; + } + else { + $data = '•' x ($score - 1); + } + } + printf '', $data; + } + say '
+
+ diff --git a/common.inc.plp b/common.inc.plp index 68ada33..a634733 100644 --- a/common.inc.plp +++ b/common.inc.plp @@ -1,5 +1,6 @@ <: use 5.014; +use strict; use utf8; use warnings; no warnings 'qw'; # you know what you doing @@ -10,42 +11,45 @@ use File::stat 'stat'; use HTTP::Date; use Encode qw( decode_utf8 ); +our $Dev; + sub Alert { my ($html, $debug) = @_; ref $html eq 'ARRAY' or $html = [$html]; my ($title, @lines) = @{$html}; - $body = "

$title

"; + my $body = "

$title

"; $body .= "\n

$_

" for @lines; $body .= "\n
$debug
" if $Dev and $debug; say "
$body
\n"; } +sub Abort { + my ($html, $code, $debug) = @_; + unless ($PLP::sentheaders) { + $header{Status} = $code || 500; + } + elsif ($Dev) { + ref $html eq 'ARRAY' or $html = [$html]; + push @{$html}, "Also failed to set HTTP status $code" + . " after output!"; + } + Alert($html, $debug); + exit; +} + BEGIN { require Time::HiRes; our $Time = [Time::HiRes::gettimeofday()]; - $PLP::ERROR = sub { - my ($text, $html) = @_; - warn $text; - unless ($PLP::sentheaders and $PLP::sentheaders->[0] !~ m{/PLP\.pm$}) { - Html({nocache => 1}); - say '

Page unavailable

'; - } - Alert("Fatal error: $html."); - }; - push @INC, '.'; # user request our $Dev = $ENV{HTTP_HOST} =~ /\bdev\./; - our ($file) = $ENV{SCRIPT_FILENAME} =~ m{ ([^/]+) \.plp$ }x; } -our $Request = decode_utf8($ENV{PATH_INFO} =~ s{^/}{}r); +our $Request //= decode_utf8($ENV{PATH_INFO} =~ s{^/}{}r); our $style; -our $showkeys = !exists $get{keys} ? undef : - ($get{keys} ne '0' && ($get{keys} || 'always')); $header{content_type} = 'text/html; charset=utf-8'; @@ -72,7 +76,7 @@ sub stylesheet { return map { sprintf( '', - $_ eq $style ? 'stylesheet' : 'alternate stylesheet', "/$_.css?1.10", $_ + $_ eq $style ? 'stylesheet' : 'alternate stylesheet', "/$_.css?1.18", $_ ) } @avail; } @@ -93,6 +97,24 @@ sub checkmodified { $header{'Last-Modified'} = time2str($lastmod); } +sub Data { + my ($filename) = @_; + my @data = eval { + open my $cache, '<:raw', "data/$filename.json" + or return do "./$filename.inc.pl"; # silent fallback to original code + require JSON; + local $/; # slurp + return JSON::decode_json(readline $cache); + }; + if ($@ or !@data or !$data[0]) { + die ['Table data not found', $@ || $!]; + } + if (@data == 1 and ref $data[0] eq 'HASH' and not %{$data[0]}) { + die ['Table data missing']; + } + return wantarray ? @data : $data[0]; # list compatibility like do does +} + sub Html { my ($meta) = @_; @@ -109,6 +131,7 @@ sub Html { # default fallbacks $meta->{stylesheet} ||= [qw( light dark circus mono red )]; $meta->{charset} ||= 'utf-8'; + $meta->{lang} ||= 'en'; # convert options to arrays ref $_ eq 'ARRAY' or $_ = [$_] @@ -117,51 +140,61 @@ sub Html { # document headers before output $header{content_type} = "text/html; charset=$meta->{charset}" unless $PLP::sentheaders; + exit if $ENV{REQUEST_METHOD} eq 'HEAD'; unshift @{ $meta->{raw} }, stylesheet($meta->{stylesheet}); push @{ $meta->{raw} }, ( - '', + '', ); - # optional amends - push @{ $meta->{raw} }, ( - '', - '', - !$showkeys ? '' : - $showkeys eq 'ghost' ? '' : (), - '', - ) if $meta->{keys}; - - # leading output - say ''; - say ''; - say ''; - say ''; - say sprintf '', $_ - for $header{content_type}; - say sprintf '%s', $meta->{title}; - say sprintf '', EscapeHTML($_) - for join(' ', @{ $meta->{description} }) || (); - say sprintf '', EscapeHTML($_) - for join(', ', @{ $meta->{keywords} }) || (); - say ''; - say ''; - say for map { @{$_} } $meta->{raw} || (); - say '' if $Dev; - say ''; - say ''; - say sprintf '', $file; - - # development version indicator - printf '

beta

', join('; ', - 'position: fixed', - 'right: 1em', - 'opacity: .5', - 'border: 1ex solid red', - 'border-width: 1ex 0', - 'z-index: 1', - 'background: inherit', - ) if $Dev; + if (my $img = $meta->{image}) { + my $proto = sprintf('http%s://', !!$ENV{HTTPS} && 's'); + my $url = "$proto$ENV{HTTP_HOST}/$img"; + push @{ $meta->{raw} }, ( + qq(), + ); + } + + my ($file) = $ENV{SCRIPT_FILENAME} =~ m{ ([^/]+) \.plp$ }x; + + $meta->{canonical} //= "/$file" . ($Request ne '' && "/$Request"); + if (my $url = $meta->{canonical}) { + $url = "https://sheet.shiar.nl$url"; + push @{ $meta->{raw} }, qq(); + } + + PLP_START { + # leading output + say ''; + say qq(); + say ''; + say ''; + say sprintf '', $_ + for $header{content_type}; + say sprintf '%s', $meta->{title}; + say sprintf '', EscapeHTML($_) + for join(' ', @{ $meta->{description} // [] }) || (); + say sprintf '', EscapeHTML($_) + for join(', ', @{ $meta->{keywords} // [] }) || (); + say ''; + say ''; + say for map { @{$_} } $meta->{raw} || (); + say '' if $Dev; + say ''; + say ''; + say sprintf '', $file; + + # development version indicator + printf '

beta

', join('; ', + 'position: fixed', + 'right: 1em', + 'opacity: .5', + 'border: 1ex solid red', + 'border-width: 1ex 0', + 'z-index: 1', + 'background: inherit', + ) if $Dev; + }; # prepare trailing output PLP_END { @@ -176,6 +209,7 @@ sub Html { title="Licensed under the GNU Affero General Public License, version 3" rel="license">AGPLv3 EOT + our $Time; say sprintf '• %.3fs', Time::HiRes::tv_interval($Time) if $Dev and $Time; say '

'; say ''; @@ -183,12 +217,30 @@ EOT }; } +BEGIN { + $PLP::ERROR = sub { + my ($message, $html) = @_; + if (ref $message) { + warn join ': ', @{$message}; + $html = shift @{$message}; + } + else { + warn $message; + $message = []; + } + unless ($PLP::sentheaders) { + Html({nocache => 1}); + say '

Page unavailable

'; + } + Alert("Fatal error: $html.", @{$message}); + }; +} + sub showlink { my ($title, $href, $selected) = @_; - return sprintf( - !$href ? '%s' : - $selected ? '%s' : '%s', - EscapeHTML($title), EscapeHTML($href) - ); + EscapeHTML($title); + return $title if not $href; + return "$title" if $selected; + return sprintf '%s', EscapeHTML($href), $title; } diff --git a/countries.plp b/countries.plp index 1ed8eef..efd2f25 100644 --- a/countries.plp +++ b/countries.plp @@ -14,10 +14,10 @@ Html({

ISO-3166-1α2 Country codes

<: -my $cc = do 'data/countries.inc.pl'; +my $cc = Data('data/countries'); { - printf ''; + printf '
'; print ''; for my $section (qw{thead}) { print "<$section>
↳"; @@ -46,7 +46,7 @@ my $cc = do 'data/countries.inc.pl'; } $cell = showflag($code) // join(' ', - map { showflag($_) || $_ } split / /, $ref + map { showflag($_) || $_ } split(/ /, $ref) ); } else { @@ -89,3 +89,26 @@ my $cc = do 'data/countries.inc.pl'; +<: exit unless exists $get{v}; :> + + diff --git a/dark.css b/dark.css index 6cb893f..e7df58b 100644 --- a/dark.css +++ b/dark.css @@ -1,4 +1,4 @@ -@import url(light.css?1.10); +@import url(light.css?1.11); body { background: #000; @@ -108,6 +108,83 @@ th, td { .legend .ex:hover {background: #666} .X:hover small {color: #FFF} +/* images */ + +figcaption { + color: #FFF; + background: rgba(0, 0, 0, .5); +} +.gallery figure:hover ~ ul figcaption { + /* mark all children */ + color: #000; + background: rgba(255, 255, 255, .5); +} + +/* starcraft */ + +.units tbody tr:hover:not(.race) { + background: #222; +} +.unit-gas { + color: #AC9; +} +.unit-min, .unit-min a:not(:hover) { + color: #ABC; +} +.unit-supply { + color: #8C6; +} +.unit-o {color: #C5A} /* organic */ +.unit-u {color: #66B} /* mechanic */ +.unit-p {color: #0A8} /* psionic */ +.unit-composed { + color: #A44; +} +.unit-air { + color: #4AC; +} +.unit-x {color: #666} +.unit-s {color: #AC6} +.unit-m {color: #C70} +.unit-l {color: #C44} +.unit-h {color: #C06} +.magic-opt:before, +.magic-opt:after { + color: #CCC; +} +.hurtrel, .units .hurtrel { + color: #887; +} +tbody .unit-shield { + color: #88A; +} +.unit-pdd { + color: #A8C; +} +.unit-splash { + color: #4A0; +} +.hurt-a { + color: #8AC; +} +.hurt-g { + color: #8CA; +} +.unit-massive { + color: #844; +} +.unit-detect::before { + color: #0A8; +} +.unit-jump { + color: #780; +} +body .magic-perma { + text-decoration-color: #460; + -moz-text-decoration-color: #460; + -webkit-text-decoration-color: #460; +} + /* keyboard */ @media (max-width: 79em) { diff --git a/darklite.css b/darklite.css index b704627..7f5c113 100644 --- a/darklite.css +++ b/darklite.css @@ -1,4 +1,4 @@ -@import url(dark.css?1.10); +@import url(dark.css?1.11); th, td { border-color: #333; diff --git a/dieren.inc.pl b/dieren.inc.pl new file mode 100644 index 0000000..169fb81 --- /dev/null +++ b/dieren.inc.pl @@ -0,0 +1,30 @@ +#!/bin/env perl +use 5.014; +use warnings; +use utf8; + +[map {[split ' ']} grep {$_} split /\n/, <<'.']; + : origineel: zee-: meer_water: land/aardig: anders: #: + hond: +hond +zeehond ?scheepshond +prairiehond vleerhond #rodehond + kat: +kat +zeekat +meerkat ?cat_325 vliegende_kat #tijgerkat +#haas: haas zeehaas waterhaas ?koolhaas ?ossenhaas #buidelhaas + muis: +muis +zeemuis waterspitsmuis aardmuis +vleermuis #computermuis + rat: rat zeerat waterrat woestijnrat buidelrat #beverrat + egel: +egel +zee-egel ?wateregel ?aardegel?=cactus +mierenegel #kegel + varken: +varken +zeevarken=bruinvis waterzwijn=capibara aardvarken +stekelvarken #feestvarken + koe: +koe +zeekoe +meerkoetje ?aardekoe? koedoe #haiku + paard: +paard +zeepaardje +nijlpaard ?grasmodderpaard=草泥马#?(turn)paard luipaard #tijgerpaard +#hoorn: eenhoorn zeehoorn ?zee-eenhoorn=narwal bergahorn=esdoorn neushoorn #eekhoorn +#bra: ?bra(ssière) zebra - - cobra #sabra +#olifant: +olifant +zeeolifant +olifantsvis ?kamerolifant - #olifantsoor + beer: +beer +zeebeer waterbeertje ijsbeer +wasbeer #neusbeer + leeuw: +leeuw +zeeleeuw ?waterleeuw? ?aardleeuw?=kameleon +mierenleeuw #leeuwerik +#vos: vos +zeevos=voshaai - koolvos voskonijn #Zorro + wolf: +wolf +zeewolf ?waterwolf?=snoek aardwolf +korenwolf #bijenwolf + haan: +haan +zeehaan waterhaan rotshaan +sprinkhaan #wilde_haan?=wildrooster +#pad: pad ?zebrapad rivierdonderpad landpad schildpad #paddenstoel + draak: draak_#draak zeedraak waterdraak=agame ?aarddraak=戊辰 komododraak=varaan #drakenkop +#vlo: vlo zeevlo watervlo aardvlo - #vlok +#mot: +mot +marmot watermot +bergamot ?behemoth # +#bij: bij - waterbij aardbei moerbei #hommelbij +. diff --git a/dieren.jpg b/dieren.jpg new file mode 100644 index 0000000..a4d0104 Binary files /dev/null and b/dieren.jpg differ diff --git a/dieren.plp b/dieren.plp new file mode 100644 index 0000000..8e66008 --- /dev/null +++ b/dieren.plp @@ -0,0 +1,146 @@ +<(common.inc.plp)><: +use warnings; +no warnings 'qw'; + +my $intro = 'dieren die in het Nederlands vernoemd zijn naar andere dieren.'; +my %subpages = ( + standaard => { + title => 'dieren', + intro => $intro, + altlink => 'Zie ook verdergezochte verbanden' . + ' of het beknopte overzicht.', + prefix => qr/^(?!#)\+?/, # no # optional + + colfilter => 0, + }, + uitgebreid => { + title => 'uitgebreid dieren', + intro => "$intro.. en dergelijke.", + altlink => 'Zie het populaire overzicht voor minder.', + prefix => qr/.*?[#]|^[#+]*/, # after optional # or + + secrets => 1, + }, + beknopt => { + title => 'beknopt dieren', + intro => "een aantal $intro", + altlink => 'Zie het populaire overzicht voor meer.', + prefix => qr/^\+/, # only + + colfilter => 1, + }, +); + +$Request ||= 'standaard'; +my $pageinfo = $subpages{$Request} + or Html(), Abort("Onbekende dierenpagina $Request", '404 request not found'); + +Html({ + title => $pageinfo->{title}.' cheat sheet', + version => '1.2', + lang => 'nl', + description => "Tabeloverzicht met afbeeldingen van $pageinfo->{intro}", + keywords => [qw' + dier beest naam naamgeving woord taal nederlands gerelateerd + relatie vernoemd vernoeming combinatie samenstelling voorvoegsel onverwant + land zee lucht animals dutch language + '], + image => 'dieren.jpg', + raw => <<"EOT", + +EOT +}); + +:> +

Dierennamen (Dutch animal names)

+ +

+<: +say ucfirst $pageinfo->{intro}; +say $pageinfo->{altlink}; +:> +

+ +<: +my $table = Data('dieren'); + +if (exists $get{r}) { + use List::MoreUtils qw( part ); + my @trans = (part { state $col; /^#?>/ ? ($col = 0) : ++$col } @{$table}); + $table = []; + for (@trans) { + unshift @$_, '?:' if $_->[0] !~ /:$/; + $_->[0] =~ s/^#?\K>?/>>/; + for (@$_) { + push @$table, s/^#?\K>/$1/r; + } + } +} + +for my $prefix ($pageinfo->{prefix}) { + for my $col ($pageinfo->{colfilter} // ()) { + @{$table} = grep { $_->[$col] =~ $prefix } @{$table}; + } + $_ = [ grep { s/$prefix// } @{$_} ] for @{$table}; +} + +say ''; +for my $row (@{$table}) { + print ''; + for my $name (@{$row}) { + my $hidden = $name =~ s/^\?//; + $name =~ s/#.*//; # ignore prefixed part + $name =~ s/^-$//; + my ($img) = $name =~ /([\w-]+)/; + $name =~ y/_/ /; + if ($name =~ s/:$//) { + # trailing colon indicates header text + print ""; + next; + } + print ''; + } + say ''; +} +say ''; diff --git a/digits.plp b/digits.plp index a6a684e..a55b49a 100644 --- a/digits.plp +++ b/digits.plp @@ -37,11 +37,10 @@ unless (exists $get{v}) { $glyphs->{style} = 'univer'; } -my $scriptname = do 'writing-script.inc.pl'; +my $scriptname = eval { Data('writing-script') }; $_ = showlink($_, "/latin") for $scriptname->{latn} || (); -my $table = do "writing-digits.inc.pl"; -die "Table data not found: $_\n" for $@ || $! || (); +my $table = Data("writing-digits"); sub printtable { say '
', $glyphs->tabletag; diff --git a/digraphs.plp b/digraphs.plp index 5e4a334..9f96c50 100644 --- a/digraphs.plp +++ b/digraphs.plp @@ -1,51 +1,40 @@ <(common.inc.plp)><: -my $mode = ($Request // '') eq 'xorg' || exists $get{xorg}; -my $modename = $mode ? 'X.Org' : 'RFC-1345'; +my $mode = $Request || 'vim'; +my $include = 'digraphs' . ($mode ne 'vim' && "-$mode"); +my $cmp = exists $get{cmp} ? ($get{cmp} // 1) : !!$Request; + +my $di = eval { Data($include) } || {}; +warn "error in $include: ", @{$@} if ref $@; Html({ - title => 'digraph cheat sheet', - version => '1.2', - description => [ - "Complete table of digraph characters from $modename.", + title => "$mode digraph cheat sheet", + version => '1.4', + description => $di->{description} // [ + "Complete table of digraph characters from", + ($di->{title} // $mode) . ".", ], - keywords => [qw' + keywords => [@{ $di->{keywords} // [] }, qw' digraph mnemonic compose composition pair - character char glyph table unicode vim xorg x11 x + character char glyph table unicode vim '], stylesheet => [qw'light'], - data => [qw( data/digraphs.inc.pl )], + data => ["data/$include.json"], }); -:> -

<:= $modename :> Digraphs

- -

Character mnemonics following compose key ⎄<: -say join("\n", - $mode ? ( - ' in the X Window System (Shift+AltGr by default).', - 'Differences from RFC-1345 are indicated.', - ) : (':', - 'i^k in Vim,', - '^u^\ in Emacs,', - '^a^v in Screen.', - 'Similar but different from X.Org.', - ), - 'Also see common Unicode.

', +%{$di} or Abort( + "Requested digraphs $mode not available", + '404 request not found', ); -say '

Unofficial proposals', - ' are available as ex commands.' if not $mode; -:> -<: -my $di = do 'data/digraphs.inc.pl' - or die "Error loading digraphs data: ", $@ // $!; +say "

$di->{title} Digraphs

"; +say "

$_

" for $di->{intro} // (); if (exists $get{v}) { # show characters for inverted mnemonics (vim alternatives) - $di->{ substr($_, 1, 1) . substr($_, 0, 1) } ||= - [ $di->{$_}->[0], '', 'l0 ex', '', $di->{$_}->[4] ] - for grep { ref $di->{$_} } keys %{$di}; + $di->{key}->{ substr($_, 1, 1) . substr($_, 0, 1) } ||= [ + $di->{key}->{$_}->[0], '', 'l0 ex', '', $di->{key}->{$_}->[4] + ] for grep { ref $di->{key}->{$_} } keys %{ $di->{key} }; } my @chars = ( @@ -58,36 +47,10 @@ my @chars2 = (['_'], @chars); # trailing character (extended set) my @columns = !exists $get{split} ? \@chars2 : ([@chars2[0, 1, 3, 4, 6]], [@chars2[2, 5, 7]]); -if ($mode) { - my $xorg = do 'data/digraphs-xorg.inc.pl' - or die "Error loading Xorg data: ", $@ // $!; - $_ = [ord $_] for values %{$xorg}; - $xorg->{$_}->[2] = # class = compatibility - $di->{$_} ? $di->{$_}->[0] != $xorg->{$_}->[0] ? 'l1' : # conflict - $di->{$_}->[2] eq 'l4' ? 'l5' : 'l3' : 'l2' # rfc|any|none - for keys %{$xorg}; - - for my $cp (map {$_->[0]} values %{$xorg}) { - next if (state $seen = {})->{$cp}++; # List::MoreUtils::uniq - - # find multiple equivalent mnemonics - my @equiv = grep {$cp eq $_->[0]} - map {$xorg->{$_}} sort keys %{$xorg}; # values ordered by mnem. - - # search for the most compatible match - my ($compat) = sort { - $equiv[$b]->[2] cmp $equiv[$a]->[2] # highest level - || $b <=> $a # fallback to last mnemonic - } 0 .. $#equiv; - - # reclassify all but one as level 0 (omitted) - splice @equiv, $compat // -1, 1, (); - $_->[2] = 'l0 ex' for @equiv; - } - +if ($mode eq 'xorg') { + #TODO determine character usage from declared keys $chars2[0] = [qw( # ^ _ ` ~ )]; @chars = @chars2; - $di = $xorg; } for my $colchars (@columns) { @@ -105,21 +68,23 @@ for my $c1group (@chars) { print '
', EscapeHTML($c1); for my $c2 (map {@$_} @$colchars) { my $mnem = $c1 . $c2; - if (not defined $di->{$mnem}) { + if (not defined $di->{key}->{$mnem}) { print ''; next; } - if (ref $di->{$mnem} ne 'ARRAY') { + if (ref $di->{key}->{$mnem} ne 'ARRAY') { printf '', EscapeHTML($mnem); next; } - my ($codepoint, $name, $support, $script, $string) = @{ $di->{$mnem} }; + my ($codepoint, $name, $support, $script, $string) = + @{ $di->{key}->{$mnem} }; - my $glyph = $string || chr $codepoint; + my $glyph = $string || !!$codepoint && chr $codepoint; utf8::upgrade($glyph); # prevent latin1 output my $desc = $mnem . ($name && " ($name)"); my @class = ('X', grep {$_} $script); - push @class, $mode ? $support : "u-$support" if $support; + push @class, $cmp ? $support : + $di->{flagclass}->{$support} // "u-$support" if $support; $glyph = EscapeHTML($glyph); $glyph = "$glyph" if $script =~ /\bZs\b/; @@ -134,19 +99,8 @@ say '
'; print '
' if exists $get{split}; } -if ($mode) { :> -
- -
matching RFC-1345 - matching proposal - unique to Xorg - conflict - duplicate -
-
-<: } else { :> -
+
<: unless ($cmp) { :>
control space @@ -167,14 +121,11 @@ if ($mode) { japanese chinese
- - - ', $id; my $th = 'th'; @@ -109,11 +112,9 @@ else { say; } } - say "
full support - vim extension - vim v8.0 - proposal - not in vim +<: } :> + <: + printf qq(\n\t
%s), $cmp ? $_ : $di->{flagclass}{$_} // "u-$_", $di->{flag}->{$_} + for sort keys %{ $di->{flag} }; +:>
-<: } diff --git a/digraphs.vim.plp b/digraphs.vim.plp index 9883031..c659288 100644 --- a/digraphs.vim.plp +++ b/digraphs.vim.plp @@ -6,7 +6,7 @@ use open IO => ':utf8'; our $VERSION = 'v1.0'; $header{content_type} = 'text/plain; charset=us-ascii'; -say '" vim digraph proposals '; +say '" vim digraph proposals '; PLP_END { print "\n" }; open my $include, '<', 'shiar.inc.txt' or do { diff --git a/emoji-gmail.inc.pl b/emoji-gmail.inc.pl index 74ab939..34972f3 100644 --- a/emoji-gmail.inc.pl +++ b/emoji-gmail.inc.pl @@ -1,55 +1,50 @@ { name => 'Gmail', - icon => 'http://mail.google.com/mail/help/images/screenshots/chat/%s.gif', - iconext => 'http://usefulshortcuts.com/imgs/gtalk-hidden/%s.gif', + icon => '/data/emoji/gmail/%s.gif', + iconext => '/data/emoji/gmail/%s.png', source => 'http://mail.google.com/support/bin/answer.py?answer=34056', }, 'official', -heart => ['<3', '', 0x02665, "heart/love"], -monkey => [':(|)', '', 0x1F435, "it's a monkey!"], -rockout => ['\m/', 'fuzzy', 0x0270A, "rock out."], -shocked => [':-o', '', 0x1F632, "shocked"], -grin => [':D', '', 0x1F603, "grin"], -frown => [':(', '', 0x02639, "frown"], -angry => ['x-(', '', 0x1F623, "angry"], -cool => ['B-)', '', 0x1F60E, "cool"], -cry => [":'(", '', 0x1F622, "cry"], -equal_grin => ['=D', '', 0, "equal grin"], -wink => [';)', '', 0x1F609, "wink"], -straightface => [':-|', '', 0x1F610, "straight face"], -equal_smile => ['=)', '', 0, "equal smile"], -nose_grin => [':-D', '', 0, "nose grin"], -wink_big_nose => [';^)', '', 0, "big nose wink"], -wink_nose => [';-)', '', 0, "nose wink"], -nose_smile => [':-)', '', 0, "nose smile"], -slant => [':-/', 'fuzzy', 0x1F616, "slant"], -tongue => [':P', '', 0x1F61D, "tongue"], +[heart => '<3', '', 0x02665, "heart/love"], +[monkey => ':(|)', '', 0x1F435, "it's a monkey!"], +[rockout => '\m/', '', 0x1F918, "rock out."], +[shocked => ':-o', '', 0x1F632, "shocked"], +[grin => ':D', '', 0x1F603, "grin"], +[nose_grin => ':-D', '', 0, "nose grin"], +[equal_grin => '=D', '', 0, "equal grin"], +[frown => ':( :-( =(', '', 0x02639, "frown"], +[angry => 'x-(', '', 0x1F623, "angry"], +[cool => 'B-)', '', 0x1F60E, "cool"], +[cry => ":'(", '', 0x1F622, "cry"], +[wink => ';)', '', 0x1F609, "wink"], +[wink_nose => ';-)', '', 0, "nose wink"], +[wink_big_nose => ';^)', 'fuzzy', 0x1F925, "big nose wink"], +[straightface => ':-|', '', 0x1F610, "straight face"], +[equal_smile => '=)', '', 0, "equal smile"], +[nose_smile => ':-)', '', 0, "nose smile"], +[slant => ':-/ =/', 'fuzzy', 0x1F616, "slant"], +[tongue => ':P :-P =P', '', 0x1F61D, "tongue"], # http://tkhere.blogspot.com/2007/12/brand-new-google-chat-emoticons-no-one.html 'undocumented', -cowbell => ["+/'\\", '', 0x1F514, "cowbell"], -crab => ['V.v.V', 'ext', 0, "crab"], -devil => ['}:-)', 'ext', 0x1F608, "devil"], -frown => ['=(', '', 0, "equal sad"], -slant => ['=/', '', 0, "equal slant"], -tongue => ['=P', '', 0, "equal tongue"], -frown => [':-(', '', 0, "nose sad"], -smile => [':)', '', 0x0263A, "smile"], -wince => ['>.<', 'ext', 0, "wince"], -tongue => [':-P', '', 0, "nose tongue"], -pig => [':(:)', 'ext', 0x1F437, "pig"], -brokenheart => [' [':-x', 'ext', 0x1F618, "kiss"], -kissstar => [':*', 'ext', 0x1F61A, "kiss"], -mustache => [':{', 'ext', 0, "mustache"], +[cowbell => "+/'\\", '', 0x1F514, "cowbell"], +[crab => 'V.v.V', 'ext', 0x1F980, "crab"], +[devil => '}:-)', 'ext', 0x1F608, "devil"], +[smile => ':)', '', 0x0263A, "smile"], +[wince => '>.<', 'ext', 0x1F623, "wince"], +[pig => ':(:)', 'ext', 0x1F437, "pig"], +[brokenheart => ' ':-x', 'ext', 0x1F618, "kiss"], +[kissstar => ':*', 'ext', 0x1F61A, "kiss"], +[mustache => ':{', 'ext fuzzy', 0x1F978, "mustache"], # http://www.gtricks.com/google-talk-tricks/google-talk-hidden-emoticons/ -robot => ['[:|]', 'ext', 0], -poo => ['~@~', 'ext', 0x1F4A9], +[robot => '[:|]', 'ext', 0x1F916], +[poo => '~@~', 'ext', 0x1F4A9], -# vi:ts=15 +# vi:ts=16 diff --git a/emoji-msn.inc.pl b/emoji-msn.inc.pl index a0064a8..d2a7c29 100644 --- a/emoji-msn.inc.pl +++ b/emoji-msn.inc.pl @@ -6,80 +6,80 @@ 'faces', -regular_smile => [':-) :)', '', 0x0263A, "smile"], -teeth_smile => [':-D :d', '', 0x1F603, "open-mouthed"], -omg_smile => [':-O :o', '', 0x1F632, "surprised"], -tongue_smile => [':-P :p', '', 0x1F61C, "tongue out"], -wink_smile => [';-) ;)', '', 0x1F609, "wink"], -sad_smile => [':-( :(', '', 0x02639, "sad"], -confused_smile => [':-S :s', '', 0x1F616, "confused"], -what_smile => [':-| :|', '', 0x1F61E, "disappointed"], -cry_smile => [":'(", '', 0x1F62D, "crying"], -red_smile => [':-$ :$', '', 0x1F633, "embarrassed"], -shades_smile => ['(H) (h)', '', 0x1F60E, "hot"], -angry_smile => [':-@ :@', '', 0x1F620, "angry"], -angel_smile => ['(A) (a)', '', 0x1F607, "angel"], -devil_smile => ['(6)', '', 0x1F608, "devil"], -'47_47' => [':-#', 'fuzzy', 0x1F64A, "don't tell anyone"], -'48_48' => ['8o|', 'todo', 0, "baring teeth"], -'49_49' => ['8-|', 'fuzzy', 0x1F453, "nerd"], -'50_50' => ['^o)', '', 0, "sarcastic"], -'51_51' => [':-*', 'fuzzy', 0x1F442, "secret telling"], -'52_52' => ['+o(', 'fuzzy', 0x1F637, "sick"], -'71_71' => [':^)', 'fuzzy', 0x1F610, "i don't know"], -'72_72' => ['*-)', '', 0x1F614, "thinking"], -'74_74' => ['<:o)', 'fuzzy', 0x1F389, "party"], -'75_75' => ['8-)', 'fuzzy', 0x1F612, "eye-rolling"], -'77_77' => ['|-)', '', 0x1F629, "sleepy"], +[regular_smile => ':-) :)', '', 0x0263A, "smile"], +[teeth_smile => ':-D :d', '', 0x1F603, "open-mouthed"], +[omg_smile => ':-O :o', '', 0x1F632, "surprised"], +[tongue_smile => ':-P :p', '', 0x1F61C, "tongue out"], +[wink_smile => ';-) ;)', '', 0x1F609, "wink"], +[sad_smile => ':-( :(', '', 0x02639, "sad"], +[confused_smile => ':-S :s', '', 0x1F616, "confused"], +[what_smile => ':-| :|', '', 0x1F61E, "disappointed"], +[cry_smile => ":'(", '', 0x1F62D, "crying"], +[red_smile => ':-$ :$', '', 0x1F633, "embarrassed"], +[shades_smile => '(H) (h)', '', 0x1F60E, "hot"], +[angry_smile => ':-@ :@', '', 0x1F620, "angry"], +[angel_smile => '(A) (a)', '', 0x1F607, "angel"], +[devil_smile => '(6)', '', 0x1F608, "devil"], +['47_47' => ':-#', '', 0x1F910, "don't tell anyone"], +['48_48' => '8o|', 'todo', 0, "baring teeth"], +['49_49' => '8-|', 'fuzzy', 0x1F453, "nerd"], +['50_50' => '^o)', '', 0x1F928, "sarcastic"], +['51_51' => ':-*', 'fuzzy', 0x1F442, "secret telling"], +['52_52' => '+o(', 'fuzzy', 0x1F637, "sick"], +['71_71' => ':^)', 'fuzzy', 0x1F610, "i don't know"], +['72_72' => '*-)', '', 0x1F614, "thinking"], +['74_74' => '<:o)', '', 0x1F973, "party"], +['75_75' => '8-)', 'fuzzy', 0x1F612, "eye-rolling"], +['77_77' => '|-)', '', 0x1F629, "sleepy"], 'objects', -coffee => ['(C) (c)', '', 0x02615, "coffee cup"], -thumbs_up => ['(Y) (y)', '', 0x1F44D, "thumbs up"], -thumbs_down => ['(N) (n)', '', 0x1F44E, "thumbs down"], -beer_mug => ['(B) (b)', '', 0x1F37A, "beer mug"], -martini => ['(D) (d)', '', 0x1F378, "martini glass"], -girl => ['(X) (x)', '', 0x1F467, "girl"], -guy => ['(Z) (z)', '', 0x1F466, "boy"], -guy_hug => ['({)', '', 0, "left hug"], -girl_hug => ['(})', '', 0, "right hug"], -bat => [':-[ :[', '', 0, "vampire bat"], -cake => ['(^)', '', 0x1F382, "birthday cake"], -heart => ['(L) (l)', '', 0x02665, "red heart"], -broken_heart => ['(U) (u)', '', 0x1F494, "broken heart"], -kiss => ['(K) (k)', '', 0x1F48B, "red lips"], -present => ['(G) (g)', '', 0x1F381, "gift with a bow"], -rose => ['(F) (f)', '', 0x1F339, "red rose"], -wilted_rose => ['(W) (w)', '', 0, "wilted rose"], -camera => ['(P) (p)', '', 0x1F4F7, "camera"], -film => ['(~)', '', 0x1F3A5, "filmstrip"], -cat => ['(@)', '', 0x1F431, "cat face"], -dog => ['(&)', '', 0x1F436, "dog face"], -phone => ['(T) (t)', '', 0x1F4DE, "telephone receiver"], -lightbulb => ['(I) (i)', '', 0x1F4A1, "light bulb"], -note => ['(8)', '', 0x0266A, "note"], -moon => ['(S)', '', 0x1F31C, "sleeping half-moon"], -star => ['(*)', '', 0x02606, "star"], -envelope => ['(E) (e)', '', 0x1F4E7, "e-mail"], -clock => ['(O) (o)', '', 0x023F0, "clock"], -messenger => ['(M) (m)', 'fuzzy', 0x1F465, "MSN Messenger icon"], +[coffee => '(C) (c)', '', 0x02615, "coffee cup"], +[thumbs_up => '(Y) (y)', '', 0x1F44D, "thumbs up"], +[thumbs_down => '(N) (n)', '', 0x1F44E, "thumbs down"], +[beer_mug => '(B) (b)', '', 0x1F37A, "beer mug"], +[martini => '(D) (d)', '', 0x1F378, "martini glass"], +[girl => '(X) (x)', '', 0x1F467, "girl"], +[guy => '(Z) (z)', '', 0x1F466, "boy"], +[guy_hug => '({)', '', 0, "left hug"], +[girl_hug => '(})', '', 0, "right hug"], +[bat => ':-[ :[', '', 0x1F987, "vampire bat"], +[cake => '(^)', '', 0x1F382, "birthday cake"], +[heart => '(L) (l)', '', 0x02665, "red heart"], +[broken_heart => '(U) (u)', '', 0x1F494, "broken heart"], +[kiss => '(K) (k)', '', 0x1F48B, "red lips"], +[present => '(G) (g)', '', 0x1F381, "gift with a bow"], +[rose => '(F) (f)', '', 0x1F339, "red rose"], +[wilted_rose => '(W) (w)', '', 0x1F940, "wilted rose"], +[camera => '(P) (p)', '', 0x1F4F7, "camera"], +[film => '(~)', 'fuzzy', 0x1F3A5, "filmstrip"], +[cat => '(@)', '', 0x1F431, "cat face"], +[dog => '(&)', '', 0x1F436, "dog face"], +[phone => '(T) (t)', '', 0x1F4DE, "telephone receiver"], +[lightbulb => '(I) (i)', '', 0x1F4A1, "light bulb"], +[note => '(8)', '', 0x0266A, "note"], +[moon => '(S)', '', 0x1F31C, "sleeping half-moon"], +[star => '(*)', '', 0x02606, "star"], +[envelope => '(E) (e)', '', 0x1F4E7, "e-mail"], +[clock => '(O) (o)', '', 0x023F0, "clock"], +[messenger => '(M) (m)', 'fuzzy', 0x1F465, "MSN Messenger icon"], 'secondary', -'53_53' => ['(sn)', '', 0x1F40C, "snail"], -'70_70' => ['(bah)', 'fuzzy', 0x1F411, "black sheep"], -'55_55' => ['(pl)', '', 0x1F374, "plate"], -'56_56' => ['(||)', '', 0x1F35C, "bowl"], -'57_57' => ['(pi)', '', 0x1F355, "pizza"], -'58_58' => ['(so)', '', 0x026BD, "soccer ball"], -'59_59' => ['(au)', '', 0x1F697, "auto"], -'60_60' => ['(ap)', '', 0x02708, "airplane"], -'61_61' => ['(um)', '', 0x02602, "umbrella"], -'62_62' => ['(ip)', '', 0x1F334, "island with a palm tree"], -'63_63' => ['(co)', '', 0x1F4BB, "computer"], -'64_64' => ['(mp)', '', 0x1F4F1, "mobile phone"], -'66_66' => ['(st)', '', 0x02601, "stormy cloud"], -'73_73' => ['(li)', 'fuzzy', 0x02607, "lightning"], -'69_69' => ['(mo)', '', 0x1F4B0, "money"], +['53_53' => '(sn)', '', 0x1F40C, "snail"], +['70_70' => '(bah)', 'fuzzy', 0x1F411, "black sheep"], +['55_55' => '(pl)', '', 0x1F37D, "plate"], +['56_56' => '(||)', '', 0x1F35C, "bowl"], +['57_57' => '(pi)', '', 0x1F355, "pizza"], +['58_58' => '(so)', '', 0x026BD, "soccer ball"], +['59_59' => '(au)', '', 0x1F697, "auto"], +['60_60' => '(ap)', '', 0x02708, "airplane"], +['61_61' => '(um)', '', 0x02602, "umbrella"], +['62_62' => '(ip)', '', 0x1F334, "island with a palm tree"], +['63_63' => '(co)', '', 0x1F4BB, "computer"], +['64_64' => '(mp)', '', 0x1F4F1, "mobile phone"], +['66_66' => '(st)', '', 0x1F327, "stormy cloud"], +['73_73' => '(li)', '', 0x1F329, "lightning"], +['69_69' => '(mo)', '', 0x1F4B0, "money"], -# vi:ts=15 +# vi:ts=16 diff --git a/emoji-yahoo.inc.pl b/emoji-yahoo.inc.pl index bb75cef..62a8361 100644 --- a/emoji-yahoo.inc.pl +++ b/emoji-yahoo.inc.pl @@ -8,120 +8,120 @@ 'part 1', -1 => [':)', 'eminent v6', 0x0263A, "happy"], -2 => [':(', 'eminent v6', 0x02639, "sad"], -3 => [';)', 'eminent v6', 0x1F609, "winking"], -4 => [':D', 'eminent v6', 0x1F601, "big grin"], -5 => [';;)', 'v6', 0, "batting eyelashes"], -6 => ['>:D<', 'v6', 0x1F450, "big hug"], -7 => [':-/', 'eminent v6 fuzzy', 0x1F616, "confused"], -8 => [':x', 'v6', 0x1F60D, "love struck"], -9 => [':">', 'eminent v6', 0x1F633, "blushing"], -10 => [':P', 'eminent v6', 0x1F61C, "tongue"], -11 => [':-*', 'eminent v6', 0x1F61A, "kiss"], -12 => ['=((', 'v6', 0x1F494, "broken heart"], -13 => [':-O', 'eminent v6', 0x1F632, "surprise"], -14 => ['X(', 'eminent v6', 0x1F620, "angry"], -15 => [':>', 'eminent v6 fuzzy', 0x1F624, "smug"], # triumph -16 => ['B-)', 'eminent v6', 0x1F60E, "cool"], -17 => [':-S', 'eminent v6', 0x1F628, "worried"], -18 => ['#:-S', 'v6', 0x1F623, "whew!"], # U+1F60C is too happy -19 => ['>:)', 'eminent v6', 0x1F608, "devil"], -20 => [':((', 'eminent v6', 0x1F62D, "crying"], -21 => [':))', 'eminent v6', 0, "laughing"], +[1 => ':)', 'eminent v6', 0x0263A, "happy"], +[2 => ':(', 'eminent v6', 0x02639, "sad"], +[3 => ';)', 'eminent v6', 0x1F609, "winking"], +[4 => ':D', 'eminent v6', 0x1F601, "big grin"], +[5 => ';;)', 'v6', 0, "batting eyelashes"], +[6 => '>:D<', 'v6', 0x1F450, "big hug"], +[7 => ':-/', 'eminent v6 fuzzy', 0x1F616, "confused"], +[8 => ':x', 'v6', 0x1F60D, "love struck"], +[9 => ':">', 'eminent v6', 0x1F633, "blushing"], +[10 => ':P', 'eminent v6', 0x1F61C, "tongue"], +[11 => ':-*', 'eminent v6', 0x1F61A, "kiss"], +[12 => '=((', 'v6', 0x1F494, "broken heart"], +[13 => ':-O', 'eminent v6', 0x1F632, "surprise"], +[14 => 'X(', 'eminent v6', 0x1F620, "angry"], +[15 => ':>', 'eminent v6 fuzzy', 0x1F624, "smug"], # triumph +[16 => 'B-)', 'eminent v6', 0x1F60E, "cool"], +[17 => ':-S', 'eminent v6', 0x1F628, "worried"], +[18 => '#:-S', 'v6', 0x1F623, "whew!"], # U+1F60C is too happy +[19 => '>:)', 'eminent v6', 0x1F608, "devil"], +[20 => ':((', 'eminent v6', 0x1F62D, "crying"], +[21 => ':))', 'eminent v6', 0, "laughing"], 'part 2', -22 => [':|', 'eminent v6', 0x1F610, "straight face"], -23 => ['/:)', 'v6', 0, "raised eyebrows"], -24 => ['=))', 'v6', 0, "rolling on the floor"], -25 => ['O:-)', 'v6', 0x1F607, "angel"], -26 => [':-B', 'v6 fuzzy', 0x1F453, "nerd"], -27 => ['=;', 'v6', 0x0270B, "talk to the hand"], -101 => [':-c', '', 0, "call me"], -100 => [':)]', '', 0, "on the phone"], -102 => ['~X(', '', 0, "at wits' end"], -103 => [':-h', '', 0x1F44B, "wave"], -104 => [':-t', '', 0, "time out"], -105 => ['8->', '', 0, "day dreaming"], -28 => ['I-)', 'v6', 0x1F62A, "sleepy"], -29 => ['8-|', 'v6 fuzzy', 0x1F612, "rolling eyes"], -30 => ['L-)', 'v6', 0, "loser"], -31 => [':-&', 'eminent v6 fuzzy', 0x1F637, "sick"], -32 => [':-$', 'v6 fuzzy', 0x1F64A, "don't tell anyone"], -33 => ['[-(', 'v6', 0, "no talking"], -34 => [':O)', 'v6', 0, "clown"], -35 => ['8-}', 'v6', 0, "silly"], -36 => ['<:-P', 'v6 fuzzy', 0x1F389, "party"], +[22 => ':|', 'eminent v6', 0x1F610, "straight face"], +[23 => '/:)', 'v6', 0, "raised eyebrows"], +[24 => '=))', 'v6', 0, "rolling on the floor"], +[25 => 'O:-)', 'v6', 0x1F607, "angel"], +[26 => ':-B', 'v6 fuzzy', 0x1F453, "nerd"], +[27 => '=;', 'v6', 0x0270B, "talk to the hand"], +[101 => ':-c', '', 0, "call me"], +[100 => ':)]', '', 0, "on the phone"], +[102 => '~X(', '', 0, "at wits' end"], +[103 => ':-h', '', 0x1F44B, "wave"], +[104 => ':-t', '', 0, "time out"], +[105 => '8->', '', 0, "day dreaming"], +[28 => 'I-)', 'v6', 0x1F62A, "sleepy"], +[29 => '8-|', 'v6 fuzzy', 0x1F612, "rolling eyes"], +[30 => 'L-)', 'v6', 0, "loser"], +[31 => ':-&', 'eminent v6 fuzzy', 0x1F637, "sick"], +[32 => ':-$', 'v6 fuzzy', 0x1F64A, "don't tell anyone"], +[33 => '[-(', 'v6', 0, "no talking"], +[34 => ':O)', 'v6', 0, "clown"], +[35 => '8-}', 'v6', 0, "silly"], +[36 => '<:-P', 'v6 fuzzy', 0x1F389, "party"], 'part 3', -37 => ['(:|', 'eminent v6', 0x1F629, "yawn"], -38 => ['=P~', 'v6', 0x1F60B, "drooling"], -39 => [':-?', 'eminent v6', 0x1F614, "thinking"], -40 => ['#-o', 'v6', 0, "d'oh"], -41 => ['=D>', 'v6', 0x1F44F, "applause"], -42 => [':-SS', 'v6', 0, "nail biting"], -43 => ['@-)', 'v6', 0, "hypnotized"], -44 => [':^o', 'v6', 0, "liar"], -45 => [':-w', 'v6', 0, "waiting"], -46 => [':-<', 'v6', 0, "sigh"], -47 => ['>:P', 'v6', 0, "phbbbbt"], -48 => ['<):)', 'v6', 0, "cowboy"], -109 => ['X_X', '', 0x1F648, "I don't want to see"], -110 => [':!!', '', 0, "hurry up!"], -111 => ['\m/', '', 0, "rock on!"], -112 => [':-q', '', 0x1F44E, "thumbs down"], -113 => [':-bd', '', 0x1F44D, "thumbs up"], -114 => ['^#(^', '', 0, "it wasn't me"], -pirate_2 => [':ar!', 'ext', 0, "pirate"], +[37 => '(:|', 'eminent v6', 0x1F629, "yawn"], +[38 => '=P~', 'v6', 0x1F60B, "drooling"], +[39 => ':-?', 'eminent v6', 0x1F614, "thinking"], +[40 => '#-o', 'v6', 0, "d'oh"], +[41 => '=D>', 'v6', 0x1F44F, "applause"], +[42 => ':-SS', 'v6', 0, "nail biting"], +[43 => '@-)', 'v6', 0, "hypnotized"], +[44 => ':^o', 'v6', 0, "liar"], +[45 => ':-w', 'v6', 0, "waiting"], +[46 => ':-<', 'v6', 0, "sigh"], +[47 => '>:P', 'v6', 0, "phbbbbt"], +[48 => '<):)', 'v6', 0, "cowboy"], +[109 => 'X_X', '', 0x1F648, "I don't want to see"], +[110 => ':!!', '', 0, "hurry up!"], +[111 => '\m/', '', 0, "rock on!"], +[112 => ':-q', '', 0x1F44E, "thumbs down"], +[113 => ':-bd', '', 0x1F44D, "thumbs up"], +[114 => '^#(^', '', 0, "it wasn't me"], +[pirate_2 => ':ar!', 'ext', 0, "pirate"], # http://messenger.yahoo.com/features/hiddenemoticons/ 'hidden 1', -108 => [':o3', 'hidden fuzzy', 0x1F436, "puppy dog eyes"], -106 => [':-??', 'hidden', 0, "I don't know"], -107 => ['%-(', 'hidden', 0x1F649, "not listening"], -49 => [':@)', 'hidden v6', 0x1F437, "pig"], -50 => ['3:-O', 'hidden v6', 0x1F42E, "cow"], -51 => [':(|)', 'hidden v6', 0x1F435, "monkey"], -52 => ['~:>', 'hidden v6', 0x1F414, "chicken"], -53 => ['@};-', 'hidden v6', 0x1F339, "rose"], -54 => ['%%-', 'hidden v6', 0x1F340, "good luck"], -55 => ['**==', 'hidden v6', 0x02690, "flag"], -56 => ['(~~)', 'hidden v6', 0x1F383, "pumpkin"], -57 => ['~O)', 'hidden v6', 0x02615, "coffee"], -58 => ['*-:)', 'hidden v6', 0x1F4A1, "idea"], +[108 => ':o3', 'hidden fuzzy', 0x1F436, "puppy dog eyes"], +[106 => ':-??', 'hidden', 0, "I don't know"], +[107 => '%-(', 'hidden', 0x1F649, "not listening"], +[49 => ':@)', 'hidden v6', 0x1F437, "pig"], +[50 => '3:-O', 'hidden v6', 0x1F42E, "cow"], +[51 => ':(|)', 'hidden v6', 0x1F435, "monkey"], +[52 => '~:>', 'hidden v6', 0x1F414, "chicken"], +[53 => '@};-', 'hidden v6', 0x1F339, "rose"], +[54 => '%%-', 'hidden v6', 0x1F340, "good luck"], +[55 => '**==', 'hidden v6', 0x02690, "flag"], +[56 => '(~~)', 'hidden v6', 0x1F383, "pumpkin"], +[57 => '~O)', 'hidden v6', 0x02615, "coffee"], +[58 => '*-:)', 'hidden v6', 0x1F4A1, "idea"], 'hidden 2', -59 => ['8-X', 'hidden v6', 0x1F480, "skull"], -60 => ['=:)', 'hidden v6', 0x1F41C, "bug"], -61 => ['>-)', 'hidden v6', 0x1F47D, "alien"], -62 => [':-L', 'hidden v6', 0x1F612, "frustrated"], -63 => ['[-O<', 'hidden v6', 0x1F64F, "praying"], -64 => ['$-)', 'hidden v6', 0, "money eyes"], -65 => [':-"', 'hidden v6', 0x0266B, "whistling"], -66 => ['b-(', 'hidden v6', 0, "feeling beat up"], -67 => [':)>-', 'hidden v6', 0x0262E, "peace sign"], # U+270C -68 => ['[-X', 'hidden v6', 0, "shame on you"], -69 => ['\:D/', 'hidden v6', 0x1F483, "dancing"], +[59 => '8-X', 'hidden v6', 0x1F480, "skull"], +[60 => '=:)', 'hidden v6', 0x1F41C, "bug"], +[61 => '>-)', 'hidden v6', 0x1F47D, "alien"], +[62 => ':-L', 'hidden v6', 0x1F612, "frustrated"], +[63 => '[-O<', 'hidden v6', 0x1F64F, "praying"], +[64 => '$-)', 'hidden v6', 0, "money eyes"], +[65 => ':-"', 'hidden v6', 0x0266B, "whistling"], +[66 => 'b-(', 'hidden v6', 0, "feeling beat up"], +[67 => ':)>-', 'hidden v6', 0x0262E, "peace sign"], # U+270C +[68 => '[-X', 'hidden v6', 0, "shame on you"], +[69 => '\:D/', 'hidden v6', 0x1F483, "dancing"], 'hidden 3', -70 => ['>:/', 'hidden v6', 0, "bring it on"], -71 => [';))', 'hidden v6', 0x1F60F, "hee hee"], -76 => [':-@', 'hidden v6', 0, "chatterbox"], -77 => ['^:)^', 'hidden v6', 0x1F647, "not worthy"], -78 => [':-j', 'hidden v6', 0, "oh go on"], -79 => ['(*)', 'hidden v6', 0x02606, "star"], -72 => ['o->', 'hidden v6', 0, "hiro"], -73 => ['o=>', 'hidden v6', 0, "billy"], -74 => ['o-+', 'hidden v6', 0, "april"], -75 => ['(%)', 'hidden v6', 0x0262F, "yin yang"], -115 => [':bz', 'hidden', 0x1F41D, "bee"], -transformer => ['[..]', 'hidden ext', 0, "transformer"], +[70 => '>:/', 'hidden v6', 0, "bring it on"], +[71 => ';))', 'hidden v6', 0x1F60F, "hee hee"], +[76 => ':-@', 'hidden v6', 0, "chatterbox"], +[77 => '^:)^', 'hidden v6', 0x1F647, "not worthy"], +[78 => ':-j', 'hidden v6', 0, "oh go on"], +[79 => '(*)', 'hidden v6', 0x02606, "star"], +[72 => 'o->', 'hidden v6', 0, "hiro"], +[73 => 'o=>', 'hidden v6', 0, "billy"], +[74 => 'o-+', 'hidden v6', 0, "april"], +[75 => '(%)', 'hidden v6', 0x0262F, "yin yang"], +[115 => ':bz', 'hidden', 0x1F41D, "bee"], +[transformer => '[..]', 'hidden ext', 0, "transformer"], # http://www.wackyb.co.nz/Archive_Yahoo_Messenger_Smiley_History/ diff --git a/emoji.plp b/emoji.plp index 2a546b4..63572c7 100644 --- a/emoji.plp +++ b/emoji.plp @@ -2,7 +2,7 @@ Html({ title => 'emoji cheat sheet', - version => '1.0', + version => '1.1', description => [ "Emoticons overview and Unicode equivalents" . " of MSN, Y!M, and Gmail icons.", @@ -12,6 +12,7 @@ Html({ chat im messenger msn yahoo ym gmail google '], stylesheet => [qw'light'], + data => ['emoji-gmail.inc.pl'], }); :> @@ -21,21 +22,20 @@ Html({ say '
'; for my $system (qw'gmail msn yahoo') { - my @info = do "emoji-$system.inc.pl"; - my $meta = shift @info or die $@; - ref $meta eq 'HASH' or die "invalid $system definitions"; + my @info = Data("emoji-$system"); + my $meta = shift @info; + ref $meta eq 'HASH' or Abort("Invalid $system definitions", 404); my $title = $meta->{name} // $system; $title = showlink($title, $_) for $meta->{source} || (); say sprintf '

%s

', $meta->{name} // $system; say ''; - for (my $i = 0; $i <= $#info; $i++) { - my $name = $info[$i]; - unless (ref $info[$i+1] eq 'ARRAY') { - say sprintf '
', $name; + for my $row (@info) { + unless (ref $row eq 'ARRAY') { + say '
'; next; } - my ($input, $flags, $char, $desc) = @{ $info[++$i] }; + my ($name, $input, $flags, $char, $desc) = @{$row}; say sprintf('
%s%s%s%s', sprintf($meta->{ $flags =~ /\bext\b/ ? 'iconext' : 'icon' } // '%s', $name), EscapeHTML($name), diff --git a/font.plp b/font.plp index 3a39c2e..7019573 100644 --- a/font.plp +++ b/font.plp @@ -4,7 +4,7 @@ my $font = $Request; Html({ title => 'font coverage '.($font ? "for $font" : 'sheet'), - version => '1.2', + version => '1.4', keywords => [qw( unicode font glyph char character support overview cover coverage script block symbol sign mark reference table @@ -14,13 +14,13 @@ Html({ }); if ($font) { - my ($fontmeta, @cover) = do "data/font/$font.inc.pl"; - $fontmeta or die "Unknown font $font\n"; + my $fontmeta = eval { Data("data/font/$font") } + or Abort("Unknown font $font", '404 font not found', ref $@ && $@->[1]); my $map = eval { $get{map} or return; - my $groupinfo = do 'data/unicode-cover.inc.pl' or die $@ || $!; + my $groupinfo = Data('data/unicode-cover'); my ($cat, $name) = split m{/}, $get{map}, 2 or die "invalid map\n"; if (!$name) { @@ -39,7 +39,7 @@ if ($font) { } return \@map; }; - die $@ if $@; + Abort($@, '404 invalid query') if $@; require Unicode::UCD; @@ -52,14 +52,14 @@ if ($font) { return $_->[0]->[0] for Unicode::UCD::charblock(ucfirst) || (); # block die "Unknown offset query '$_'\n"; }; - die $@ if $@; + Abort($@, '400 invalid offset') if $@; say "

Font coverage

"; say "

$_

" for EscapeHTML($fontmeta->{name}); printf("

Version %s released %s contains %d glyphs.", !!$_->[2] && qq( title="revision $_->[2]"), $_->[1], $_->[0], - scalar @cover, + scalar @{ $fontmeta->{cover} }, ) for [ grep { $_ } ($fontmeta->{date} || '?') =~ s/T.*//r, @@ -86,7 +86,7 @@ if ($font) { require Shiar_Sheet::FormatChar; my $glyphs = Shiar_Sheet::FormatChar->new; - my %cover = map { ($_ => 1) } @cover; # lookup map + my %cover = map { ($_ => 1) } @{ $fontmeta->{cover} }; # lookup map say <<"EOT"; @@ -156,12 +156,15 @@ EOT my ($class, $name, $mnem, $entity, $string) = @{$info}; my $np = $class =~ /\bC\S\b/; # noprint if control or invalid # display literal character, with placeholder circle if non-spacing/enclosing - my $html = ($class =~ /\bM[ne]\b/ && chr 9676) . EscapeHTML(chr $cp); + $string ||= ($class =~ /\bM[ne]\b/ && chr 9676) . chr($cp); + my $html = $np ? !!$cover{$cp} && sprintf("&#%d;", $cp) : + EscapeHTML($string); say sprintf '

%s', - !$class ? ('l0', $cp, '', '') : + !$class ? ('l0', $cp, '', '') : ( $cover{$cp} ? $np ? 'l2' : 'l5' : $np ? 'Xi' : 'l1', $cp, !!$name && ": $name", - ($cover{$cp} || !$np) && $html; + $html + ); } say '
'; @@ -180,7 +183,7 @@ Character support of Unicode <: -my $cover = do 'data/unicode-cover.inc.pl' or die $@ || $!; +my $cover = Data('data/unicode-cover'); my @ossel = @{ $cover->{osdefault} }; my @fontlist = map { @{ $cover->{os}->{$_} } } @ossel; @@ -218,7 +221,7 @@ my @rows = ( if (my $group = $get{q}) { my $grouprows = $cover->{$group} - or die "Unknown character category $_\n"; + or Abort("Unknown character category $_", 404); @rows = map { "$group/$_" } sort keys %{$grouprows}; } diff --git a/graffiti.ttf b/graffiti.ttf new file mode 100644 index 0000000..303498d Binary files /dev/null and b/graffiti.ttf differ diff --git a/index.plp b/index.plp index 8189519..f05c02a 100644 --- a/index.plp +++ b/index.plp @@ -2,7 +2,8 @@ Html({ title => 'cheat sheets', - version => '1.10', + canonical => '/', + version => '1.18', description => [ "Cheat sheets summarising various software programs and standards.", ], @@ -15,8 +16,8 @@ Html({ ' title="RSS feed of repository updates"', ' href="http://git.shiar.nl/sheet.git/rss">', ], + data => ['UPDATE'], }); - :>

Shiar's cheat sheets

@@ -28,12 +29,15 @@ Originally created by Mischa Poslawsky, but you're free to use, print, alter, and redistribute under the AGPL license.

<: -my @format = ('--date=short', "--pretty=%ad (%ar)\t%s"); -if (open my $log, '-|', git => 'log', -1, @format) {{ +if (open my $log, '<', 'UPDATE') {{ my $line = readline $log; $line or next; # explicitly ignore empty input + EscapeHTML $line; my ($date, $subject) = split /[\t\n]/, $line; $date =~ s/ \K// and $date .= ''; + $subject =~ s{\A (\w+) (?= (?:/\w+)* :\h )}{ + showlink($1, -e "$1.plp" && "/$1"); + }ex; say "

Last update: $date $subject

"; }} @@ -49,7 +53,8 @@ if (open my $log, '-|', git => 'log', -1, @format) {{
  • vimperator
  • mutt
  • nethack -
  • mplayer +
  • mplayer/mpv +
  • altgr/option
  • @@ -75,9 +80,9 @@ if (open my $log, '-|', git => 'log', -1, @format) {{
  • perl versions
  • apl symbols
  • terminal colours -
  • starcraft 2 units - (bw) +
  • starcraft units
  • emoticons +
  • dieren (Dutch animals)
  • diff --git a/keyboard.plp b/keyboard.plp index 2fe9c07..fa2aaf2 100644 --- a/keyboard.plp +++ b/keyboard.plp @@ -1,67 +1,84 @@ <(common.inc.plp)><: +$Request ||= 'altgr/windows'; +my $mode = lc $Request; +my $include = "keyboard/$mode.eng"; + +if (-e (my $page = "keyboard/$Request/index.inc.plp")) { + Include $page; + exit; +} + +my $info = eval { Data($include) } || {}; +warn "error in $include: ", @{$@} if ref $@; +$mode = $info->{title} // $mode; + +my $showkeys //= !exists $get{keys} ? undef : + ($get{keys} ne '0' && ($get{keys} || 'always')); +my @keystyle = ( + '', + '', + !$showkeys ? '' : + $showkeys eq 'ghost' ? '' : (), + '', +); + Html({ - title => 'keyboard cheat sheet', - version => '1.0', + title => "\L$mode\E keyboard cheat sheet", + version => $info->{version} || '0.1', + canonical => -e "$Request.plp" ? "/$Request" : undef, # historic shorthand + description => $info->{description} // + ["Keyboard cheat sheet for the default controls of $mode."], + keywords => [@{ $info->{keywords} // [] }, qw' + sheet cheat reference overview keyboard control commands shortkey + '], + image => $info->{image}, stylesheet => [qw( light dark circus mono red )], - keys => 1, + data => ["$include.inc.pl"], + raw => \@keystyle, }); -:> -

    keyboard cheat sheet

    +%{$info} or Abort( + "Requested keyboard $mode not available", + '404 request not found', +); -

    normal mode (default)

    +say "

    $mode keyboard

    "; +say "

    $_

    " for $info->{intro} // (); +say "

    ", $info->{mode}->{''}, " (default)

    " + if $info->{mode} and %{ $info->{mode} } > 1; -<: -use Shiar_Sheet::Keyboard 2.07; -use Unicode::Normalize qw( NFKD ); -use Text::Unidecode qw( unidecode ); +use Shiar_Sheet::Keyboard 2.08; +my $keys = Shiar_Sheet::Keyboard->new($info); +$keys->map($get{map}) or undef $get{map}; +$keys->print_rows($get{rows} || $info->{moderows}, $info->{rows}); -my @usintrows = ( - [ 'a' .. 'z'], - [qw(Á B ¢ Ð É F G H Í J Œ Ø µ Ñ Ó Ö Ä ® § Þ Ú V Å X Ü Æ)], - [qw(á b © ð é f g h í j œ ø µ ñ ó ö ä ® ß þ ú v å x ü æ)], - [qw(Å ı Ç ð ´ ̉ ˝ ̣ ˆ ½  Þ ¾ ˜ Ø ∏ Œ ‰ / ˇ ¨ ◊ „ ˛ ¼ ¸)], - [qw(å ∫ ç ∂ ́ ƒ © ˙ ̂ ∆ ° ¬ µ ̃ ø π œ ® ß † ̈ √ ∑ ≈ ¥ Ω)], -); -my @usint = ( - map { - my $c = $_; - [ map { $usintrows[$_]->[$c] } 0 .. 2 ] - } 0 .. $#{ $usintrows[0] } -); +{ + say "
    \n"; + say '
    '; -my $keys = Shiar_Sheet::Keyboard->new({ - def => { - '' => { - map { - my @row = @{$_}; - my $class = ( - !defined $row[2] || $row[0] eq $row[2] ? 1 # identical - : NFKD($row[2]) =~ $row[0] ? 2 # decomposed equivalent - : $row[2] =~ /^\p{Latin}/ ? 4 # latin script - : unidecode($row[2]) =~ /^\W*\Q$row[0]/ ? 5 # transliterated - : $row[2] =~ /^\p{Mn}/ ? 8 # combining accent - : 7 - ); - $row[0] => "g$class" - } @usint - }, - }, - key => { - map { - $_->[0] => "$_->[1]
    $_->[2]" - } @usint - }, - flag => { - g1 => ['unaltered'], - g2 => ['accented'], - g4 => ['latin'], - g7 => ['other'], - g8 => ['combining'], - }, -}); -$keys->map($get{map}) or undef $get{map}; -$keys->print_rows($get{rows}, [0]); -$keys->print_legends(\%get); + use List::MoreUtils qw( part ); + my @gflags = part {/^g\d/} sort keys %{ $keys->{flag} }; + + say "\t", '
    '; + $keys->print_legend('legend-types', $gflags[1]); + say "\t
    \n"; + + say "\t", '
    '; + $keys->print_legend('legend-options', $gflags[0]); + say ''; + + say "\t\t", '
      '; + + say "\t\t
    • keyboard map is ", + ($get{map} ? 'set to ' : ''), "$keys->{map}"; + say "\t\t
    • keys are ", + "", ($showkeys ? 'always shown' : 'hidden if unassigned'), "", + (!defined $showkeys && ' by default'); + say "\t\t
    • default style is ", + (defined $get{style} && 'set to '), "$style"; + say "\t\t
    "; + say "\t
    \n"; + say "
    \n"; +} diff --git a/keyboard/altgr/apl.eng.inc.pl b/keyboard/altgr/apl.eng.inc.pl new file mode 100644 index 0000000..c796cb3 --- /dev/null +++ b/keyboard/altgr/apl.eng.inc.pl @@ -0,0 +1,117 @@ +use utf8; +use strict; +use warnings; +use Shiar_Sheet::KeyboardChars 'kbchars'; + +my %dyalogx = ( + 'Q' => '⍰', + 'R' => '⌾', + 'G' => '⍢', + 'B' => '⍭', + 'N' => '⍡', + 'M' => '∥', +); +my %rows = ( + '~' => '⌺', + '!' => '⌶', + '@' => '⍫', + '#' => '⍒', + '$' => '⍋', + '%' => '⌽', + '^' => '⍉', + '&' => '⊖', + '*' => '⍟', + '(' => '⍱', + ')' => '⍲', + '_' => '!', + '+' => '⌹', + '`' => '⋄', + '1' => '¨', + '2' => '¯', + '3' => '<', + '4' => '≤', + '5' => '=', + '6' => '≥', + '7' => '>', + '8' => '≠', + '9' => '∨', + '0' => '∧', + '-' => '×', + '=' => '÷', + 'E' => '⍷', + 'T' => '⍨', + 'I' => '⍸', + 'O' => '⍥', + 'P' => '⍣', + '{' => '⍞', + '}' => '⍬', + '|' => '⊣', + 'q' => '?', + 'w' => '⍵', + 'e' => '∊', + 'r' => '⍴', + 't' => '∼', # ~ + 'y' => '↑', + 'u' => '↓', + 'i' => '⍳', + 'o' => '○', + 'p' => '⋆', # * + '[' => '←', + ']' => '→', + '\\'=> '⊢', + 'J' => '⍤', + 'K' => '⌸', + 'L' => '⌷', + ':' => '≡', + '"' => '≢', + 'a' => '⍺', + 's' => '⌈', + 'd' => '⌊', + 'f' => '_', + 'g' => '∇', + 'h' => '∆', + 'j' => '∘', + 'k' => "'", + 'l' => '⎕', + ';' => '⍎', + "'" => '⍕', + 'Z' => '⊆', + '<' => '⍪', + '>' => '⍙', + '?' => '⍠', + 'z' => '⊂', + 'x' => '⊃', + 'c' => '∩', + 'v' => '∪', + 'b' => '⊥', + 'n' => '⊤', + 'm' => '|', + ',' => '⍝', + '.' => '⍀', + '/' => '⌿', + %dyalogx, +); + +my $groups = kbchars(\%rows); +$groups->{def}{''}{$_} .= ' ext' for keys %dyalogx; +$groups->{flag}{ext} = ['extended', 'optional operators not available in all variants']; + ++{ + %{$groups}, + version => '1.0', + title => 'APL', + category => 'specialised', + intro => join("\n", + 'Resulting Unicode characters', + 'of a typical APL keyboard layout', + 'derived from IBM System/360 terminals.', + 'Usually obtained by prefixing ` (Dyalog)', + 'and/or pressing AltGr (APLX).', + ), + description => [ + 'Typical IBM-derived APL keyboard layout,', + 'as found in APLX and Dyalog implementations.', + ], + image => 'data/keyboard/thumb/unicomp-apl.jpg', + imagealt => 'Alt on a custom keyboard with APL labels', +} diff --git a/keyboard/altgr/boyeg.eng.inc.pl b/keyboard/altgr/boyeg.eng.inc.pl new file mode 100644 index 0000000..63bfa49 --- /dev/null +++ b/keyboard/altgr/boyeg.eng.inc.pl @@ -0,0 +1,95 @@ +use utf8; +use strict; +use warnings; +use Shiar_Sheet::KeyboardChars 'kbchars'; + +my %rows = ( + '~' => "\N{COMBINING CEDILLA}", + '`' => '§', + '!' => "\N{COMBINING GRAVE ACCENT}", + '1' => '¬', + '@' => "\N{COMBINING ACUTE ACCENT}", + '2' => '¤', + '#' => "\N{COMBINING VERTICAL LINE BELOW}", + '3' => '₵', + '$' => '€', + '4' => '£', + '%' => '°', # assume misaligned + '5' => '₦', + '^' => "\N{COMBINING DOT ABOVE}", + '6' => "\N{COMBINING DOT BELOW}", + '&' => "\N{COMBINING DIAERESIS}", + '7' => "\N{COMBINING DIAERESIS BELOW}", + '*' => "\N{COMBINING TILDE}", + '8' => "\N{COMBINING TILDE BELOW}", + '(' => "\N{COMBINING CIRCUMFLEX ACCENT}", + '9' => "\N{COMBINING CIRCUMFLEX ACCENT BELOW}", + ')' => "\N{COMBINING CARON}", + '0' => "\N{COMBINING CARON BELOW}", + '-' => "\N{COMBINING MACRON BELOW}", + '_' => "\N{COMBINING MACRON}", + '+' => "\N{COMBINING BRIDGE ABOVE}", + '=' => "\N{COMBINING BRIDGE BELOW}", + + 'Q' => 'Ɵ', + 'W' => 'Ɛ', + 'E' => 'Ǝ', + 'R' => 'Ɍ', + 'T' => 'Ʈ', + 'Y' => 'Ƴ', # subtle + 'U' => 'Ʊ', + 'I' => 'Ɨ', + 'O' => 'Ɖ', + 'P' => 'Ƥ', # different lowercase + '{' => '¶', + '}' => 'μ', + + 'A' => 'Ʌ', + 'S' => 'Ʃ', + 'D' => 'Ɗ', + 'F' => 'Ƒ', + 'G' => 'Ɂ', # probably caseless ʔ + 'H' => 'Ħ', # different uppercase + 'J' => 'Ɉ', # lowercase shown dotless + 'K' => 'Ƙ', # subtle + 'L' => 'Ɩ', + ':' => 'Œ', + ';' => 'œ', + + 'Z' => 'Ʒ', + 'X' => 'Ɣ', + 'C' => 'Ɔ', + 'V' => 'Ʋ', + 'B' => 'Ɓ', + 'N' => 'Ŋ', + 'M' => 'Ɲ', + '<' => '«', + '>' => '»', + '?' => 'Æ', + '/' => 'æ', +); + +$rows{lc $_} //= lc $rows{$_} for 'A'..'Z'; + +my $groups = kbchars(\%rows); + ++{ + %{ $groups }, + version => '1.0', + title => 'Boyeg', + category => 'latin', + intro => join("\n", + 'Commercial product by', + 'Keyboard Africa', + 'providing Unicode characters', + 'for various African languages while pressing', + # Ewe, Baoule, Akan, Dagbani, Hausa, Temme, Ewondo, Igbo, Fon, Wolof, Fulfide, Berber, IIshan, Fula, Dyula, Yoruba, Itsekiri, Konkomba, Kanuri, Dan, Luhya, Bukusu, Gusii, Meru, Kikuyu, English, French, Spanish and more + 'Fn.', + ), + description => [ + "Boyeg Keyboard layout table with its Fn modifier key", + "providing latin letters and accents for various African languages.", + ], + image => 'data/keyboard/thumb/boyeg.jpg', + imagealt => 'Fn on the Boyeg Office Keyboard', +} diff --git a/keyboard/altgr/drix.eng.inc.pl b/keyboard/altgr/drix.eng.inc.pl new file mode 100644 index 0000000..c36f53b --- /dev/null +++ b/keyboard/altgr/drix.eng.inc.pl @@ -0,0 +1,125 @@ +use utf8; +use strict; +use warnings; +use Shiar_Sheet::KeyboardChars 'kbchars'; + +my %rows = ( + '!' => "\N{COMBINING GRAVE ACCENT}", + '#' => "\N{COMBINING CIRCUMFLEX ACCENT}", + '$' => "\N{COMBINING DIAERESIS}", + '%' => "\N{COMBINING RING ABOVE}", + '&' => "\N{COMBINING CEDILLA}", + '~' => "\N{COMBINING TILDE}", + '(' => "\N{COMBINING CARON}", + ')' => "\N{COMBINING DOUBLE ACUTE ACCENT}", + '*' => "\N{COMBINING OGONEK}", + '+' => "\x{2260}", + '-' => "\"", + '0' => "\x{2070}", + '1' => "\xB9", + '2' => "\xB2", + '3' => "\xB3", + '4' => "\x{2074}", + '5' => "\x{2075}", + '6' => "\x{2076}", + '7' => "\x{2077}", + '8' => "\x{2078}", + '9' => "\x{2079}", + '=' => "'", + '@' => "\N{COMBINING ACUTE ACCENT}", + '[' => "{", + ']' => "}", + '^' => "\N{COMBINING MACRON}", + '_' => "\xB1", + '`' => "\xA3", + 'A' => "\x{2190}", + 'a' => "\xE6", + 'B' => "\x{20bf}", + 'b' => "\x{2642}", + 'c' => "\xA9", + 'C' => "\xA2", + 'd' => "\x{394}", + 'D' => "\x{2192}", + 'e' => "\x{20AC}", + 'E' => "\x{20AC}", + 'f' => "\x{192}", + 'F' => "\x{191}", + #'g' => "g", + #'G' => "G", + #'H' => "H", + #'h' => "h", + 'i' => "\x{2018}", + 'I' => "\x{2019}", + 'j' => "\x{201C}", + 'J' => "\x{201D}", + 'k' => "\x{201A}", + 'K' => "\x{201E}", + 'L' => "\x{3BB}", + 'l' => "\xA3", + #'M' => "M", # at : + 'm' => "\xB5", # at ; + #'N' => "N", + 'n' => "\x{26a5}", + 'o' => "\x{153}", + 'O' => "\x{3A9}", + 'P' => "\x{20b1}", + 'p' => "\x{3C0}", + 'q' => "\xF8", + 'Q' => "\xD8", + 'R' => "\x{20bd}", + 'r' => "\xAE", + 's' => "\xDF", + 'S' => "\x{2193}", + 'T' => "\x{3C4}", + 't' => "\x{2122}", + #'u' => "u", + #'U' => "U", + #'V' => "V", + 'v' => "\x{2640}", + 'W' => "\x{2191}", + #'w' => "w", + 'x' => "\xD7", + 'X' => "\xF7", + 'y' => "\xA5", + 'Y' => "\xA5", + 'z' => "\xA7", + 'Z' => "\xB6", + '{' => "\xAB", + '}' => "\xBB", + + '"' => "\x{2030}", # unshifted % + "'" => "~", # unshifted # + #'|' => '×', # unshifted & at BKSL same as x + #'\\'=> '$', # unshifted * at bksl + '|' => "≤", # unshifted < at LSGT + '\\'=> "≥", # unshifted > at lsgt + '<' => "\xB7", # unshifted , + ',' => "\x{2026}", # unshifted . + '>' => "\xB4", # unshifted ; + '.' => "`", # unshifted : + '?' => "\xA6", # unshifted \ + '/' => "|", + ':' => "\xBF", # unshifted ? at M + ';' => "\xA1", # unshifted ! at m +); + +my $groups = kbchars(\%rows); +$groups->{def}{''}{$_} .= ' ext' for qw( ` E Y ); + ++{ + %{$groups}, + version => '1.0', + title => 'Drix', + category => 'latin/xorg', + intro => join("\n", + "European Latin layout version 3.1 providing", + 'Unicode characters while pressing AltGr,', + 'developed by Jerome Leclanche', + 'for Linux.', + ), + description => [ + "Drix EU Latin keyboard layout table", + "with the AltGr modifier key: provides miscellaneous symbols", + "and accents for some European languages.", + ], +} diff --git a/keyboard/altgr/emojiworks.eng.inc.pl b/keyboard/altgr/emojiworks.eng.inc.pl new file mode 100644 index 0000000..dca101c --- /dev/null +++ b/keyboard/altgr/emojiworks.eng.inc.pl @@ -0,0 +1,99 @@ +use utf8; +use strict; +use warnings; +no warnings 'qw'; +use Shiar_Sheet::KeyboardChars 'kbchars'; + +my %rows = qw( + ` 🤖 + 1 🦄 + 2 🔥 + 3 🎉 + 4 💰 + ~ 🏻 ! 🏼 @ 🏽 # 🏾 $ 🏿 + 5 🎶 % 🍿 + 6 💩 ^ 🍑 + 7 🙈 & 🌭 + 8 ☀️ * ☔ + 9 👀 ( ❄️ + 0 💯 ) 🇺🇸 + - 🔫 _ 🕊️ + = 💁 + 🙅 + q 👉 Q 👈 ^q ☝ + w ✌ W 🤘 ^w ✊ + e 🙌 E 💪 ^e 🏋 + r 👌 R 👋 ^r 💦 + t 👍 T 👎 ^t 👑 + y ♥ Y 💔 ^y 💙 + u 💕 U 💋 ^u 💏 + i 👏 I ⚡ ^i 🎁 + o 🙏 O 👊 ^o 🕴 + p ✋ P 👆 ^p 🍔 + [ 🌮 { 🍕 + ] ☕ } 🍻 + \ ✨ | 🌟 + a 😍 A 😻 ^a 🏀 + s 😘 S 👫 ^s 🏈 + d 😳 D 😨 ^d ⚽ + f 😜 F 😋 ^f 😝 + g 😊 G 🤗 ^g 🏃 + h 😂 H 😆 ^h 💐 + j 😄 J 🙃 ^j 🌹 + k 😉 K 👯 ^k 🌈 + l 😌 L 💃 ^l 🍭 + ; 😎 : 🤓 + ' 🤔 " 🎅 + z 😈 Z ⛄ ^z 👻 + x 😡 X ☠️ ^x ⚔️ + c 😱 C 🙊 ^c 👽 + v 😬 V 👼 ^v 🛠️ + b 😑 B 😶 ^b 😷 + n 😒 N 🙄 ^n 😏 + m 😢 M 👶 ^m 🐶 + , 😭 < 😖 + . 😔 > 😩 + / 😴 ? 😞 +); + +my $groups = kbchars(\%rows); + +while (my ($k, $c) = each %rows) { + # override letter-based classes by unicode versions + $groups->{def}{''}{$k} = ( + $c =~ /\p{General_Category=Modifier_Symbol}/ ? 'g9' : + $c =~ /\p{In=1.1}/ ? 'g2' : + $c =~ /\p{In=5.2}/ ? 'g3' : + $c =~ /\p{In=6.0}/ ? 'g4' : + $c =~ /\p{In=7.0}/ ? 'g5' : + $c =~ /\p{In=8.0}/ ? 'g7' : + 'g0' # unexpectedly newer + ); +} + ++{ + %{$groups}, + title => 'EmojiWorks', + version => '1.0', + category => 'legacy/emoji', + tableclass => 'keys big', + intro => join("\n", + "Commercial product from 2015 (no longer available)", + "with emoji (Alt) buttons", + "to insert various Unicode emoticons and other symbols.", + ), + description => [ + "Legacy EmojiWorks keyboard layout", + "for typing a selection of Unicode emoji symbols.", + ], + rows => [2, 1, 0], + moderows => '321-21', + image => 'data/keyboard/thumb/emojiworks.jpg', + flag => { + g2 => ['legacy' => "Already in Unicode 1.1 released in 1993 as text symbols"], + g3 => ['predated' => "Updates up to Unicode 5.2 between, retroactively emojified"], + g4 => ['first' => "Initial emoji support with Unicode 6.0 in 2010"], + g5 => ['update' => "Extensions in Unicode 6.1 and 7.0 (2014)"], + g7 => ['latest' => "Added in Unicode 8.0, in 2015 when these characters were selected"], + g9 => ['modifier' => "Fitzpatrick skin colour selection marks in Unicode 8.0"], + }, +} diff --git a/keyboard/altgr/eurkey.eng.inc.pl b/keyboard/altgr/eurkey.eng.inc.pl new file mode 100644 index 0000000..5b9702c --- /dev/null +++ b/keyboard/altgr/eurkey.eng.inc.pl @@ -0,0 +1,296 @@ +use utf8; +use strict; +use warnings; +use Shiar_Sheet::KeyboardChars 'kbmodes'; + +my $V = v1.3; + +my $presymbol = $V ge v1.3 ? '\\' : '-'; +my %rows = ( + '' => { + '1' => '¡', + '!' => '¹', + '2' => 'ª', + '@' => '²', + '3' => 'º', + '#' => '³', + '4' => $V ge v1.1 ? '£' : '€', + '$' => '¥', + '5' => $V ge v1.1 ? '€' : '£', + '%' => '¢', + '6' => "\N{COMBINING CIRCUMFLEX ACCENT}", + '^' => "\N{COMBINING CARON}", + '7' => "\N{COMBINING RING ABOVE}", + '&' => "\N{COMBINING MACRON}", + '8' => "\N{DOUBLE LOW-9 QUOTATION MARK}", + '*' => "\N{SINGLE LOW-9 QUOTATION MARK}", + '9' => "\N{LEFT DOUBLE QUOTATION MARK}", + '(' => "\N{LEFT SINGLE QUOTATION MARK}", + '0' => "\N{RIGHT DOUBLE QUOTATION MARK}", + ')' => "\N{RIGHT SINGLE QUOTATION MARK}", + '-' => $V ge v1.3 ? '✓' : '©', + '_' => $V ge v1.3 ? '✗' : '№', + '=' => '×', + '+' => '÷', + 'q' => 'æ', + 'Q' => 'Æ', + 'w' => 'å', + 'W' => 'Å', + 'e' => 'ë', + 'E' => 'Ë', + 'r' => 'ý', + 'R' => 'Ý', + 't' => 'þ', + 'T' => 'Þ', + 'y' => 'ÿ', + 'Y' => 'Ÿ', + 'u' => 'ü', + 'U' => 'Ü', + 'i' => 'ï', + 'I' => 'Ï', + 'o' => 'ö', + 'O' => 'Ö', + 'p' => 'œ', + 'P' => 'Œ', + '[' => '«', + '{' => '‹', + ']' => '»', + '}' => '›', + + 'a' => 'ä', + 'A' => 'Ä', + 's' => 'ß', + 'S' => $V ge v1.3 ? 'ẞ' : '¶', + 'd' => $V ge v1.2 ? 'đ' : 'ð', + 'D' => $V ge v1.2 ? 'Đ' : 'Ð', + 'f' => 'è', + 'F' => 'È', + 'g' => 'é', + 'G' => 'É', + 'h' => 'ù', + 'H' => 'Ù', + 'j' => 'ú', + 'J' => 'Ú', + 'k' => 'ij', + 'K' => 'IJ', + 'l' => 'ø', + 'L' => 'Ø', + ';' => $V ge v1.2 ? '°' : "\N{COMBINING DIAERESIS}", + ':' => '·', + "'" => "\N{COMBINING ACUTE ACCENT}", + '"' => $V ge v1.2 ? "\N{COMBINING DIAERESIS}" : '†', + '`' => "\N{COMBINING GRAVE ACCENT}", + '~' => "\N{COMBINING TILDE}", + + '\\'=> '¬', + '|' => '¦', + 'z' => 'à', + 'Z' => 'À', + 'x' => 'á', + 'X' => 'Á', + 'c' => 'ç', + 'C' => 'Ç', + 'v' => 'ì', + 'V' => 'Ì', + 'b' => 'í', + 'B' => 'Í', + 'n' => 'ñ', + 'N' => 'Ñ', + 'm' => 'Ω', + 'M' => '√', # ± + ',' => 'ò', + '<' => 'Ò', + '.' => 'ó', + '>' => 'Ó', + '/' => '¿', + '?' => '…', + }, + + # greek + 'm' => { + 'a' => 'α', + 'b' => 'β', # v + 'g' => 'γ', + 'd' => 'δ', + 'e' => 'ε', + 'z' => 'ζ', + 'i' => 'η', + 'h' => 'θ', + 'j' => 'ι', + 'k' => 'κ', + 'l' => 'λ', + 'm' => 'μ', + 'n' => 'ν', + 'x' => 'ξ', + 'o' => 'ο', + 'p' => 'π', + 'r' => 'ρ', + 's' => 'σ', + 't' => 'τ', + 'y' => 'υ', + 'f' => 'φ', + 'c' => 'χ', + 'w' => 'ψ', + 'q' => 'ω', # u + + # suþscript + '1' => '¹', + '2' => '²', + '3' => '³', + '4' => '⁴', + '5' => '⁵', + '6' => '⁶', + '7' => '⁷', + '8' => '⁸', + '9' => '⁹', + '0' => '⁰', + '!' => '₁', + '@' => '₂', + '#' => '₃', + '$' => '₄', + '%' => '₅', + '^' => '₆', + '&' => '₇', + '*' => '₈', + '(' => '₉', + ')' => '₀', + }, + + # maths + 'M' => { + '!' => '≠', + '~' => '≈', + '=' => '≝', + '>' => '≥', + '<' => '≤', + '-' => '±', + 'i' => '∞', + 'n' => 'ⁿ', + 'r' => '√', + '3' => '∛', + '4' => '∜', + '%' => '‰', + + 'f' => 'ƒ', + 'S' => '∫', + "'" => '′', + '"' => '″', + 'p' => '∂', + 'd' => 'Δ', + 'D' => '∇', + '+' => '⊕', + '*' => '⊗', + '^' => '℘', + + 's' => '∩', + 'u' => '∪', + 'U' => '∖', + 'O' => '∅', + 'g' => '⊂', + 'G' => '⊃', + 'h' => '⊄', + 'H' => '⊅', + 'b' => '⊆', + 'B' => '⊇', + 'm' => '∈', + 'M' => '∉', + 'k' => '∋', + 'K' => '∌', + + 'A' => '∀', + 'E' => '∃', + 'X' => '∄', + '&' => '∧', + '|' => '∨', + 'c' => '∝', + '.' => '⋅', + 'o' => '∘', + ':' => '∴', + ';' => '∵', + 'z' => '↯', + 'F' => '∎', + + 'R' => 'ℝ', + 'C' => 'ℂ', + 'N' => 'ℕ', + 'P' => 'ℙ', + 'Q' => 'ℚ', + 'Z' => 'ℤ', + '9' => '∟', + '8' => '∠', + '7' => '∡', + 'l' => '∥', + 'L' => '∦', + }, + + # symbols + $presymbol => { + 't' => '™', + 'c' => '©', + 'p' => '℗', + 'r' => '®', + $V lt v1.3 ? ( + '1' => '¼', + '2' => '½', + '3' => '¾', + '4' => '⅓', + '5' => '⅔', + 's' => '℠', + ) : ( + 's' => '§', + '1' => '№', + '2' => '½', + '3' => '⅓', + '4' => '¼', + '5' => '⅔', + '6' => '¾', + 'T' => '℠', + ), + + # arrows + 'h' => '←', + 'H' => '⇐', + 'j' => '↓', + 'J' => '⇓', + 'k' => '↑', + 'K' => '⇑', + 'l' => '→', + 'L' => '⇒', + 'u' => '↖', + 'U' => '⇖', + 'i' => '↗', + 'I' => '⇗', + 'n' => '↙', + 'N' => '⇙', + 'm' => '↘', + 'M' => '⇘', + '=' => '↔', + '+' => '⇔', + }, +); + ++{ + %{ kbmodes(\%rows) }, + mode => { + '' => 'option-shifted ⌥', + 'm' => 'Ω greek prefix ⌥m', + 'M' => '√ maths prefix ⌥M', + $presymbol => "$rows{''}{$presymbol} symbol prefix ⌥$presymbol", + }, + version => '1.1', + title => 'EurKEY', + category => 'latin/thirdparty', + intro => join("\n", + 'Third-party proposal EurKEY', + 'v1.3 by Steffen Brüntjen', + 'supporting most European languages while pressing AltGr or ⌥ Option.', + 'Selectable in Linux', + 'and available for Windows', + 'or macOS.', + ), + description => [ + "An interactive map of EurKEY, the European Keyboard Layout.", + ], + image => 'data/keyboard/thumb/eurkeyboard.jpg', + imagealt => 'Right alt on the EurKEYboard created by Psy-Q', +} diff --git a/keyboard/altgr/index.inc.plp b/keyboard/altgr/index.inc.plp new file mode 100644 index 0000000..d4d8bde --- /dev/null +++ b/keyboard/altgr/index.inc.plp @@ -0,0 +1,173 @@ +<: # included from keyboard.plp +use 5.014; +use warnings; +use utf8; + +my @incs = glob 'keyboard/altgr/*.eng.inc.pl'; + +Html({ + title => "altgr keyboard cheat sheets", + version => '1.2', + description => [ + "Overview of alternate keyboard modes,", + "offering extended Unicode characters if a modifier key", + "(such as AltGr or option) is pressed.", + ], + keywords => [qw' + sheet cheat reference overview keyboard altgr option + '], + image => 'data/keyboard/thumb/ibm-m.jpg', + stylesheet => [qw( light dark circus mono red )], + data => ['keyboard/altgr/index.inc.plp', @incs], + raw => <<'.', + +. +}); + +:> +

    Extended keyboards

    + +

    Overview of available key layouts with AltGr or similar modifier keys.

    + +<: +my @sample = split /(? qq{\N{TOP HAT}}, + windows => qq{\x{1FA9F}}, # \N{WINDOW} + macos => qq{\N{RED APPLE}}, + xorg => qq{\N{PENGUIN}}, +); + +printf '
    ', @sample ? 'section' : 'gallery'; +if (@sample) { + print ''; + print ''; +} +my %idx = map {s/\Q.inc.pl\E$//; ($_ => eval{ Data($_) })} @incs; +my $most = max(map { scalar keys %{$_->{def}{''}} } values %idx); +for my $inc (sort { + $idx{$a}{category} cmp $idx{$b}{category} || $a cmp $b +} keys %idx) { + print @sample ? ''; + } +} +print '
    '; + print "$_" for @sample; + say '
    ' : '
    '; + printf '', $inc =~ s/\.eng$//r; + my $table = $idx{$inc}; + my $title = $table && $table->{title} || $inc; + + unless (@sample) { + if ($table and my $img = $table->{image}) { + EscapeHTML $name = $table->{imagealt} // $img =~ m{.*/([^/.]*)}; + print qq{$name}; + } + printf '
    %s
    ', $title; + say '
    '; + } + else { + print $title; + print '', "\n\t"; + my $keys = Shiar_Sheet::Keyboard->new($table); + for my $mode ($keys->{mode} ? sort keys %{ $keys->{mode} } : '') { + my %inventory; + $inventory{$_}++ for grep { /^g[2-9]/ } map { s/ (?!ext).*//r } + values %{ $keys->{def}{$mode} }; + print ''; + print "" for $keys->{key}{$mode} =~ s/\s.*//r || (); + for my $g (sort keys %inventory) { + printf ' %s', + $g, $_/$most*100, $_, + join(' ', map { + $keys->{flag}{$_}[0] || 'extra' # legend label of each class + } reverse split / /, $g) + for $inventory{$g}; + } + say ''; + } + print "\t
    "; + print join ' ', map { $caticon{$_} // () } split m{/}, $keys->{category}; + say ''; + $keys->print_key('', $_, $keys->{def}{''}{$_} // 'ni') for @sample; + say '
    ' if @sample; +:>
    + diff --git a/keyboard/altgr/ipa.eng.inc.pl b/keyboard/altgr/ipa.eng.inc.pl new file mode 100644 index 0000000..4fc3cd5 --- /dev/null +++ b/keyboard/altgr/ipa.eng.inc.pl @@ -0,0 +1,147 @@ +use utf8; +use strict; +use warnings; +use Shiar_Sheet::KeyboardChars 'kbmodes'; + +my %rows = ( + '' => { + '`' => 'ǀ', + '+`' => "\N{MODIFIER LETTER RHOTIC HOOK}", + '~' => "\N{COMBINING LEFT ANGLE ABOVE}", + '+1' => 'ɨ', + '1' => 'ɴ', + '!' => 'ǃ', + '+2' => 'ø', + '2' => 'ǁ', + '@' => 'ˈ', + '#' => 'ɹ', + '3' => 'ɻ', + '+3'=> 'ɜ', + '4' => 'ɽ', + '+4' => 'ɾ', + '$' => '$', + '+5' => 'ɫ', + '5' => 'ʟ', + '%' => 'ˌ', + '+6' => 'ɐ', + '6' => 'ɓ', + '^' => "\N{COMBINING INVERTED BREVE BELOW}", + '+7' => 'ɤ', + '7' => 'ˠ', + '&' => 'ɶ', + '+8' => 'ɵ', + '8' => 'ɞ', + '*' => '*', + '9' => 'ɠ', + '+9' => 'œ', + '(' => '(', + '0' => "\N{COMBINING RING ABOVE}", + '+0' => "\N{COMBINING RING BELOW}", + ')' => ')', + '-' => "\N{COMBINING DOUBLE INVERTED BREVE}", + '_' => '‿', + '+-'=> '-', + '+' => '+', + '+=' => "\N{COMBINING VERTICAL LINE BELOW}", + '=' => 'ǂ', + + 'Q' => 'ɒ', + 'q' => "\N{COMBINING UP TACK BELOW}", + 'W' => 'ʍ', + 'w' => 'ʷ', + 'E' => 'ɛ', + 'e' => 'ɘ', + 'r' => 'ʀ', + 'R' => 'ʁ', + 'T' => 'θ', + 't' => 'ʈ', + 'Y' => 'ʏ', + 'y' => "\N{COMBINING DOWN TACK BELOW}", + 'u' => 'ɦ', + 'U' => 'ʊ', + 'I' => 'ɪ', + 'i' => "\N{COMBINING PLUS SIGN BELOW}", + 'O' => 'ɔ', + 'o' => 'ʘ', + 'P' => 'ʋ', + 'p' => 'ɸ', + '{' => 'æ', + '[' => 'ɗ', + '}' => 'ʉ', + ']' => "\N{COMBINING BRIDGE BELOW}", + + 'A' => 'ɑ', + 'a' => "\N{COMBINING MINUS SIGN BELOW}", + 'S' => 'ʃ', + 's' => 'ʂ', + 'D' => 'ð', + 'd' => 'ɖ', + 'F' => 'ɱ', + 'f' => 'ɟ', + 'g' => 'ɢ', + 'G' => 'ɣ', + 'H' => 'ɥ', + 'h' => 'ʰ', + 'J' => 'ɲ', + 'j' => 'ʝ', + 'K' => 'ɬ', + 'k' => 'ɮ', + 'L' => 'ʎ', + 'l' => 'ɭ', + "'" => 'ɚ', + "+'" => 'ʲ', + '"' => 'ə', + ';' => "\N{COMBINING DIAERESIS}", + ':' => 'ː', + '|' => "\N{COMBINING TILDE}", + '\\'=> "\N{COMBINING TILDE BELOW}", + + 'z' => 'ʐ', + 'Z' => 'ʒ', + 'X' => 'χ', + 'x' => 'ħ', + 'C' => 'ç', + 'c' => 'ɕ', + 'v' => 'ʑ', + 'V' => 'ʌ', + 'b' => 'ʙ', + 'B' => 'β', + 'N' => 'ŋ', + 'n' => 'ɳ', + 'M' => 'ɯ', + 'm' => 'ɰ', + '<' => "\N{COMBINING BREVE}", + ',' => 'ʼ', + '.' => "\N{COMBINING DIAERESIS BELOW}", + '>' => '→', + '?' => 'ʔ', + '/' => 'ʕ', + }, +); + +# missing: ʤ ɜ ɝ ʄ ɡ ʛ ɧ ʜ ɺ ʧ ⱱ ʡ ʢ + ++{ + %{ kbmodes(\%rows) }, + version => '1.0', + title => 'UCL phonetic', + category => 'specialised', + intro => join("\n", + 'Unicode Phonetic Keyboard', + 'v1.10 by Mark Huckvale', + 'from UCL, available for', + 'Windows,', + 'providing Unicode symbols', + 'with Shift (top row) and Altgr', + 'to transcribe (at least English) sounds', + 'in IPA.', + ), + description => [ + "UCL Unicode Phonetic Keyboard layout table", + "with the AltGr modifier key.", + ], + image => 'data/keyboard/thumb/uclphonetics.jpg', + imagealt => 'Mechanical typewriter somehow wrote ˈɪŋglɪʃ fəˈnɛtɪks', + rows => [3,1,0], + moderows => '21-241', +} diff --git a/keyboard/altgr/macos-abc.eng.inc.pl b/keyboard/altgr/macos-abc.eng.inc.pl new file mode 100644 index 0000000..2c9f729 --- /dev/null +++ b/keyboard/altgr/macos-abc.eng.inc.pl @@ -0,0 +1,214 @@ +use utf8; +use strict; +use warnings; +use Shiar_Sheet::KeyboardChars 'kbmodes'; + +my %rows = ( + '' => { + 'A' => "\N{MACRON}", + 'a' => "\N{COMBINING MACRON}", + 'B' => "\N{BREVE}", + 'b' => "\N{COMBINING BREVE}", + 'C' => "\N{CEDILLA}", + 'c' => "\N{COMBINING CEDILLA}", + 'D' => 'Ð', + 'd' => 'ð', + 'E' => "\N{ACUTE ACCENT}", + 'e' => "\N{COMBINING ACUTE ACCENT}", + 'f' => 'ƒ', + 'F' => "\N{COMBINING TILDE BELOW}", + 'G' => "\N{COMBINING CIRCUMFLEX ACCENT BELOW}", + 'g' => '©', + 'H' => "\N{MODIFIER LETTER LOW MACRON}", + 'h' => "\N{COMBINING MACRON BELOW}", + 'I' => "\N{MODIFIER LETTER APOSTROPHE}", + 'i' => "\N{COMBINING COMMA ABOVE}", + 'J' => "\N{DOUBLE ACUTE ACCENT}", + 'j' => "\N{COMBINING DOUBLE ACUTE ACCENT}", + 'K' => '°', + 'k' => "\N{COMBINING RING ABOVE}", + 'L' => '-', + 'l' => "\N{COMBINING SHORT STROKE OVERLAY}", #XXX + 'M' => "\N{OGONEK}", + 'm' => "\N{COMBINING OGONEK}", + 'N' => "\N{SMALL TILDE}", + 'n' => "\N{COMBINING TILDE}", + 'O' => 'Ø', + 'o' => 'ø', + 'P' => "\N{SINGLE LOW-9 QUOTATION MARK}", #XXX + 'p' => "\N{COMBINING COMMA BELOW}", + 'Q' => 'Œ', + 'q' => 'œ', + 'R' => '‰', + 'r' => '®', + 'S' => "\N{COMBINING INVERTED BREVE}", + 's' => 'ß', + 'T' => 'Þ', + 't' => 'þ', + 'U' => "\N{DIAERESIS}", + 'u' => "\N{COMBINING DIAERESIS}", + 'V' => "\N{CARON}", + 'v' => "\N{COMBINING CARON}", + 'W' => "\N{DOT ABOVE}", + 'w' => "\N{COMBINING DOT ABOVE}", + 'X' => "\N{MODIFIER LETTER LOW RING}", #XXX + 'x' => "\N{COMBINING DOT BELOW}", + 'Y' => "\N{COMBINING DOUBLE GRAVE ACCENT}", + 'y' => '¥', + 'Z' => "\N{MODIFIER LETTER GLOTTAL STOP}", + 'z' => "\N{COMBINING HOOK ABOVE}", + '[' => "\N{LEFT DOUBLE QUOTATION MARK}", + '{' => "\N{RIGHT DOUBLE QUOTATION MARK}", + ']' => "\N{LEFT SINGLE QUOTATION MARK}", + '}' => "\N{RIGHT SINGLE QUOTATION MARK}", + ';' => '…', + ':' => '№', + '"' => 'Æ', + "'" => 'æ', + '|' => '»', + '\\'=> '«', + '<' => "\N{DOUBLE LOW-9 QUOTATION MARK}", + ',' => '≤', + '>' => 'ʔ', + '.' => '≥', + '/' => '÷', + '?' => '¿', + '~' => "\N{GRAVE ACCENT}", + '`' => "\N{COMBINING GRAVE ACCENT}", + '1' => '¡', + '!' => '⁄', + '2' => '™', + '@' => '€', + '3' => '£', + '#' => '‹', + '4' => '¢', + '$' => '›', + '5' => '§', + '%' => '†', + '6' => "\N{COMBINING CIRCUMFLEX ACCENT}", + '^' => "\N{MODIFIER LETTER CIRCUMFLEX ACCENT}", #XXX + '7' => '¶', + '&' => '‡', + '8' => '•', + '*' => '°', + '9' => 'ª', + '(' => '·', + '0' => 'º', + ')' => '‚', + '-' => '–', + '_' => '—', + '+' => '±', + '=' => '≠', + }, + + ':' => { + '@' => 'Ƨ', + '2' => 'ƨ', + '#' => 'Ɛ', + '3' => 'ɛ', + '%' => 'Ƽ', + '5' => 'ƽ', + '^' => 'Ƅ', + '6' => 'ƅ', #XXX + '7' => '⁊', + '*' => 'Ȣ', + '8' => 'ȣ', + 'Q' => 'Ƣ', + 'q' => 'ƣ', + 'W' => 'Ƿ', + 'w' => 'ƿ', + 'E' => 'Ǝ', + 'e' => 'ǝ', #XXX ə + 'R' => 'Ʀ', + 'r' => 'ʀ', #XXX + 'k' => 'ĸ', + 'Y' => 'Ɜ', + 'y' => 'ɜ', + 'U' => 'Ʊ', + 'u' => 'ʊ', + 'A' => 'Ə', + 'a' => 'ə', + 's' => 'ſ', + 'G' => 'Ɣ', + 'g' => 'ɣ', + 'H' => 'Ƕ', + 'h' => 'ƕ', + 'J' => 'Ƞ', + 'j' => 'ƞ', #XXX ɳ + 'K' => 'Ǩ', + 'Z' => 'Ʒ', + 'z' => 'ʒ', + 'C' => 'Ɔ', + 'c' => 'ɔ', + 'v' => 'ʌ', + 'N' => 'Ŋ', #XXX + 'n' => 'ŋ', + 'M' => 'Ɯ', + 'm' => 'ɯ', + '"' => '″', #XXX ʺ + "'" => '′', #XXX ʹ + }, + + '>' => { + 'q' => 'ʠ', + 'R' => 'Ʈ', #XXX mirrored? + 'r' => 'ʈ', + 'T' => 'Ƭ', + 't' => 'ƭ', + 'Y' => 'Ƴ', + 'y' => 'ƴ', + 'U' => 'Ʋ', + 'u' => 'ʋ', + 'I' => 'Ɩ', + 'i' => 'ɩ', + 'P' => 'Ƥ', + 'p' => 'ƥ', + 'S' => 'Ʃ', + 's' => 'ʃ', + 'D' => 'Ɗ', + 'd' => 'ɗ', + 'F' => 'Ƒ', + 'f' => 'ƒ', + 'G' => 'Ɠ', + 'g' => 'ɠ', + 'h' => 'ɦ', + 'K' => 'Ƙ', + 'k' => 'ƙ', + 'Z' => 'Ȥ', + 'z' => 'ȥ', + 'X' => 'Ɖ', + 'x' => 'ɖ', + 'C' => 'Ƈ', + 'c' => 'ƈ', + 'N' => 'Ɲ', + 'n' => 'ɲ', + 'B' => 'Ɓ', + 'b' => 'ɓ', + }, +); + ++{ + %{ kbmodes(\%rows) }, + mode => { + '' => 'option-shifted ⌥', + ':' => '№ number prefix ⌥:', + '>' => 'ʔ hook prefix ⌥>', + }, + version => '1.0', + title => 'ABC option', + category => '2/latin/macos', + intro => join("\n", + 'Resulting selection of Unicode characters', + "while pressing ⌥ Option (Alt) with Apple's ABC Extended", + "(formerly US Extended and Extended Roman) layout", + 'on macOS.', + 'Significant changes from standard', + 'US or local options.', + ), + description => [ + "Apple ABC Extended keyboard layout table", + "with the Option modifier key.", + ], + image => 'data/keyboard/thumb/macbook-gray.jpg', + imagealt => 'Option key on a black MacBook', +} diff --git a/keyboard/altgr/macos.eng.inc.pl b/keyboard/altgr/macos.eng.inc.pl new file mode 100644 index 0000000..15b0a7f --- /dev/null +++ b/keyboard/altgr/macos.eng.inc.pl @@ -0,0 +1,121 @@ +use utf8; +use strict; +use warnings; +use Shiar_Sheet::KeyboardChars 'kbchars'; + +my %rows = ( + 'A' => 'Å', + 'a' => 'å', + 'B' => 'ı', + 'b' => '∫', + 'C' => 'Ç', + 'c' => 'ç', + 'D' => 'Î', + 'd' => '∂', + 'E' => "\N{ACUTE ACCENT}", + 'e' => "\N{COMBINING ACUTE ACCENT}", + 'f' => 'ƒ', + 'F' => 'Ï', + 'G' => "\N{DOUBLE ACUTE ACCENT}", + 'g' => '©', + 'H' => 'Ó', + 'h' => "\N{DOT ABOVE}", + 'I' => "\N{MODIFIER LETTER CIRCUMFLEX ACCENT}", + 'i' => "\N{COMBINING CIRCUMFLEX ACCENT}", + 'J' => 'Ô', + 'j' => '∆', + 'K' => '', + 'k' => '°', + 'L' => 'Ò', + 'l' => '¬', + 'M' => 'Â', + 'm' => 'µ', + 'N' => "\N{SMALL TILDE}", + 'n' => "\N{COMBINING TILDE}", + 'O' => 'Ø', + 'o' => 'ø', + 'P' => '∏', + 'p' => 'π', + 'Q' => 'Œ', + 'q' => 'œ', + 'R' => '‰', + 'r' => '®', + 'S' => 'Í', + 's' => 'ß', + 'T' => "\N{CARON}", + 't' => '†', + 'U' => "\N{DIAERESIS}", + 'u' => "\N{COMBINING DIAERESIS}", + 'V' => '◊', + 'v' => '√', + 'W' => '„', + 'w' => '∑', + 'X' => "\N{OGONEK}", + 'x' => '≈', + 'Y' => 'Á', + 'y' => '¥', + 'Z' => "\N{CEDILLA}", + 'z' => 'Ω', + '[' => "\N{LEFT DOUBLE QUOTATION MARK}", + '{' => "\N{RIGHT DOUBLE QUOTATION MARK}", + ']' => "\N{LEFT SINGLE QUOTATION MARK}", + '}' => "\N{RIGHT SINGLE QUOTATION MARK}", + ':' => 'Ú', + ';' => '…', + '"' => 'Æ', + "'" => 'æ', + '|' => '»', + '\\'=> '«', + '<' => "\N{MACRON}", + ',' => '≤', + '>' => "\N{BREVE}", + '.' => '≥', + '/' => '÷', + '?' => '¿', + '~' => "\N{GRAVE ACCENT}", + '`' => "\N{COMBINING GRAVE ACCENT}", + '1' => '¡', + '!' => '⁄', + '2' => '™', + '@' => '€', + '3' => '£', + '#' => '‹', + '4' => '¢', + '$' => '›', + '5' => '∞', + '%' => 'fi', + '6' => '§', + '^' => 'fl', + '7' => '¶', + '&' => '‡', + '8' => '•', + '*' => '°', + '9' => 'ª', + '(' => '·', + '0' => 'º', + ')' => '‚', + '-' => '–', + '_' => '—', + '+' => '±', + '=' => '≠', +); + ++{ + %{ kbchars(\%rows) }, + version => '1.3', + title => 'US option', + category => '2/latin/macos', + intro => join("\n", + 'Resulting selection of Unicode characters', + "while pressing ⌥ Option (Alt) with Apple's US (or US International) layout", + 'on macOS.', + q{An alternative ABC Extended is also available.}, + q{Different from AltGr on Windows.}, + ), + description => [ + "Apple US International keyboard layout table", + "with the Option modifier key.", + ], + image => 'data/keyboard/thumb/matias-fk302.jpg', + imagealt => 'Option key on a Matias Tactile Pro keyboard with USA keycaps', +} diff --git a/keyboard/altgr/msx-graph.eng.inc.pl b/keyboard/altgr/msx-graph.eng.inc.pl new file mode 100644 index 0000000..3bcf5d1 --- /dev/null +++ b/keyboard/altgr/msx-graph.eng.inc.pl @@ -0,0 +1,158 @@ +use utf8; +use strict; +use warnings; +use Shiar_Sheet::KeyboardChars 'kbchars'; +our %get; + +my %rows = ( + '1' => '¼', + '@' => '²', + '2' => '½', + '#' => 'ⁿ', + '3' => '¾', + '4' => '∩', + '5' => '‰', + '^' => '⌡', + '6' => '⌠', + '7' => '√', + '8' => '∞', + '(' => '◘', # inverted · + '9' => '·', # smaller than • + ')' => '◙', + '0' => '○', + '_' => '🮯', + '-' => '─', + '+' => '≡', + '=' => '±', + '~' => '≈', + '`' => '∽', + + 'Q' => '🮙', + 'q' => '🮘', + 'W' => '🭮', + 'w' => '🭬', + 'E' => '🭯', + 'e' => '🭭', + 'R' => '⌐', + 'r' => '┌', + 't' => '┬', + 'Y' => '¬', + 'y' => '┐', + 'U' => '🮅', + 'u' => '▂', + 'I' => '▀', + 'i' => '▄', + 'O' => '🮂', + 'o' => '▆', + 'P' => '🮖', + 'p' => '█', + '[' => '☺', + '{' => '☻', + ']' => '♪', + '}' => '♫', + + 'A' => '▮', + 'a' => '▬', + 'S' => '🮚', + 's' => '🮛', + 'D' => '▚', + 'd' => '▞', + 'F' => '▗', + 'f' => '├', + 'G' => '⟊', # ┼ without connecting right + 'g' => '┼', + 'H' => '▖', + 'h' => '┤', + 'J' => '🮊', + 'j' => '▎', + 'K' => '▐', + 'k' => '▌', + 'L' => '🮇', + 'l' => '▊', + '"' => '♥', + "'" => '♣', + ':' => '♦', + ';' => '♠', + '|' => '│', + '\\'=> '╲', + + 'Z' => '◦', # small white circle + 'z' => '☼', + 'X' => '•', # small black circle + 'x' => '╳', + 'C' => '⁃', + 'c' => '◇', # ◊ + 'V' => '▝', + 'v' => '└', + 'B' => '▬', + 'b' => '┴', + 'N' => '▘', + 'n' => '┘', + 'M' => '♀', + 'm' => '♂', + '<' => '«', + ',' => '≤', + '>' => '»', + '.' => '≥', + '?' => '÷', + '/' => '╱', + +); + +my %compat = ( + 'Q' => '▨', + 'q' => '▧', + 'W' => '◀', # + 'w' => '▶', + 'E' => '▲', + 'e' => '▼', # + 'U' => '▓', + 'J' => '░', + 'O' => '▔', + 'P' => '▒', + 'S' => '⧗', + 's' => '⧓', + 'G' => '╂', + '_' => '┿', + 'L' => '▕', +); + +if (exists $get{compat}) { + %rows = (%rows, %compat); +} + +my $groups = kbchars(\%rows); + +# replace rare punctuation distinctions by symbols +$groups->{def}{''}{$_} =~ s/g[78]/g6/ for keys %rows; + +$groups->{def}{''}{$_} = 'g7' + for grep { $rows{$_} =~ /[\x{2500}-\x{259F}]/ } keys %rows; +$groups->{flag}{g7} = ['drawing', 'box drawing or block elements']; + +$groups->{def}{''}{$_} = 'g8' for keys %compat; # mostly U+1FBxx +$groups->{flag}{g8} = ['legacy', + 'drawing symbols best represented by Unicode 13.0' + . (exists $get{compat} && ', converted to compatible equivalents') +]; + ++{ + %{ $groups }, + version => '1.0', + title => 'MSX graph', + category => 'legacy/msx', + intro => join("\n", + 'Resulting selection', + 'of equivalent Unicode characters', + "when the graph key is pressed on an MSX home computer", + "(International model such as Toshiba HX10 or Phillips NMS 8245).", + 'See also letters and symbols', + "from pressing code.", + ), + description => [ + "MSX keyboard layout table", + "with the graph modifier key.", + ], + image => 'data/keyboard/thumb/msxgraph.jpg', + imagealt => 'Graph key on a Toshiba HX10 with graph labels', +} diff --git a/keyboard/altgr/msx.eng.inc.pl b/keyboard/altgr/msx.eng.inc.pl new file mode 100644 index 0000000..a7d8c0b --- /dev/null +++ b/keyboard/altgr/msx.eng.inc.pl @@ -0,0 +1,116 @@ +use utf8; +use strict; +use warnings; +use Shiar_Sheet::KeyboardChars 'kbchars'; + +my %rows = ( + '!' => '¡', + '1' => 'ƒ', + '@' => '₧', + '2' => '‡', + '#' => '¶', + '3' => '§', + '$' => '£', + '4' => '¢', + '%' => '¥', + '5' => 'ÿ', + '6' => 'α', + '7' => 'ß', + '*' => 'Γ', + '8' => 'γ', + '(' => 'Ç', + '9' => 'ç', + ')' => 'Δ', + '0' => 'δ', + '-' => '∈', + '=' => 'ϴ', + '\\'=> '£', + + 'q' => 'â', + 'w' => 'ê', + 'e' => 'î', + 'r' => 'ô', + 't' => 'û', + 'y' => 'á', + 'U' => 'É', + 'u' => 'é', + 'i' => 'í', + 'o' => 'ó', + 'P' => 'Π', + 'p' => 'ú', + '{' => 'Φ', + '[' => 'ø', + '}' => 'Ω', + ']' => 'ω', + + 'A' => 'Ä', + 'a' => 'ä', + 's' => 'ë', + 'd' => 'ï', + 'F' => 'Ö', + 'f' => 'ö', + 'G' => 'Ü', + 'g' => 'ü', + 'H' => 'Ã', + 'h' => 'ã', + 'J' => 'Æ', + 'j' => 'æ', + 'K' => 'Ĩ', + 'k' => 'ĩ', + 'L' => 'Õ', + 'l' => 'õ', + ':' => 'Ũ', + ';' => 'ũ', + '"' => 'IJ', + "'" => 'ij', + '~' => 'Σ', + '`' => 'σ', + + 'z' => 'à', + 'x' => 'è', + 'c' => 'ì', + 'v' => 'ò', + 'b' => 'ù', + 'N' => 'Ñ', + 'n' => 'ñ', + 'm' => 'μ', + '<' => 'Å', + ',' => 'å', + '.' => 'ª', + '?' => '¿', + '/' => 'º', +); + +my %uc = ( + (map { (uc $_ => uc $rows{$_}) } grep { + !defined $rows{uc $_} + } keys %rows), + '|' => '€', + 'M' => 'Ú', + '+' => 'Ø', +); + +my $groups = kbchars({%rows, %uc}); +$groups->{def}{''}{$_} .= ' ext' for keys %uc; +$groups->{flag}{ext} = ['anachrone', 'expected uppercase variants if allowed by charset']; + ++{ + %{ $groups }, + version => '1.2', + title => 'MSX code', + category => 'legacy/msx/latin', + intro => join("\n", + 'Resulting selection', + 'of equivalent Unicode characters', + "when the code key is pressed on an MSX home computer", + "(International model such as Toshiba HX10 or Phillips NMS 8245).", + 'See also block graphics', + "from pressing graph.", + ), + description => [ + "MSX keyboard layout table", + "with the code modifier key.", + ], + image => 'data/keyboard/thumb/msxcode.jpg', + imagealt => 'Code key on a Toshiba HX10 with graph labels', +} diff --git a/keyboard/altgr/olpc.eng.inc.pl b/keyboard/altgr/olpc.eng.inc.pl new file mode 100644 index 0000000..3d72e36 --- /dev/null +++ b/keyboard/altgr/olpc.eng.inc.pl @@ -0,0 +1,94 @@ +use utf8; +use strict; +use warnings; +no warnings 'qw'; +use Shiar_Sheet::KeyboardChars 'kbchars'; + +my %rows = ( + '1' => '¡', + '2' => '¬', + '3' => "\N{COMBINING GRAVE ACCENT}", + '4' => "\N{COMBINING ACUTE ACCENT}", + '5' => "\N{COMBINING BREVE}", + '6' => "\N{COMBINING RING ABOVE}", + '7' => "\N{COMBINING CIRCUMFLEX ACCENT}", + '8' => "\N{COMBINING CARON}", + '9' => "\N{COMBINING DOT ABOVE}", + '0' => "\N{COMBINING DIAERESIS}", + '-' => "\N{COMBINING MACRON}", + '=' => "\N{COMBINING TILDE}", + + 'q' => 'ω', + 'Q' => 'Ω', + 'w' => 'ø', + 'W' => 'Ø', + 'e' => 'œ', + 'E' => 'Œ', + 'r' => "\N{COMBINING CEDILLA}", + 't' => "\N{COMBINING BREVE BELOW}", + 'y' => "\N{COMBINING RING BELOW}", + 'u' => "\N{COMBINING CIRCUMFLEX ACCENT BELOW}", + 'i' => "\N{COMBINING CARON BELOW}", + 'o' => "\N{COMBINING DOT BELOW}", + 'p' => "\N{COMBINING DIAERESIS BELOW}", + '[' => "\N{COMBINING MACRON BELOW}", + ']' => "\N{COMBINING TILDE BELOW}", + + 'a' => 'æ', + 'A' => 'Æ', + 's' => 'ß', + 'S' => 'ẞ', + 'd' => 'ð', + 'D' => 'Ð', + 'f' => 'þ', + 'F' => 'Þ', + 'h' => '£', + 'j' => '€', + ';' => 'º', + ':' => 'ª', + "'" => '¤', + '\\'=> '§', + + 'c' => 'ç', + 'C' => 'Ç', + 'n' => 'ñ', + 'N' => 'Ñ', + 'm' => "\N{MICRO SIGN}", + ',' => '«', + '.' => '»', + '/' => '¿', +); + +my %shift = ( + qw[ ! 1 @ 2 # 3 $ 4 % 5 ^ 6 & 7 * 8 ( 9 ) 0 _ - + = ], + qw( { [ } ] " ' | \ < , > . ? / ` 3 ~ = ), + (map {uc, lc} qw[ r t y u i o p h j m ]), +); +$rows{$_} = $rows{ $shift{$_} } for keys %shift; # alias shifted + +my $groups = kbchars(\%rows); +$groups->{flag}{ext} = ['alias', 'identical results from unshifted key']; +$groups->{def}{''}{$_} .= ' ext' for keys %shift; # mark aliases + ++{ + %{ $groups }, + version => '1.0', + title => 'OLPC', + category => 'legacy/latin/xorg', + intro => join("\n", + "International US English developed for the OLPC project,", + 'providing mostly European', + 'Unicode characters while pressing AltGr,', + 'entirely different from the Windows', + 'or MacOS maps.', + ), + description => [ + "OLPC keyboard layout table", + "with the AltGr modifier key:", + "provides common western European letters and symbols,", + "and various combining accents above and below.", + ], + image => 'data/keyboard/thumb/olpc.jpg', + imagealt => 'AltGr on the OLPC XO Laptop', + moderows => '21-1', +} diff --git a/keyboard/altgr/spacecadet.eng.inc.pl b/keyboard/altgr/spacecadet.eng.inc.pl new file mode 100644 index 0000000..740dd35 --- /dev/null +++ b/keyboard/altgr/spacecadet.eng.inc.pl @@ -0,0 +1,117 @@ +use utf8; +use strict; +use warnings; +use Shiar_Sheet::KeyboardChars 'kbchars'; + +my %rows = ( + 'q' => '∧', + 'w' => '∨', + 'e' => '∩', + 'r' => '∪', + 't' => '⊂', + 'y' => '⊃', + 'u' => '∀', + 'i' => '∞', + 'o' => '∃', + 'p' => '∂', + + 'a' => '⊥', + 's' => '⊤', + 'd' => '⊢', + 'f' => '⊣', + 'g' => '↑', + 'h' => '↓', + 'j' => '←', + 'k' => '→', + 'l' => '↔', + + 'z' => '⌊', + 'x' => '⌈', + 'c' => '≠', + 'v' => '≃', + 'b' => '≡', + 'n' => '≤', + 'm' => '≥', + #',' => '<', # just shifted + #'.' => '>', + #'/' => '?', + + '+:' => '⋄', # positioned left of 1, also drawn as §-ish + '+1' => '†', + '+2' => '‡', + '+3' => '∇', + '+4' => '¢', + '+5' => '∘', + '+6' => '⎕', # or ⌷ + '+7' => '÷', + '+8' => '×', + '+9' => '¶', + '+0' => '○', + '+-' => '¯', + '+=' => '≈', + + '+q' => 'θ', + '+w' => 'ω', + '+e' => 'ε', + '+r' => 'ρ', + '+t' => 'τ', + '+y' => 'ψ', + '+u' => 'υ', + '+i' => 'ι', + '+o' => 'ο', + '+p' => 'π', + '+[' => '⟦', # separate keys ([ and {< + '+]' => '⟧', # )] and }> ⟨⟩ + '+`' => '¬', # positioned between ] and \ + '+\\'=> '∥', + + '+a' => 'α', + '+s' => 'σ', + '+d' => 'δ', + '+f' => 'φ', # drawn like ø + '+g' => 'γ', + '+h' => 'η', + '+j' => 'ϑ', # probably + '+k' => 'κ', + '+l' => 'λ', + '+;' => '¨', + "+'" => '·', # ambiguous dot (visually raised •) + + '+z' => 'ζ', + '+x' => 'ξ', + '+c' => 'χ', + '+v' => 'ς', # likely + '+b' => 'β', + '+n' => 'ν', + '+m' => 'μ', + '+,' => '≪', + '+.' => '≫', + '+/' => '∫', +); + +my $groups = kbchars(\%rows); +$rows{$_} =~ /\A\p{Greek}/ and $groups->{def}{''}{$_} =~ s/g6/g5/ for map {"+$_"} 'a'..'z'; +$groups->{flag}{g4} = ['similar', 'transliterates or transcribes an expected letter']; +$groups->{flag}{g5} = ['greek', 'different Greek letters or symbols']; + ++{ + %{$groups}, + version => '1.1', + title => 'Space Cadet', + category => 'legacy', + intro => join("\n", + 'Apparent glyphs available', + 'on the 1978 (later Symbolics) Space Cadet keyboard', + 'by pressing either the Greek/Front or Top key.', + 'Distinct from the modern IBM standard', + 'for APL programming.', + ), + description => [ + 'A map of the legendary Space Cadet keyboard', + 'with Unicode characters of all greek and APL options.', + ], + rows => [3, 0], # greek/front and top + moderows => '41-4', + image => 'data/keyboard/thumb/spacecadet.jpg', + imagealt => 'Many modifier keys on a traditional Symbolics Space Cadet keyboard', +} diff --git a/keyboard/altgr/symbolics.eng.inc.pl b/keyboard/altgr/symbolics.eng.inc.pl new file mode 100644 index 0000000..b0c3a1e --- /dev/null +++ b/keyboard/altgr/symbolics.eng.inc.pl @@ -0,0 +1,133 @@ +use utf8; +use strict; +use warnings; +use Shiar_Sheet::KeyboardChars 'kbchars'; + +my %rows = ( + '!' => "\xAC", + '"' => "\x{2190}", + '#' => "\xA3", + '$' => "\x{20AC}", + '%' => "\x{2030}", + '&' => "\xA7", + "'" => "\x{2192}", + '(' => "\xB7", + ')' => "\xB0", + '*' => "\x{221E}", + '+' => "\xF7", + ',' => "\x{2264}", + '-' => "\x{2260}", + '.' => "\x{2265}", + '/' => "\x{203D}", + '0' => "\x{2070}", + '1' => "\xB9", + '2' => "\xB2", + '3' => "\xB3", + '4' => "\x{2074}", + '5' => "\x{2075}", + '6' => "\x{2076}", + '7' => "\x{2077}", + '8' => "\x{2078}", + '9' => "\x{2079}", + ':' => "\x{2191}", + ';' => "\x{2193}", + '<' => "\xAB", + '=' => "\xD7", + '>' => "\xBB", + '?' => "\x{2766}", + '@' => "\x{2234}", + '[' => "\x{222A}", + '\\'=> "`", + '|' => "~", + '`' => "\\", + '~' => "|", + ']' => "\x{2282}", + '^' => "\x{221A}", + '_' => "\xB1", + 'A' => "\x{391}", + 'a' => "\x{3B1}", + 'B' => "\x{392}", + 'b' => "\x{3B2}", + 'c' => "\x{3C8}", + 'C' => "\x{3A8}", + 'D' => "\x{394}", + 'd' => "\x{3B4}", + 'E' => "\x{395}", + 'e' => "\x{3B5}", + 'F' => "\x{3A6}", + 'f' => "\x{3C6}", + 'g' => "\x{3B3}", + 'G' => "\x{393}", + 'H' => "\x{397}", + 'h' => "\x{3B7}", + 'i' => "\x{3B9}", + 'I' => "\x{399}", + 'j' => "\x{3BE}", + 'J' => "\x{39E}", + 'k' => "\x{3BA}", + 'K' => "\x{39A}", + 'l' => "\x{3BB}", + 'L' => "\x{39B}", + 'M' => "\x{39C}", + 'm' => "\x{3BC}", + 'n' => "\x{3BD}", + 'N' => "\x{39D}", + 'O' => "\x{39F}", + 'o' => "\x{3BF}", + 'p' => "\x{3C0}", + 'P' => "\x{3A0}", + 'Q' => "\x{2203}", + 'q' => "\x{2200}", + 'R' => "\x{3A1}", + 'r' => "\x{3C1}", + 'S' => "\x{3A3}", + 's' => "\x{3C3}", + 'T' => "\x{3A4}", + 't' => "\x{3C4}", + 'u' => "\x{3B8}", + 'U' => "\x{398}", + 'v' => "\x{3C9}", + 'V' => "\x{3A9}", + 'w' => "\x{2208}", + 'W' => "\x{2209}", + 'x' => "\x{3C7}", + 'X' => "\x{3A7}", + 'Y' => "\x{3A5}", + 'y' => "\x{3C5}", + 'z' => "\x{3B6}", + 'Z' => "\x{396}", + '{' => "\x{2229}", + '}' => "\x{2283}", + + # LSGT (iso key) brackets at TLDE/BKSL inversions + '`' => "\x{230A}", + '~' => "\x{230B}", + '\\'=> "\x{2308}", + '|' => "\x{2309}", +); + +my $groups = kbchars(\%rows); +$groups->{flag}->{g5} = [greek => + "a different greek letter not corresponding with latin transcription" +]; +while (my ($key, $chr) = each %rows) { + $groups->{def}->{''}->{$key} =~ s/g6/g5/ if $chr =~ /\A\p{Greek}/; +} + ++{ + %{$groups}, + version => '1.1', + title => 'US Symbolics', + category => 'specialised/greek/xorg', + intro => join("\n", + "A US English extension providing scientific", + 'Unicode characters while pressing AltGr,', + 'developed by Daniele Baisero', + 'for Linux.', + ), + description => [ + "US Symbolics keyboard layout table", + "with the AltGr modifier key: provides Greek letters", + "and symbols for scientific English literature.", + ], +} diff --git a/keyboard/altgr/ukext.eng.inc.pl b/keyboard/altgr/ukext.eng.inc.pl new file mode 100644 index 0000000..6a8e914 --- /dev/null +++ b/keyboard/altgr/ukext.eng.inc.pl @@ -0,0 +1,120 @@ +use utf8; +use strict; +use warnings; +use Shiar_Sheet::KeyboardChars 'kbchars'; + +my %rows = ( + '~' => '¦', + '!' => '¡', + '1' => '¹', + '@' => '½', # uk " + '2' => "\N{COMBINING DIAERESIS}", + '#' => '⅓', # uk £ + '3' => '³', + '$' => '¼', + '4' => '€', + '%' => '⅜', + '5' => '½', + '^' => '⅝', + '6' => "\N{COMBINING CIRCUMFLEX ACCENT}", + '&' => '⅞', + '7' => '{', + '*' => '™', + '8' => '[', + '(' => '±', + '9' => ']', + ')' => '°', + '0' => '}', + '_' => '¿', + '-' => '\\', + '+' => "\N{COMBINING OGONEK}", + '=' => "\N{COMBINING CEDILLA}", + 'Q' => 'Ω', + 'q' => '@', + 'W' => 'Ẃ', + 'w' => 'ẃ', + 'E' => 'É', + 'e' => 'é', + 'R' => '®', + 'r' => '¶', + 'T' => 'Ŧ', + 't' => 'ŧ', + 'Y' => 'Ý', + 'y' => 'ý', + 'U' => 'Ú', + 'u' => 'ú', + 'I' => 'Í', + 'i' => 'í', + 'O' => 'Ó', + 'o' => 'ó', + 'P' => 'Þ', + 'p' => 'þ', + '{' => "\N{COMBINING RING ABOVE}", + '}' => "\N{COMBINING MACRON}", + 'A' => 'Á', + 'a' => 'á', + 'S' => '§', + 's' => 'ß', + 'D' => 'Ð', + 'd' => 'ð', + 'F' => 'ª', + 'f' => 'đ', + 'G' => 'Ŋ', + 'g' => 'ŋ', + 'H' => 'Ħ', + 'h' => 'ħ', + 'J' => "\N{COMBINING HORN}", + 'j' => "\N{COMBINING HOOK ABOVE}", + 'K' => '&', + 'k' => 'ĸ', + 'L' => 'Ł', + 'l' => 'ł', + ':' => "\N{COMBINING DOUBLE ACUTE ACCENT}", + ';' => "\N{COMBINING ACUTE ACCENT}", + '"' => "\N{COMBINING CARON}", # uk @ + "'" => "\N{COMBINING ACUTE ACCENT}", # same as ;? + '|' => "\N{COMBINING TILDE}", + '\\'=> "\N{COMBINING BREVE}", + '~' => "\N{COMBINING GRAVE ACCENT}", + '`' => '¦', + 'Z' => '<', + 'z' => '«', + 'X' => '>', + 'x' => '»', + 'C' => 'Ç', + 'c' => 'ç', + 'V' => '‘', + 'v' => '“', + 'B' => '’', + 'b' => '”', + #'N'=> 'N', + #'n'=> 'n', + 'M' => 'º', + 'm' => 'µ', + '<' => '×', + ',' => '─', + '>' => '÷', + '.' => '·', + '?' => "\N{COMBINING DOT ABOVE}", + '/' => "\N{COMBINING DOT BELOW}", +); +$rows{'['} = $rows{'2'}; +$rows{']'} = $rows{'#'}; + ++{ + %{ kbchars(\%rows) }, + title => 'UK-extended', + category => 'latin/thirdparty', + version => '1.0', + intro => join("\n", + "A Chrome OS extension", + "expanding on Windows' UK Extended QWERTY keyboard.", + 'Similar to the US international variant.', + ), + description => [ + "Google UK-Extended keyboard layout table for Chrome OS", + "with the AltGr modifier key.", + ], + image => 'data/keyboard/thumb/chromebook-hp11.jpg', + imagealt => 'AltGr key on a HP Chromebook 11 G2', +} diff --git a/keyboard/altgr/windows.eng.inc.pl b/keyboard/altgr/windows.eng.inc.pl new file mode 100644 index 0000000..eb021b7 --- /dev/null +++ b/keyboard/altgr/windows.eng.inc.pl @@ -0,0 +1,98 @@ +use utf8; +use strict; +use warnings; +use Shiar_Sheet::KeyboardChars 'kbchars'; + +my @az = ('A'..'Z', 'a'..'z'); +my @letters = qw( + Á B ¢ Ð É F G H Í J Œ Ø µ Ñ Ó Ö Ä ® § Þ Ú V Å X Ü Æ + á b © ð é f g h í j œ ø µ ñ ó ö ä ® ß þ ú v å x ü æ +); +my %xkb = ( + '@' => "\N{COMBINING DOUBLE ACUTE ACCENT}", + '#' => "\N{COMBINING MACRON}", + '&' => "\N{COMBINING HORN}", + '*' => "\N{COMBINING OGONEK}", + '(' => "\N{COMBINING BREVE}", + ')' => "\N{COMBINING RING ABOVE}", + '_' => "\N{COMBINING DOT BELOW}", + '>' => "\N{COMBINING CARON}", + '.' => "\N{COMBINING DOT ABOVE}", + '?' => "\N{COMBINING HOOK ABOVE}", + # 1.7~39 (2009-06-12) + '%' => "\N{COMBINING CEDILLA}", + # 2.38~16 (2023-01-13) + 'R' => '™', + # 2.39~101 (2023-03-17) + 'f' => 'ë', + 'F' => 'Ë', + 'j' => 'ï', + 'J' => 'Ï', + # 2.39~96 (2023-03-21) + 'M' => '±', + # 2.40~122 (2023-06-11) + 'x' => '·', + 'X' => "\N{COMBINING SHORT SOLIDUS OVERLAY}", # dead_stroke (slash ø, bar ʉ, stroke ł) +); + +my %rows = ( + '~' => "\N{COMBINING TILDE}", + '`' => "\N{COMBINING GRAVE ACCENT}", + '!' => '¹', + '1' => '¡', + '2' => '²', + '3' => '³', + '$' => '£', + '4' => '¤', + '5' => '€', + '^' => "\N{COMBINING CIRCUMFLEX ACCENT}", + '6' => '¼', + '7' => '½', + '8' => '¾', + '9' => '‘', + '0' => '’', + '-' => '¥', + '+' => '÷', + '=' => '×', + '{' => '“', + '}' => '”', + '[' => '«', + ']' => '»', + ':' => '°', + ';' => '¶', + "'" => "\N{COMBINING ACUTE ACCENT}", + '"' => "\N{COMBINING DIAERESIS}", + '<' => 'Ç', + ',' => 'ç', + '/' => '¿', + '|' => '¦', + '\\'=> '¬', + (map { + ($az[$_] eq $letters[$_]) ? () : + ($az[$_] => $letters[$_]) + } 0 .. $#az), + %xkb, +); + +my $groups = kbchars(\%rows); +$groups->{def}{''}{$_} .= ' ext' for keys %xkb; +$groups->{flag}{ext} = ['xkb', 'unofficial extensions added in Linux (Gnome, KDE)']; + ++{ + %{$groups}, + title => 'Windows AltGr', + category => '1/latin/windows/xorg', + version => '1.4', + intro => join("\n", + 'Resulting selection of Unicode characters', + 'while pressing the AltGr modifier', + 'with the Windows US international layout.', + 'Macs have option options instead.', + ), + description => [ + "Windows US international keyboard layout table", + "with the AltGr modifier key.", + ], + image => 'data/keyboard/thumb/ku2971b-usint.jpg', + imagealt => 'AltGr on a KeyboardCompany KU2971B with USA International keycaps', +} diff --git a/less.eng.inc.pl b/keyboard/less.eng.inc.pl similarity index 96% rename from less.eng.inc.pl rename to keyboard/less.eng.inc.pl index fed0bd2..9000189 100644 --- a/less.eng.inc.pl +++ b/keyboard/less.eng.inc.pl @@ -2,6 +2,14 @@ use utf8; { # less v418 +title => 'Less', +version => '1.1', +description => [ + "Default bindings of the less pager.", + "Clearly shows how much it's more than more.", +], +keywords => [qw' less keys pager more options '], +rows => [1, 0], key => { "\e"=> "alt<>/meta", diff --git a/mplayer.eng.inc.pl b/keyboard/mplayer.eng.inc.pl similarity index 79% rename from mplayer.eng.inc.pl rename to keyboard/mplayer.eng.inc.pl index 1c2e170..9568ed8 100644 --- a/mplayer.eng.inc.pl +++ b/keyboard/mplayer.eng.inc.pl @@ -1,6 +1,19 @@ use utf8; { +title => 'MPlayer', +version => '1.3', +intro => join("\n", + 'Default interface controls for the original MPlayer v1.0 media player.', + 'Mostly inherited by mpv.', +), +description => [ + "Keyboard cheat sheet for the $mode media player,", + "overviewing the default controls.", +], +keywords => [qw'mpv mplayer mplayer2 media player video audio'], +rows => [1, 0], + key => { '[' => "slow down 10%", ']' => "speed up 10%", @@ -11,8 +24,8 @@ key => { 'p' => "pause", '.' => "step forward", 'q' => "stop and quit", - '+' => "audio delay +<>.1s", - '-' => "audio delay -<>.1s", + '+' => "audio delay +<>.1s", # +ctrl in mpv + '-' => "audio delay -<>.1s", # +ctrl in mpv '/' => "volume decrease", '*' => "volume increase", 'm' => "mute sound", @@ -39,8 +52,8 @@ key => { 's' => "screen<>shot\n-vf screenshot", 'S' => "record screen<>shot<>s\n-vf screenshot", 'I' => "filename", - '!' => "chapter back", - '@' => "chapter forward", + '!' => "chapter back", # also pgdn in mpv + '@' => "chapter forward", # also pgup in mpv '1' => "contrast less", '2' => "contrast more", '3' => "brighter", @@ -63,7 +76,7 @@ flag => { g7 => [playback => "Playback control."], g9 => [general => "Other MPlayer features."], - arg => ["key" => "Commands with a dot need an argument afterwards."], + arg => ["key" => "Commands with a dot read further input afterwards."], ext => ["optional" => "Some features depend on setup and/or parameters."], }, diff --git a/keyboard/mpv.eng.inc.pl b/keyboard/mpv.eng.inc.pl new file mode 100644 index 0000000..11d4aff --- /dev/null +++ b/keyboard/mpv.eng.inc.pl @@ -0,0 +1,80 @@ +use utf8; + +my $legacy = do 'keyboard/mplayer.eng.inc.pl' or die $@; + +{ +title => 'mpv', +version => '1.3', +intro => join("\n", + 'Default interface controls for version 0.35 of the mpv media player.', + 'Differences from the original MPlayer are indicated.', +), +keywords => $legacy->{keywords}, +rows => [1, 0], + +key => { %{ $legacy->{key} }, + ',' => "step backward<>s", + 'Q' => "save and quit", + '_' => "cycle video tr<>ack<>s", + '+' => "audio delay +<>.1s", # +ctrl in mpv + '-' => "audio delay -<>.1s", # +ctrl in mpv + 'o' => "osd state switch", + 'O' => "osd mode toggle", + 'd' => "deint<>erlace", + 'E' => "edition cycle", + 'i' => "stats info", + 'I' => "toggle stats info", + 'j' => "next sub<>title", + 'J' => "prev<>ious sub<>title", + 'A' => "aspect override", + 'u' => "subtitle style", + 'V' => "subtitle aspect", + 'l' => "A-B loop", + 'L' => "infinite looping", + 'S' => "record screen<>shot<>s\n-vf screenshot", # mpv? + '^s'=> "actual screen<>shot", + '5' => "gamma decrease", + '6' => "gamma increase", + 'F' => 'enlarge sub font', + 'G' => 'smaller sub font', + '`' => 'console', +}, + +mode => $legacy->{mode}, + +flag => { %{ $legacy->{flag} }, + new => ["mpv" => "Introduced in mpv, not supported in original MPlayer"], +}, + +def => { + '' => { %{ $legacy->{def}->{''} }, + '`' => 'g9 arg new', + 'b' => undef, + 'g' => undef, + 'y' => undef, + 'F' => 'g2 new', + 'G' => 'g2 new', + 'a' => undef, + 'c' => undef, + 'n' => undef, + 'i' => 'g1 new', + 'I' => 'g1 new', + ',' => 'g7 new', + '_' => 'g4 new', + 'Q' => 'g9 new', + 'O' => 'g1 new', + 'P' => '=o new', + 'J' => 'g2 new', + 'A' => 'g4 new', + 'u' => 'g2 new', + 'V' => 'g2 new', + 'l' => 'g7 new', + 'L' => 'g7 new', + 'E' => 'g4 new', + '^s'=> 'g9 ext new', + 'R' => '=t new', + 'Z' => '=x new', + 'W' => '=e new', + }, +}, +} diff --git a/mutt.eng.inc.pl b/keyboard/mutt.eng.inc.pl similarity index 87% rename from mutt.eng.inc.pl rename to keyboard/mutt.eng.inc.pl index 2c58283..4c94c09 100644 --- a/mutt.eng.inc.pl +++ b/keyboard/mutt.eng.inc.pl @@ -59,6 +59,14 @@ my %commondef = ( ); { +title => 'Mutt', +version => '1.3', +description => [ + "Cheat sheet for the Mutt v2.2 e-mail client,", + "showing the default binding for each key.", +], +keywords => [qw' mutt MUA email client '], + key => { %commonkey, @@ -69,6 +77,10 @@ key => { '#' => "split up thread", '&' => "thread tagged", '%' => "toggle reado<>nl<>y", + '-' => "collapse thread", + '_' => "collapse all", + "'" => "marked mes<>sag<>e", + '~' => "save mark", 'a' => "create alias", 'b' => "bounce", @@ -91,6 +103,7 @@ key => { 'g' => "reply to all\nGroup reply", 'G' => "fetch POP\nGather new mail", 'h' => "toggle headers", + 'i' => "fetch IMAP", '^i'=> "unread msg ", '+^i'=> "unread msg ", 'j' => "messag<>e ", @@ -101,7 +114,8 @@ key => { '+k'=> "send public key", 'l' => "limit pattern", 'L' => "reply to list", - '+l'=> "show current limit", + '+l'=> "mlist actions", + #'+l'=> "show current limit", 'm' => "compo<>s<>e mail", 'N' => "toggle new", '^n'=> "thread ", @@ -136,12 +150,14 @@ key => { 'W' => "clear flag", 'x' => "abort", 'y' => "list incoming mailboxes", + 'Y' => "edit label", (map { 'm'.$_ => $commonkey{$_} } keys %commonkey), 'm|' => "pipe attach<>m<>ent", 'ma' => "attach file", 'mA' => "attach messag<>e", + 'm^b'=> "url<>view", 'mb' => "edit bcc", 'mc' => "edit cc", 'mC' => "copy file", @@ -158,22 +174,30 @@ key => { 'mG' => "get attach<>m<>ent", 'mh' => "display message", 'mi' => "run ispell", + 'm+k'=> "attach PGP key", 'ml' => "print attach<>m<>ent", 'mm' => "edit attach<>m<>ent\nMime-appropriate open", 'mM' => "edit mix", 'm^m'=> "view attach<>m<>ent", 'mn' => "new attach<>m<>ent", + 'mo' => "autocrypt toggle", #TODO + 'm^o'=> "rename attach<>m<>ent", + 'mp' => "PGP menu", 'mP' => "post<>pone", 'mr' => "edit reply<>-to", 'mR' => "rename attach<>m<>ent", 'ms' => "edit subject", 'mS' => "s/mime options", 'mt' => "edit to", + 'mT' => "enter tags", #TODO 'm^t'=> "ctype attach<>m<>ent", - 'mw' => "copy to folder", 'mu' => "unlink toggle", + 'mv' => "preview alt fil<>t<>er", # m+v mV + 'mV' => "preview mailcap filter", + 'mw' => "copy to folder", 'mU' => "encode attach<>m<>ent", 'my' => "send", + # ^xe 'wD' => "deleted", 'wN' => "new", @@ -202,6 +226,7 @@ key => { '/~L' => "receiv<>d by", '/~l' => "mailing list", '/~m' => "num<>ber ran<>g<>e", + '/~M' => "mime type", '/~n' => "score range", '/~N' => "new", '/~O' => "old", @@ -225,6 +250,8 @@ key => { '/~=' => "dupli<>cate", '/~$' => "unrefer<>enced", '/~(' => "in thread", + '/~<' => "parent match", + '/~>' => "child match", # globally label escape as meta key "\e"=> "+", @@ -237,7 +264,7 @@ mode => { '' => 'index', 'm' => 'compose (m)', w => 'message flags (w)', - '/~' => 'search flags (/~)', + '/~' => 'search patterns (/~)', }, flag => { @@ -264,6 +291,10 @@ def => { '#' => 'g4', # break-thread '&' => 'g4', # link-threads '%' => 'g4', # toggle-write + '-' => 'g9', + '_' => 'g9', + '~' => 'g4 arg', # mark-message #TODO + "'" => 'g3 arg', ' ' => '=^m', 'a' => 'g6', # create-alias @@ -275,7 +306,7 @@ def => { '+c'=> 'g8', # change-folder-readonly '+C'=> undef, # decode-copy 'd' => 'g4', # delete-message - 'D' => 'g4 arg', # delete-pattern + 'D' => 'g4 arg mode/~', # delete-pattern '^d'=> 'g4', # delete-thread '+d'=> 'g4', # delete-subthread 'e' => 'g4 linkvi', # edit @@ -287,6 +318,7 @@ def => { 'g' => 'g7 modem', # group-reply 'G' => 'g6', # fetch-mail 'h' => 'g9', # display-toggle-weed + 'i' => 'g6', # imap-fetch-mail '^i'=> 'g3', # next-new-then-unread '+^i'=> undef, # previous-new-then-unread 'j' => 'g2', # next-undeleted @@ -295,9 +327,9 @@ def => { 'K' => 'g3', # previous-entry '^k'=> 'g1', # extract-keys '+k'=> 'g7 modem', # mail-key - 'l' => 'g9', # limit + 'l' => 'g9 arg mode/~', # limit 'L' => 'g7 modem', # list-reply - '+l'=> 'g1', # show-limit + '+l'=> 'g1', # list-actions/show-limit 'm' => 'g7 modem', # mail 'N' => 'g4', # toggle-new '^n'=> 'g3', # next-thread @@ -317,11 +349,11 @@ def => { '+r'=> 'g4', # read-subthread 's' => 'g4', # save-message '+s'=> 'g4', # decode-save - 'T' => 'g4 arg', # tag-pattern - '^t'=> 'g4', # untag-pattern + 'T' => 'g4 arg mode/~', # tag-pattern + '^t'=> 'g4 arg mode/~', # untag-pattern '+t'=> 'g4', # tag-thread 'u' => 'g4', # undelete-message - 'U' => 'g4 arg', # undelete-pattern + 'U' => 'g4 arg mode/~', # undelete-pattern '^u'=> 'g4', # undelete-thread '+u'=> 'g4', # undelete-subthread 'v' => 'g1', # view-attachments @@ -332,15 +364,17 @@ def => { 'W' => 'g4 arg modew', # clear-flag 'x' => 'g8', # exit 'y' => 'g8', # M ? + 'Y' => 'g4 arg', # edit-label }, # index 'm' => { %commondef, '|' => 'g4', - 'a' => 'g6', - 'A' => 'g6', + 'a' => 'g4', + 'A' => 'g4', 'b' => 'g4', + '^b'=> 'g1', 'c' => 'g4', 'C' => 'g6', 'd' => 'g4', @@ -356,20 +390,28 @@ def => { 'G' => 'g1', 'h' => 'g1', 'i' => 'g6', + '+k'=> 'g4', 'l' => 'g1', 'm' => 'g4', 'M' => 'g4', '^m'=> 'g1', 'n' => 'g6', + 'o' => 'g4 ext', + '^o'=> 'g4', + 'p' => 'g1', #TODO 'P' => 'g8 mode', 'r' => 'g4', 'R' => 'g4', 's' => 'g4', 'S' => 'g4 menumS', 't' => 'g4', + 'T' => 'g4', '^t'=> 'g4', 'w' => 'g6', 'u' => 'g6', + 'v' => 'g1', + '+v'=> 'g1', + 'V' => 'g1', 'U' => 'g4', 'y' => 'g7', }, # compose @@ -410,6 +452,7 @@ def => { L => 'g3 arg', l => 'g3', m => 'g3 arg', + M => 'g3 arg', n => 'g3 arg', N => 'g3', O => 'g3', @@ -433,6 +476,8 @@ def => { '=' => 'g3', '$' => 'g3', '(' => 'g3 arg', + '<' => 'g3 arg', + '>' => 'g3 arg', }, # search option }, } diff --git a/nethack.eng.inc.pl b/keyboard/nethack.eng.inc.pl similarity index 85% rename from nethack.eng.inc.pl rename to keyboard/nethack.eng.inc.pl index e54a639..19aa7a3 100644 --- a/nethack.eng.inc.pl +++ b/keyboard/nethack.eng.inc.pl @@ -1,6 +1,17 @@ use utf8; { +title => 'NetHack', +version => '1.2', +description => [ + "Keyboard overview sheet for the NetHack console roguelike game,", + "describing the default controls.", +], +intro => "Command bindings for version 3.6.1 of the vanilla NetHack game.", +keywords => [qw' nethack rogue game controls '], +rows => [3, 2, 1, 0], +moderows => '4321-421', + key => { 'b' => "step left down\nnumpad 1", 'j' => "step down\nnumpad 2", @@ -31,6 +42,7 @@ key => { 'g' => "run until interest", 'm' => "m<>ove blind\nno pickup", + 'M' => "go far", 'G' => "g any<>where\nfollow branches", '?' => "help menu", @@ -49,6 +61,7 @@ key => { '+a'=> "adjust inv<>ent<>ory", 'c' => "close door", 'C' => "call monster", + '^c'=> "panic quit", '+c'=> "chat", 'd' => "drop item", 'D' => "drop items", @@ -69,6 +82,7 @@ key => { '+n'=> "name item<>(s)", 'o' => "open door", 'O' => "options", + '^o'=> "overview levels", '+o'=> "offer sacrifice", 'p' => "pay bill", 'P' => "put on", @@ -116,6 +130,7 @@ key => { '$' => "count gold", '+' => "list spells", '\\'=> "discover<>ed obj<>ects", + '`' => "types ident<>if<>ied", '!' => "shell escape", '#' => "more comm<>ands", @@ -133,10 +148,16 @@ key => { 'Iu' => 'list unpaid', 'Ix' => 'list billed', 'I$' => 'count money', + 'IB' => 'list blessed', + 'IU' => 'list uncurs<>e<>d', + 'IC' => 'list cursed', + 'IX' => 'list un<>know<>n', }, mode => { '' => 'normal gameplay', + 'I' => 'inventory type', + 'D' => 'drop item type', }, flag => { @@ -183,6 +204,7 @@ def => { 'g' => 'g3 argm', 'm' => 'g3 argm', + 'M' => 'g3 argm', 'G' => 'g3 argm', '?' => 'g8 mode?', #help @@ -201,6 +223,7 @@ def => { '+a'=> 'g6', #adjust 'c' => 'g4 argm', #close 'C' => 'g4 arg', #call + '^c'=> 'g6', '+c'=> 'g4 arg', #chat 'd' => 'g4 argi', #drop 'D' => 'g4 arg modeD', #Drop @@ -221,7 +244,9 @@ def => { '+n'=> 'g7 arg', #name 'o' => 'g4 argm', #open 'O' => 'g8 modeO', #options + '^o'=> 'g6', '+o'=> 'g4 argi', #offer + '+O'=> "=^o", #overview 'p' => 'g4', #pay 'P' => 'g4 argi', #puton '^p'=> 'g6', #prevmsg @@ -259,20 +284,23 @@ def => { ',' => 'g4', #pickup '@' => 'g6', '^' => 'g6 argm', #trap_id - ')' => 'g7', - '[' => 'g7', - '=' => 'g7', - '"' => 'g7', - '(' => 'g7', - '*' => 'g7', - '$' => 'g6', #gold - '+' => 'g7', #spells + ')' => 'g7', #seeweapon + '[' => 'g7', #seearmor + '=' => 'g7', #seerings + '"' => 'g7', #seeamulet + '(' => 'g7', #seetools + '*' => 'g7', #seeall + '$' => 'g6', #seegold + '+' => 'g7', #seespells '\\'=> 'g7', #known + '`' => 'g7', #knownclass '!' => 'g6', #sh '#' => 'g8', }, 'D' => { + "\e" => 'g8 mode', # static reset button, even though it's not (officially) in the game + 'B' => 'g4', 'U' => 'g4', 'C' => 'g4', @@ -285,10 +313,16 @@ def => { }, 'I' => { + "\e" => 'g8 mode', + '*' => 'g6', 'u' => 'g6', 'x' => 'g6', '$' => 'g6', + 'B' => 'g6', + 'U' => 'g6', + 'C' => 'g6', + 'X' => 'g6', }, }, } diff --git a/readline.eng.inc.pl b/keyboard/readline.eng.inc.pl similarity index 78% rename from readline.eng.inc.pl rename to keyboard/readline.eng.inc.pl index 4b28885..5e5b0cd 100644 --- a/readline.eng.inc.pl +++ b/keyboard/readline.eng.inc.pl @@ -1,6 +1,16 @@ use utf8; { +title => 'readline', +version => 1.2, +description => [ + "Reference sheet of default key bindings for GNU readline,", + "used for line-editing in most Unix software, notably Emacs and Bash.", +], +keywords => [qw( readline gnu bash emacs editing curses )], +rows => [4, 3, 2], +moderows => '^x=213', + key => { '+<' => "history start", '+>' => "history end", @@ -94,8 +104,8 @@ flag => { g9 => [mode => "Additional key functionality (click to view)."], arg => ["key" => "Commands with a dot need a char argument afterwards."], - new => [">v2.0" => "Unavailable before readline version 2.1 (1997)."], - ext => ["bash" => "Default assignment in Bash shells, but not common readline."], + 'v21 new' => [">v2.0" => "Unavailable before readline version 2.1 (1997)."], + 'xbash ext' => ["bash" => "Default assignment in Bash shells, but not common readline."], }, def => { @@ -103,37 +113,37 @@ def => { "\e" => 'g8', '+<' => 'g4', - '+=' => '=+?', #TODO: new # emacs, not in v2.0 + '+=' => '=+?', #TODO: v21 # emacs, not in v2.0 '+>' => 'g4', '^?' => '=^h', '+?' => 'g1', - '^@' => 'g8 new', # not in v2.0 + '^@' => 'g8 v21', # not in v2.0 - '+#' => 'g6 new', # not in v2.0 + '+#' => 'g6 v21', # not in v2.0 '+&' => 'g6', - '+*' => 'g6 new', # not in v2.0 + '+*' => 'g6 v21', # not in v2.0 '+.' => 'g4', '+~' => '=+&', # emacs '^[' => 'g8', '^+['=> '=^i', '+\\'=> 'g7', - '^]' => 'g2 arg new', # not in v2.0 - '^+]'=> 'g2 arg new', # not in v2.0 + '^]' => 'g2 arg v21', # not in v2.0 + '^+]'=> 'g2 arg v21', # not in v2.0 '^_' => 'g4', '+_' => '=+.', - '+~' => 'g6 ext', # common emacs => '=+&' - '+!' => 'g6 ext', - '+@' => 'g6 ext', - '+$' => 'g6 ext', - '+^' => 'g4 ext', - '+/' => 'g1 ext', + '+~' => 'g6 xbash', # common emacs => '=+&' + '+!' => 'g6 xbash', + '+@' => 'g6 xbash', + '+$' => 'g6 xbash', + '+^' => 'g4 xbash', + '+/' => 'g1 xbash', '^a' => 'g2', '^b' => 'g2', '+b' => 'g2', - '^c' => 'g8 ext', + '^c' => 'g8 xbash', '+c' => 'g6', '^d' => 'g7', '+d' => 'g7 ring', @@ -156,7 +166,7 @@ def => { '^+m'=> '=^+j', '^n' => 'g4', '+n' => 'g4', - '^o' => 'g4 ext', + '^o' => 'g4 xbash', '^p' => 'g4', '+p' => 'g4', '^q' => '=^v', @@ -174,7 +184,7 @@ def => { '^y' => 'g4', '+y' => 'g4 ring', '^+y'=> "yank arg", - '^z' => 'g8 ext', + '^z' => 'g8 xbash', }, '^x' => { @@ -185,13 +195,13 @@ def => { '(' => 'g8', ')' => 'g8', 'e' => 'g8', - '^e' => 'g6 ext linkvi', + '^e' => 'g6 xbash linkvi', '^g' => '=^g', '^h' => '=^u', '^r' => 'g8', '^u' => '=^_', - '^x' => 'g2 new', # not in v2.0 - '^v' => 'g1 ext', + '^x' => 'g2 v21', # not in v2.0 + '^v' => 'g1 xbash', '^?' => '=^x^h', }, }, diff --git a/screen.eng.inc.pl b/keyboard/screen.eng.inc.pl similarity index 91% rename from screen.eng.inc.pl rename to keyboard/screen.eng.inc.pl index 7198b25..893adf3 100644 --- a/screen.eng.inc.pl +++ b/keyboard/screen.eng.inc.pl @@ -2,6 +2,13 @@ use utf8; { # screen version 4.00.03jw4 +title => 'Screen', +version => '1.1', +description => [ + "Interactive cheat sheet for the Screen terminal manager,", + "describing the function of each key.", +], +keywords => [qw' screen terminal window manager '], key => { 'a' => "literal a", @@ -16,7 +23,7 @@ key => { 'f' => "flow", # flow 'F' => "fit", '^g'=> "vbell", # vbell - 'h' => "hardcopy", # hardcopy + 'h' => "hard<>copy", # hardcopy 'H' => "log", # log 'i' => "prop<>erties", # info 'I' => "login on", #XXX @@ -53,7 +60,7 @@ key => { '|' => "split vert", # split -v '{' => "history", # history '}' => "history", # history - '=' => "remove buf", # removebuf + '=' => "remove buf<>fer", # removebuf '*' => "displays", # displays '.' => "dump<>termcap", # dumptermcap ',' => "license", # license @@ -73,7 +80,7 @@ flag => { g3 => ["select", "Switch between existing windows."], g4 => ["config", "Toggle configuration flags to change behaviour of the current window."], g5 => ["window", "Operate on or in current window with lasting results."], - g6 => ["buffer", "..."], + g6 => ["buffer", "Related to the paste buffer or an exchange file"], g7 => ["contents", "Insert or read character contents on a screen."], g9 => ["screen", "Manipulate global and inter-screen commands."], diff --git a/vi.eng.inc.pl b/keyboard/vi.eng.inc.pl similarity index 68% rename from vi.eng.inc.pl rename to keyboard/vi.eng.inc.pl index 48a3832..58ac2f3 100644 --- a/vi.eng.inc.pl +++ b/keyboard/vi.eng.inc.pl @@ -1,6 +1,20 @@ use utf8; +my @motions = qw( + g z [ ] + b B e E f F G ^h h H j ^j k l L M ^m n N ^n ^p t T w W + 0 ` ' # $ % ^ * ( ) { } ; / ? + - _ | , +); + { +title => 'vi/vim', +version => 1.5, +description => [ + "Interactive cheat sheet for vi text editors, notably Vim,", + "describing each key in various modes.", +], +keywords => [qw' vi vim nvi '], + key => { "\e"=> "normal mode", @@ -242,7 +256,6 @@ key => { '[^i'=> "to first occur<>renc<>e", '[m' => "start of funct<>ion", '[p' => "P reind<>ent<>ed", - '[P' => "[p", '[s' => "last missp<>ell<>ing", '[S' => "last bad word", '[z' => "start of open fold", @@ -339,7 +352,6 @@ key => { 'vD' => "delete lines", 'vg' => "extra cmds", 'v^g'=> "select mode", - 'v^h'=> "back<>space", # delete in select mode, left otherwise 'vi' => "extend inner a<>r<>ea", 'vI' => "insert to block", # block 'vJ' => "join lines", @@ -448,6 +460,98 @@ key => { 'i^x^u' => "cus<>tom comp<>l<>et<>e", 'i^x^v' => "ex cmd compl<>et<>e", 'i^x^y' => "window down", + + # plugins + 'gc' => "(un)<>com<>ment\ncommentary or tComment plugin", + 'vgc' => "(un)<>com<>ment\ncommentary or tComment plugin", + 'gl' => "align to left\nlion plugin, also good for easy-align", + 'vgl' => "align to left\nlion plugin, also good for easy-align", + 'gL' => "align to right\nlion plugin", + 'vgL' => "align to right\nlion plugin", + 'i^gs' => "sur<>round\nsurround plugin", + + # unimpaired + '[a' => "prev<>ious file\nunimpaired map for :prev", + ']a' => "next file\nunimpaired map for :n", + '[A' => "first file\nunimpaired map for :rew", + ']A' => "last file\nunimpaired map for :la", + '[b' => "prev<>ious buffer\nunimpaired map for :bp", + ']b' => "next buffer\nunimpaired map for :bn", + '[B' => "first buffer\nunimpaired map for :br", + ']B' => "last buffer\nunimpaired map for :bl", + '[e' => "exchange line above\nunimpaired plugin", + ']e' => "exchange line belo<>w\nunimpaired plugin", + '[f' => "preced<>ing file alph<>abet<>ic<>al<>ly\nunimpaired plugin", + ']f' => "next file alph<>abet<>ic<>al<>ly\nunimpaired plugin", + '[l' => "previous loc<>at<>ion\nunimpaired map for :lp", + ']l' => "next loc<>ation\nunimpaired map for :lne", + '[L' => "first loc<>ation\nunimpaired map for :lr", + ']L' => "last loc<>ation\nunimpaired map for :lla", + '[^l'=> "next file in loc<>at<>ions\nunimpaired map for :lpf", + ']^l'=> "file back in loc<>at<>ions\nunimpaired map for :lnf", + '[n' => "previous conflict<>/hunk\nunimpaired plugin", + ']n' => "next confl<>ict<>/hunk\nunimpaired plugin", + '[o' => "enable option\nunimpaired plugin", + ']o' => "disable option\nunimpaired plugin", + 'yo' => "toggle option\nunimpaired plugin", + '[q' => "previous quickfix\nunimpaired map for :cp", + ']q' => "next quickfix error\nunimpaired map for :cn", + '[Q' => "first quickfix\nunimpaired map for :cr", + ']Q' => "last quickfix error\nunimpaired map for :cla", + '[^q'=> "quickfix file b<>ack\nunimpaired map for :cpf", + ']^q'=> "next file in q<>uick<>f<>ix\nunimpaired map for :cnf", + '[t' => "previous tag\nunimpaired map for :tp", + ']t' => "next tag\nunimpaired map for :tn", + '[T' => "first tag\nunimpaired map for :tr", + ']T' => "last tag\nunimpaired map for :tl", + '[u' => "url encode\nunimpaired plugin", + ']u' => "url decode\nunimpaired plugin", + '[x' => "xml encode\nunimpaired plugin", + ']x' => "xml decode\nunimpaired plugin", + '[y' => "escape c str<>ing\nunimpaired plugin", + ']y' => "unescap<>e c str<>ing\nunimpaired plugin", + + (map { ("d$_" => "delete to $_") } qw( g z [ ] )), + 'dW' => 'delete word', + 'db' => 'delete word', + 'dB' => 'delete word', + 'de' => 'delete word e<>nd', + 'dE' => 'delete word e<>nd', + 'df' => 'delete to char<>acter', + 'dF' => 'delete to char<>acter', + 'dG' => 'delete to line<>/eof', + 'dH' => 'delete to top', + 'dj' => 'delete line', + 'dk' => 'delete line', + 'dL' => 'delete to bottom', + 'dM' => 'delete to middle', + 'dn' => 'delete to next res<>ult', + 'dN' => 'delete to prev res<>ult', + 'dt' => 'delete upto ch<>ar<>acter', + 'dT' => 'delete upto ch<>ar<>acter', + 'dw' => 'delete word', + 'd,' => 'delete to prev ch<>ar<>acter', + 'd;' => 'delete to next ch<>ar<>acter', + 'd/' => 'delete to res<>ult', + 'd?' => 'delete to res<>ult', + 'd`' => 'delete to mark', + "d'" => 'delete lines to m<>ark', + 'd*' => 'delete to find', + 'd#' => 'delete to find', + 'd%' => 'delete to line pct', + 'd^' => 'delete to soft bol', + 'd0' => 'delete to bol', + 'd|' => 'delete to col<>umn', + 'd{' => 'delete par<>agr<>aph', + 'd}' => 'delete rest of p<>ar<>agr<>aph', + 'd(' => 'delete senten<>ce', + 'd)' => 'delete rest of s<>en<>ten<>ce', + 'da' => 'delete area', + 'di' => 'delete inner', + 'dd' => 'delete line', + 'do' => 'diff obtain', + 'dp' => 'diff put', + 'ds' => 'delete surr<>oun<>d<>ing', }, mode => { @@ -466,6 +570,7 @@ mode => { i => "insert mode", 'i^g' => "extended insert commands (i ctrl-g)", 'i^x' => "insert completion commands (i ctrl-x)", + d => 'delete motions', }, flag => { @@ -480,8 +585,8 @@ flag => { arg => ["key", "Commands with a dot need a char argument afterwards."], motion => ["key", "Requires a motion afterwards, operates between cursor and destination."], - 'vim6 ext' => ["vim", "Not in original Vi (assessment incomplete)."], - 'vim7 ext new' => ["vim7", "New in vim version 7.x."], + 'v6 new' => ["vim", "Not in original Vi (assessment incomplete)."], + 'xcommentary xlion xsurround xunimpaired ext' => ["plugin", "Optional features provided by common plugins."], }, def => { @@ -489,12 +594,12 @@ def => { '~' => "g4 undo", '!' => "g4 argm undo modec", '@' => "g4 arg undo", - '#' => "g2 ext vim6", + '#' => "g2 v6", '$' => "g2", '%' => "g2", '^' => "g2", '&' => "g4 undo", - '*' => "g2 ext vim6", + '*' => "g2 v6", '(' => 'g2', ')' => 'g2', '_' => "g2", @@ -528,11 +633,11 @@ def => { '^a'=> "g4 undo", 'b' => "g2", 'B' => "g2", - '^b'=> "g2", + '^b'=> "g3", 'c' => "g6 argm undo modei", 'C' => "g6 undo modei", '^c'=> "g4", - 'd' => "g4 argm undo", + 'd' => "g4 argm undo moded", 'D' => "g4 undo", '^d'=> "g3", 'e' => "g2", @@ -540,7 +645,7 @@ def => { '^e'=> "g3", 'f' => "g2 arg", 'F' => "g2 arg", - '^f'=> "g2", + '^f'=> "g3", 'g' => "g9 arg modeg", 'G' => "g2", '^g'=> "g1", @@ -549,7 +654,7 @@ def => { '^h'=> "=h", 'i' => "g6 undo modei", 'I' => "g6 undo modei", - '^i'=> "g2 ext vim6", + '^i'=> "g2 v6", 'j' => "g2", 'J' => "g4 undo", '^j'=> "=j", @@ -566,7 +671,7 @@ def => { '^n'=> "=j", 'o' => "g6 undo modei", 'O' => "g6 undo modei", - '^o'=> "g2 ext vim6", + '^o'=> "g2 v6", 'p' => "g4 undo", 'P' => "g4 undo", '^p'=> "=k", @@ -575,7 +680,7 @@ def => { '^q'=> "g1", # or ^v 'r' => "g4 arg undo", 'R' => "g6 undo modei", - '^r'=> "g4 undo ext vim6", + '^r'=> "g4 undo v6", 's' => "g6 undo modei", 'S' => "g6 undo modei", '^s'=> "g1", @@ -587,7 +692,7 @@ def => { '^u'=> "g3", 'v' => "g8 modev", 'V' => "g8 modev", - '^v'=> "g8 modev ext vim6", + '^v'=> "g8 modev v6", 'w' => "g2", 'W' => "g2", '^w'=> "g9 arg mode^w", @@ -607,65 +712,68 @@ def => { "\e"=> "g7 mode", - '~' => "g4 argm ext vim6", - '@' => "g4 ext vim7 new", - '#' => "g2 ext vim6", + '~' => "g4 argm v6", + '@' => "g4 v7", + '#' => "g2 v6", '$' => "g2", - '^' => "g2 ext vim6", + '^' => "g2 v6", '&' => "g4", - '*' => "g2 ext vim6", - '_' => "g2 ext vim6", - '+' => "g4 ext vim7 new", - '`' => "g2 ext vim6 arg", + '*' => "g2 v6", + '_' => "g2 v6", + '+' => "g4 v7", + '`' => "g2 v6 arg", '8' => "g1", - '0' => "g2 ext vim6", - '-' => "g4 ext vim7 new", + '0' => "g2 v6", + '-' => "g4 v7", '^['=> "g7 mode", ']' => "g3", '^]'=> "g3", ';' => "g2", - "'" => "g2 ext vim6 arg", - '<' => "g4 ext vim7 new", - '?' => "g4 argm ext vim6", + "'" => "g2 v6 arg", + '<' => "g4 v7", + '?' => "g4 argm v6", ',' => "g2", 'a' => "g1", '^a'=> "g1", - 'd' => "g2 ext vim6", - 'D' => "g2 ext vim6", + 'c' => 'g4 argm xcommentary', + 'd' => "g2 v6", + 'D' => "g2 v6", 'e' => "g2", 'E' => "g2", - 'f' => "g4 ext vim6", - 'F' => "g4 ext vim7 new", + 'f' => "g4 v6", + 'F' => "g4 v7", 'g' => "g2", '^g'=> "g1 vim6", 'h' => "g8 modev", 'H' => "g8 modev", - '^h'=> "g8 modev ext vim6", + '^h'=> "g8 modev v6", 'i' => "g6 undo modei", 'I' => "g6 undo modei", - 'j' => "g2 ext vim6", + 'j' => "g2 v6", 'J' => "g4", - 'k' => "g2 ext vim6", - 'm' => "g2 ext vim6", - 'n' => "g8 vim7 new modev", - 'N' => "g8 vim7 new modev", + 'k' => "g2 v6", + 'l' => 'g3 argm arg xlion', + 'L' => 'g3 argm arg xlion', + 'm' => "g2 v6", + 'n' => "g8 v7 modev", + 'N' => "g8 v7 modev", 'o' => "g2", 'p' => "g4 undo", 'P' => "g4", 'q' => "g4 argm", - 'Q' => "g7 ext vim6", + 'Q' => "g7 v6", 'r' => "g4 arg", 'R' => "g6 undo modei", - 's' => "g1 ext vim6", - 't' => "g3 ext vim7 new", - 'T' => "g3 ext vim7 new", - 'u' => "g4 argm ext vim6", # XXX undo? - 'U' => "g4 undo argm ext vim6", + 's' => "g1 v6", + 't' => "g3 v7", + 'T' => "g3 v7", + 'u' => "g4 argm v6", # XXX undo? + 'U' => "g4 undo argm v6", 'v' => 'g8 modev', 'V' => "g4", - 'w' => "g4 argm ext vim7 new", - 'x' => "g4 ext vim7 new", + 'w' => "g4 argm v7", + 'x' => "g4 v7 ext", }, # mode g Z => { @@ -674,7 +782,7 @@ def => { "\e"=> "g7 mode", '^['=> "=\e", - 'Q' => "g4 ext vim6", + 'Q' => "g4 v6", 'Z' => "g4", }, # mode Z @@ -686,47 +794,47 @@ def => { '^' => "g3", '+' => "g3", '-' => "g3", - '=' => "g4 ext vim7 new", + '=' => "g4 v7", '.' => "g3", '^['=> "=\e", - 'a' => "g4 ext vim6 folding", - 'A' => "g4 ext vim6 folding", + 'a' => "g4 v6 folding", + 'A' => "g4 v6 folding", 'b' => "g3", - 'c' => "g4 ext vim6 folding", - 'C' => "g4 ext vim6 folding", - 'd' => "g4 ext vim6 folding", - 'D' => "g4 ext vim6 folding", + 'c' => "g4 v6 folding", + 'C' => "g4 v6 folding", + 'd' => "g4 v6 folding", + 'D' => "g4 v6 folding", 'e' => "g3", - 'E' => "g4 ext vim6 folding", - 'f' => "g4 argm ext vim6 folding", - 'F' => "g4 ext vim6 folding", - 'g' => "g4 ext vim7 new", - 'G' => "g4 ext vim7 new", + 'E' => "g4 v6 folding", + 'f' => "g4 argm v6 folding", + 'F' => "g4 v6 folding", + 'g' => "g4 v7", + 'G' => "g4 v7", 'h' => "g3", 'H' => "g3", - 'i' => "g4 ext vim6 folding", - 'j' => "g2 ext vim6 folding", - 'k' => "g2 ext vim6 folding", + 'i' => "g4 v6 folding", + 'j' => "g2 v6 folding", + 'k' => "g2 v6 folding", 'l' => "g3", 'L' => "g3", '^m'=> "g3", - 'm' => "g4 ext vim6 folding", - 'M' => "g4 ext vim6 folding", - 'n' => "g4 ext vim6 folding", - 'N' => "g4 ext vim6 folding", - 'o' => "g4 ext vim6 folding", - 'O' => "g4 ext vim6 folding", - 'r' => "g4 ext vim6 folding", - 'R' => "g4 ext vim6 folding", + 'm' => "g4 v6 folding", + 'M' => "g4 v6 folding", + 'n' => "g4 v6 folding", + 'N' => "g4 v6 folding", + 'o' => "g4 v6 folding", + 'O' => "g4 v6 folding", + 'r' => "g4 v6 folding", + 'R' => "g4 v6 folding", 's' => "g3", 't' => "g3", - 'u' => "g4 arg ext vim7 new", - 'v' => "g4 ext vim6 folding", - 'w' => "g4 ext vim7 new", - 'W' => "g4 ext vim7 new", - 'x' => "g4 ext vim6 folding", - 'X' => "g4 ext vim6 folding", + 'u' => "g4 arg v7", + 'v' => "g4 v6 folding", + 'w' => "g4 v7", + 'W' => "g4 v7", + 'x' => "g4 v6 folding", + 'X' => "g4 v6 folding", 'z' => "g3", }, # mode z @@ -735,12 +843,12 @@ def => { "\e"=> "g7 mode", - "`" => "g2 ext vim6", + "`" => "g2 v6", '#' => "g2", '(' => "g2", '*' => "=[/", '/' => "g2", - "'" => "=[` ^", # ext vim6 + "'" => "=0[`^ g2 v6", '{' => "g2", '[' => "g2", '^['=> "=\e", @@ -756,10 +864,32 @@ def => { '^i'=> 'g3', 'm' => "g2", 'p' => "g4", - 'P' => "g4", - 's' => "g3 ext vim7 new", - 'S' => "g3 ext vim7 new", - 'z' => "g2 ext vim6 folding", + 'P' => "=[p", + 's' => "g3 v7", + 'S' => "g3 v7", + 'z' => "g2 v6 folding", + + 'a' => "g3 xunimpaired", + 'A' => "g3 xunimpaired", + 'b' => "g3 xunimpaired", + 'B' => "g3 xunimpaired", + 'e' => "g4 xunimpaired", + 'l' => "g3 xunimpaired", + 'L' => "g3 xunimpaired", + '^l'=> "g3 xunimpaired", + '^l'=> "g3 xunimpaired", + 'f' => "g3 xunimpaired", # overrides native alias + 'n' => "g3 xunimpaired", + 'o' => "g9 arg xunimpaired", + 'q' => "g3 xunimpaired", + 'Q' => "g3 xunimpaired", + '^q'=> "g3 xunimpaired", + 't' => "g3 xunimpaired", + 'T' => "g3 xunimpaired", + 'u' => "g4 argm xunimpaired", + 'x' => "g4 argm xunimpaired", + 'y' => "g4 argm xunimpaired", + ' ' => "g4 xunimpaired", }, # mode [ ']' => { @@ -767,11 +897,11 @@ def => { "\e"=> "g7 mode", - "`" => "g2 ext vim6", + "`" => "g2 v6", '#' => "g2", ')' => "g2", '*' => "=]/", - "'" => "=]` ^", # ext vim6 + "'" => '=$]`^ g2 v6', '/' => "g2", '[' => "g2", '^['=> "=\e", @@ -789,9 +919,31 @@ def => { 'm' => "g2", 'p' => "g4", 'P' => "=[p", - 's' => "g3 ext vim7 new", - 'S' => "g3 ext vim7 new", - 'z' => "g2 ext vim6 folding", + 's' => "g3 v7", + 'S' => "g3 v7", + 'z' => "g2 v6 folding", + + 'a' => "g3 xunimpaired", + 'A' => "g3 xunimpaired", + 'b' => "g3 xunimpaired", + 'B' => "g3 xunimpaired", + 'e' => "g4 xunimpaired", + 'l' => "g3 xunimpaired", + 'L' => "g3 xunimpaired", + '^l'=> "g3 xunimpaired", + '^l'=> "g3 xunimpaired", + 'f' => "g3 xunimpaired", # overrides native alias + 'n' => "g3 xunimpaired", + 'o' => "g9 arg xunimpaired", + 'q' => "g3 xunimpaired", + 'Q' => "g3 xunimpaired", + '^q'=> "g3 xunimpaired", + 't' => "g3 xunimpaired", + 'T' => "g3 xunimpaired", + 'u' => "g4 argm xunimpaired", + 'x' => "g4 argm xunimpaired", + 'y' => "g4 argm xunimpaired", + ' ' => "g4 xunimpaired", }, # mode ] '^w' => { @@ -816,7 +968,7 @@ def => { '^c'=> "g7 mode", 'd' => "g3", 'f' => "g4", - 'F' => "g4 ext vim7 new", + 'F' => "g4 v7", 'g' => "g9 arg mode^wg", 'h' => "g3", 'H' => "g3", @@ -837,7 +989,7 @@ def => { 's' => "g3", 'S' => "=^ws", 't' => "g3", - 'T' => "g3 vim7 new", + 'T' => "g3 v7", 'v' => "g3", 'w' => "g3", 'W' => "g3", @@ -853,8 +1005,8 @@ def => { ']' => "g3", '}' => "g3", '^]'=> "g3", - 'f' => "g4 ext vim7 new", - 'F' => "g4 ext vim7 new", + 'f' => "g4 v7", + 'F' => "g4 v7", }, # mode ^w g v => { @@ -862,30 +1014,26 @@ def => { '!' => "g4", ':' => "g7 modec", - ',' => "=,", - "'" => "='", - '"' => '="', '<' => "g4", '=' => 'g4 undo', '>' => 'g4', - '~' => "g4 ext vim6", + '~' => "g4 v6", '^['=> "=\e", '^]'=> "g3", '^\\'=>'^\\', - 'a' => 'g9 modeva arg ext vim6', - 'A' => 'g6 modei ext vim6', - '^a'=> 'g4 undo vim8 ext new', - 'c' => 'g6 modei ext vim6', - 'C' => 'g6 modei ext vim6', + 'a' => 'g9 modeva arg v6', + 'A' => 'g6 modei v6', + '^a'=> 'g4 undo v8', + 'c' => 'g6 modei v6', + 'C' => 'g6 modei v6', '^c'=> "g7 mode", - 'd' => "g4 ext vim6", - 'D' => "g4 ext vim6", + 'd' => "g4 v6", + 'D' => "g4 v6", 'g' => "g9 arg modevg", '^g'=> "g8", - '^h'=> 'g4', - 'i' => "g9 modeva arg ext vim6", - 'I' => "g6 modei ext vim6", # block + 'i' => "g9 modeva arg v6", + 'I' => "g6 modei v6", # block 'J' => "g4", 'K' => 'g4', 'o' => "g2", @@ -893,28 +1041,24 @@ def => { '^o'=> "g8", 'p' => 'g4', 'P' => 'g4', - '^q'=> "=^q", 'r' => 'g4 arg', 'R' => "=vS", # "might change in future" - '^s'=> "=^s", 's' => "=vc", - 'S' => 'g6 modei ext vim6', - 'u' => "g4 ext vim6", - 'U' => "g4 ext vim6", + 'S' => 'g6 modei v6', + 'u' => "g4 v6", + 'U' => "g4 v6", 'v' => "g8", 'V' => "g8", - '^v'=> "g8 ext vim6", + '^v'=> "g8 v6", 'x' => "=vd", 'X' => "=vD", - '^x'=> 'g4 undo vim8 ext new', + '^x'=> 'g4 undo v8', 'y' => "g4", 'Y' => "g4", - map { $_ => "=$_" } qw( - b B ^b ^d e E ^e f F ^f G h H ^i j ^j k l L m M ^m - n N ^n ^p q ^s t T ^u w W ^w ^y z ^z - ` # $ % ^ * ( 0 ) [ { ] } ; / ? + - _ | - ) # a lot like normal mode + (map { $_ => "=$_" } @motions, qw( + ^b ^d ^e ^f ^i m q ^q ^s ^u ^w ^y z ^z " + )), # a lot like normal mode }, # mode v vg => { @@ -923,14 +1067,17 @@ def => { "\e"=> "g8 modev", '^['=> "=\e", - '?' => "g4 ext vim6", - '^a'=> 'g4 undo vim8 ext new', + '?' => "g4 v6", + '^a'=> 'g4 undo v8', '^g' => "g1 vim6", - 'J' => 'g4 ext vim6', - 'q' => "g4 ext vim6", + 'c' => 'g4 xcommentary', + 'J' => 'g4 v6', + 'l' => 'g3 arg xlion', + 'L' => 'g3 arg xlion', + 'q' => "g4 v6", 'v' => "=gv", - 'w' => 'g4 ext vim7 new', - '^x'=> 'g4 undo vim8 ext new', + 'w' => 'g4 v7', + '^x'=> 'g4 undo v8', }, # mode v g va => { @@ -939,23 +1086,23 @@ def => { '(' => "=vab", ')' => "=vab", '`' => "=va'", - "'" => 'g2 ext vim7 new', + "'" => 'g2 v7', '"' => "=va'", - '<' => 'g2 ext vim6', + '<' => 'g2 v6', '>' => "=va<", - '[' => 'g2 ext vim6', + '[' => 'g2 v6', '{' => "=vaB", '^['=> "=\e", ']' => "=va[", '}' => "=vaB", - 'b' => 'g2 ext vim6', - 'B' => 'g2 ext vim6', - 'p' => 'g2 ext vim6', - 's' => 'g2 ext vim6', - 't' => 'g2 ext vim7 new', - 'w' => 'g2 ext vim6', - 'W' => 'g2 ext vim6', + 'b' => 'g2 v6', + 'B' => 'g2 v6', + 'p' => 'g2 v6', + 's' => 'g2 v6', + 't' => 'g2 v7', + 'w' => 'g2 v6', + 'W' => 'g2 v6', }, # mode v a #c => { @@ -976,7 +1123,7 @@ def => { # '^n' => "", #todo # '^p' => "", #todo # '^r' => "=i^r", # and then some... - # ## ["g4 arg ext vim6"], + # ## ["g4 arg v6"], # '^q' => "=^q", # '^u' => "=i^u", # '^v' => "=i^v", @@ -988,38 +1135,38 @@ def => { "\e" => "g7 mode", '^@' => "g4", - '^^' => "g4 ext vim6", + '^^' => "g4 v6", '^['=> "=\e", - '^]' => "g4 ext vim6", - '^_' => "g4 ext vim6", + '^]' => "g4 v6", + '^_' => "g4 v6", '^\\'=>'^\\', - '^a' => "g4 ext vim6", - '^b' => "no ext vim6", + '^a' => "g4 v6", + '^b' => "no v6", '^c' => "g7 mode", '^d' => 'g4', - '^e' => "g4 ext vim6", + '^e' => "g4 v6", '^f' => 'g4', '^g' => "g9 modei^g arg", '^h' => "g4", '^i' => "g4", '^j' => "g4", - '^k' => 'g4 arg arg ext vim6 linkdigraphs', - '^l' => "g7 mode ext vim6", # insertmode only + '^k' => 'g4 arg arg v6 linkdigraphs', + '^l' => "g7 mode v6", # insertmode only '^m' => "g4", - '^n' => "g2 ext vim6", + '^n' => "g2 v6", '^o' => 'g4', - '^p' => "g2 ext vim6", + '^p' => "g2 v6", '^q' => "=^q", # or i^v - '^r' => 'g4 arg ext vim6', + '^r' => 'g4 arg v6', '^s' => "=^s", '^t' => "g4", '^u' => "g4", '^v' => 'g4 linkcharset', '^w' => "g4", - '^x' => 'g9 arg modei^x ext vim6', - '^y' => "g4 ext vim6", - '^z' => "g1 ext vim6", # insertmode only + '^x' => 'g9 arg modei^x v6', + '^y' => "g4 v6", + '^z' => "g1 v6", # insertmode only }, # modei 'i^g' => { @@ -1029,8 +1176,9 @@ def => { 'k' => 'g2', 'j' => 'g2', + 's' => 'g4 arg xsurround', 'u' => 'g4', - 'U' => 'g4 vim8 ext new', + 'U' => 'g4 v8', # other keys (even esc) are not recognized }, # mode i ^g @@ -1048,16 +1196,45 @@ def => { '^k' => 'g4', '^l' => 'g4', '^n' => 'g4', - '^o' => 'g4 ext vim7 new', + '^o' => 'g4 v7', '^p' => 'g4', '^s' => 'g4', 's' => "=i^x^s", '^t' => 'g4', - '^u' => 'g4 ext vim7 new', + '^u' => 'g4 v7', '^v' => 'g4', '^y' => "g3", }, # mode i ^x + d => { + lead => "d", + + "\e"=> "g7 mode", + '^['=> "=\e", + + (map { $_ => 'g4' } @motions), + (map { $_ => 'g4 arg' } qw( f F t T ` ' / ? )), # @motions with option + (map { $_ => "=v$_" } qw( a i )), # motions from virtual + (map { $_ => "=$_" } qw( g z [ ] \\ ^\\ ^q ^s ^z )), + + 'd' => 'g4', + 'o' => 'g5', + 'p' => 'g5', + 's' => 'g4 arg xsurround', + + 'l' => '=x', + 'h' => '=X', + '^h' => '=X', + '^j' => '=dj', + '^m' => '=dj', + '^n' => '=dj', + '+' => '=dj', + '^p' => '=dk', + '-' => '=dk', + '$' => '=D', + '_' => '=dd', + }, # mode d + # TODO: mode/ (command-line) # XXX ex mode if you want to go completely wild }, diff --git a/vimperator.eng.inc.pl b/keyboard/vimperator.eng.inc.pl similarity index 96% rename from vimperator.eng.inc.pl rename to keyboard/vimperator.eng.inc.pl index 4fc3771..5338ecd 100644 --- a/vimperator.eng.inc.pl +++ b/keyboard/vimperator.eng.inc.pl @@ -1,6 +1,14 @@ use utf8; # vimperator v3.16.0 { +title => 'Vimperator', +version => '1.3', +description => [ + "Interactive cheat sheet for the Vimperator (or Pentadactyl)", + "Firefox extension, describing the function of each key.", +], +keywords => [qw'vimperator firefox pentadactyl vim browser vimfx vimium cvim'], + key => { '~' => "open home<>dir", '@' => "play macro", diff --git a/latin.plp b/latin.plp index 56f9d03..578d858 100644 --- a/latin.plp +++ b/latin.plp @@ -2,7 +2,7 @@ Html({ title => 'latin alphabet cheat sheet', - version => '1.4', + version => '1.7', description => [ ], keywords => [qw' @@ -47,33 +47,36 @@ or 'mercan) letters A–Z. Also see related alphabets and font comparison.

    -
    - <: -use List::Util qw( pairs ); - -my @table = do 'writing-latn.inc.pl'; -if ($! or $@) { - Alert("Table data not found", $@ || $!); -} -else { +my $table = Data('writing-latn'); +{ + say '
    '; say '\n"; +} - my %VOWELCOLS = (map { ($_ => 1) } 0, 4, 8, 14, 20, 24); - say ''; - say ''; - - for my $row (pairs @table) { - my ($id, $info) = @{$row}; +my %VOWELCOLS = (map { ($_ => 1) } 0, 4, 8, 14, 20, 24); +say '
    # ASCII − 64'; - print '', $_ for 1 .. 26; - say '
    '; +say ''; +printtr('order'); +say ''; +printtr('default'); +say "
    "; + +sub printtr { + for my $id (@_) { + my $info = $table->{$id}; + + if (ref $info eq 'ARRAY') { + printtr(@{$info}); + next; + } printf '
    \n"; } -:>
    - +:>