6d618ef70e5abfc5e18656ba8064ead0c8974386

Author
Andrew Janke <andrew@apjanke.net>
Committer
Andrew Janke <andrew@apjanke.net>
Date

Message

emoji plugin: generate char map from Unicode UTR51 data files

Refactor the functions and group listings to have fewer functions,
but have them take group names as parameters.
Pull group definitions in to a single associative array.

Diff

This diff is truncated to protect this page.

  1diff --git a/plugins/emoji/README.md b/plugins/emoji/README.md
  2new file mode 100644
  3index 0000000000000000000000000000000000000000..889e567e6ce8e3689fa57a517fd74ab8bc8732e6
  4--- /dev/null
  5+++ b/plugins/emoji/README.md
  6@@ -0,0 +1,135 @@
  7+# emoji plugin
  8+
  9+Support for conveniently working with Unicode emoji in Zsh.
 10+
 11+## Features
 12+
 13diff --git a/plugins/emoji/emoji-char-definitions.zsh b/plugins/emoji/emoji-char-definitions.zsh
 14new file mode 100644
 15index 0000000000000000000000000000000000000000..7d110603ceb4d7b579acaf8f12f4cea3e2b05833
 16--- /dev/null
 17+++ b/plugins/emoji/emoji-char-definitions.zsh
 18@@ -0,0 +1,1294 @@
 19+
 20+# emoji-char-definitions.zsh - Emoji character definitions for oh-my-zsh emoji plugin
 21+#
 22+# This file is auto-generated by update_emoji.pl. Do not edit it manually.
 23+#
 24+# This contains the definition for:
 25+#   $emoji         - which maps character names to Unicode characters
 26+#   $emoji_flags   - maps country names to Unicode flag characters using region indicators 
 27+
 28+typeset -gAH emoji
 29+typeset -gAH emoji_flags
 30+
 31+emoji[copyright_sign]=$'\U00A9'
 32+emoji[registered_sign]=$'\U00AE'
 33+emoji[double_exclamation_mark]=$'\U203C'
 34+emoji[exclamation_question_mark]=$'\U2049'
 35+emoji[trade_mark_sign]=$'\U2122'
 36+emoji[information_source]=$'\U2139'
 37+emoji[left_right_arrow]=$'\U2194'
 38+emoji[up_down_arrow]=$'\U2195'
 39+emoji[north_west_arrow]=$'\U2196'
 40+emoji[north_east_arrow]=$'\U2197'
 41+emoji[south_east_arrow]=$'\U2198'
 42+emoji[south_west_arrow]=$'\U2199'
 43+emoji[leftwards_arrow_with_hook]=$'\U21A9'
 44+emoji[rightwards_arrow_with_hook]=$'\U21AA'
 45+emoji[watch]=$'\U231A'
 46+emoji[hourglass]=$'\U231B'
 47+emoji[keyboard]=$'\U2328'
 48+emoji[eject_symbol]=$'\U23CF'
 49+emoji[black_right_pointing_double_triangle]=$'\U23E9'
 50+emoji[black_left_pointing_double_triangle]=$'\U23EA'
 51+emoji[black_up_pointing_double_triangle]=$'\U23EB'
 52+emoji[black_down_pointing_double_triangle]=$'\U23EC'
 53+emoji[black_right_pointing_double_triangle_with_vertical_bar]=$'\U23ED'
 54+emoji[black_left_pointing_double_triangle_with_vertical_bar]=$'\U23EE'
 55+emoji[black_right_pointing_triangle_with_double_vertical_bar]=$'\U23EF'
 56+emoji[alarm_clock]=$'\U23F0'
 57+emoji[stopwatch]=$'\U23F1'
 58+emoji[timer_clock]=$'\U23F2'
 59+emoji[hourglass_with_flowing_sand]=$'\U23F3'
 60+emoji[double_vertical_bar]=$'\U23F8'
 61+emoji[black_square_for_stop]=$'\U23F9'
 62+emoji[black_circle_for_record]=$'\U23FA'
 63+emoji[circled_latin_capital_letter_m]=$'\U24C2'
 64+emoji[black_small_square]=$'\U25AA'
 65+emoji[white_small_square]=$'\U25AB'
 66+emoji[black_right_pointing_triangle]=$'\U25B6'
 67+emoji[black_left_pointing_triangle]=$'\U25C0'
 68+emoji[white_medium_square]=$'\U25FB'
 69+emoji[black_medium_square]=$'\U25FC'
 70+emoji[white_medium_small_square]=$'\U25FD'
 71+emoji[black_medium_small_square]=$'\U25FE'
 72+emoji[black_sun_with_rays]=$'\U2600'
 73+emoji[cloud]=$'\U2601'
 74+emoji[umbrella]=$'\U2602'
 75+emoji[snowman]=$'\U2603'
 76+emoji[comet]=$'\U2604'
 77+emoji[black_telephone]=$'\U260E'
 78+emoji[ballot_box_with_check]=$'\U2611'
 79+emoji[umbrella_with_rain_drops]=$'\U2614'
 80+emoji[hot_beverage]=$'\U2615'
 81+emoji[shamrock]=$'\U2618'
 82+emoji[white_up_pointing_index]=$'\U261D'
 83+emoji[skull_and_crossbones]=$'\U2620'
 84+emoji[radioactive_sign]=$'\U2622'
 85+emoji[biohazard_sign]=$'\U2623'
 86+emoji[orthodox_cross]=$'\U2626'
 87+emoji[star_and_crescent]=$'\U262A'
 88+emoji[peace_symbol]=$'\U262E'
 89+emoji[yin_yang]=$'\U262F'
 90+emoji[wheel_of_dharma]=$'\U2638'
 91+emoji[white_frowning_face]=$'\U2639'
 92+emoji[white_smiling_face]=$'\U263A'
 93+emoji[aries]=$'\U2648'
 94+emoji[taurus]=$'\U2649'
 95+emoji[gemini]=$'\U264A'
 96+emoji[cancer]=$'\U264B'
 97+emoji[leo]=$'\U264C'
 98+emoji[virgo]=$'\U264D'
 99+emoji[libra]=$'\U264E'
100+emoji[scorpius]=$'\U264F'
101+emoji[sagittarius]=$'\U2650'
102+emoji[capricorn]=$'\U2651'
103+emoji[aquarius]=$'\U2652'
104+emoji[pisces]=$'\U2653'
105+emoji[black_spade_suit]=$'\U2660'
106+emoji[black_club_suit]=$'\U2663'
107+emoji[black_heart_suit]=$'\U2665'
108+emoji[black_diamond_suit]=$'\U2666'
109+emoji[hot_springs]=$'\U2668'
110+emoji[black_universal_recycling_symbol]=$'\U267B'
111+emoji[wheelchair_symbol]=$'\U267F'
112+emoji[hammer_and_pick]=$'\U2692'
113+emoji[anchor]=$'\U2693'
114+emoji[crossed_swords]=$'\U2694'
115+emoji[scales]=$'\U2696'
116+emoji[alembic]=$'\U2697'
117+emoji[gear]=$'\U2699'
118diff --git a/plugins/emoji/emoji-data.txt b/plugins/emoji/emoji-data.txt
119new file mode 100644
120index 0000000000000000000000000000000000000000..7b4c015f7afb8ccd82f9b027da43df8c7a8e1ba7
121--- /dev/null
122+++ b/plugins/emoji/emoji-data.txt
123@@ -0,0 +1,1308 @@
124+# DRAFT emoji-data.txt
125+# For details about the format and other information, see /../../../reports/tr51/index.html#Data_Files.
126+#
127+# Format: Code ; Default_Emoji_Style ; Emoji_Level ; Emoji_Modifier_Status ; Emoji_Sources # Comment
128+#
129+#   Field 1 — Default_Emoji_Style:
130+#             text:      default text presentation
131+#             emoji:     default emoji presentation
132+#   Field 2 — Emoji_Level:
133+#             L1:        level 1 emoji
134+#             L2:        level 2 emoji
135+#             NA:        not applicable
136+#   Field 3 — Emoji_Modifier_Status:
137+#             modifier:  an emoji modifier
138+#             primary:   a primary emoji modifier base
139+#             secondary: a secondary emoji modifier base
140+#             none:      not applicable
141+#   Field 4 — Emoji_Sources:
142+#             one or more values from {z, a, j, w, x}
143+#             see the key in http://www.unicode.org/draft/reports/tr51/tr51.html#Major_Sources
144+#             NA:        not applicable
145+#   Comment — currently contains the version where the character was first encoded,
146+#             followed by:
147+#             - a character name in uppercase (for a single character),
148+#             - a keycap name,
149+#             - an associated flag, where is associated with value unicode region code
150+#
151+00A9 ;	text ;	L1 ;	none ;	j	# V1.1 (©) COPYRIGHT SIGN
152+00AE ;	text ;	L1 ;	none ;	j	# V1.1 (®) REGISTERED SIGN
153+203C ;	text ;	L1 ;	none ;	a j	# V1.1 (‼) DOUBLE EXCLAMATION MARK
154+2049 ;	text ;	L1 ;	none ;	a j	# V3.0 (⁉) EXCLAMATION QUESTION MARK
155+2122 ;	text ;	L1 ;	none ;	j	# V1.1 (™) TRADE MARK SIGN
156+2139 ;	text ;	L1 ;	none ;	j	# V3.0 (ℹ) INFORMATION SOURCE
157+2194 ;	text ;	L1 ;	none ;	z j	# V1.1 (↔) LEFT RIGHT ARROW
158+2195 ;	text ;	L1 ;	none ;	z j	# V1.1 (↕) UP DOWN ARROW
159+2196 ;	text ;	L1 ;	none ;	j	# V1.1 (↖) NORTH WEST ARROW
160+2197 ;	text ;	L1 ;	none ;	j	# V1.1 (↗) NORTH EAST ARROW
161+2198 ;	text ;	L1 ;	none ;	j	# V1.1 (↘) SOUTH EAST ARROW
162+2199 ;	text ;	L1 ;	none ;	j	# V1.1 (↙) SOUTH WEST ARROW
163+21A9 ;	text ;	L1 ;	none ;	j	# V1.1 (↩) LEFTWARDS ARROW WITH HOOK
164+21AA ;	text ;	L1 ;	none ;	j	# V1.1 (↪) RIGHTWARDS ARROW WITH HOOK
165+231A ;	emoji ;	L1 ;	none ;	j	# V1.1 (⌚) WATCH
166+231B ;	emoji ;	L1 ;	none ;	j	# V1.1 (⌛) HOURGLASS
167+2328 ;	text ;	L2 ;	none ;	x	# V1.1 (⌨) KEYBOARD
168+23CF ;	text ;	L2 ;	none ;	x	# V4.0 (⏏) EJECT SYMBOL
169+23E9 ;	emoji ;	L1 ;	none ;	j w	# V6.0 (⏩) BLACK RIGHT-POINTING DOUBLE TRIANGLE
170+23EA ;	emoji ;	L1 ;	none ;	j w	# V6.0 (⏪) BLACK LEFT-POINTING DOUBLE TRIANGLE
171+23EB ;	emoji ;	L1 ;	none ;	j	# V6.0 (⏫) BLACK UP-POINTING DOUBLE TRIANGLE
172+23EC ;	emoji ;	L1 ;	none ;	j	# V6.0 (⏬) BLACK DOWN-POINTING DOUBLE TRIANGLE
173+23ED ;	text ;	L2 ;	none ;	w	# V6.0 (⏭) BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR
174+23EE ;	text ;	L2 ;	none ;	w	# V6.0 (⏮) BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR
175+23EF ;	text ;	L2 ;	none ;	x	# V6.0 (⏯) BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR
176+23F0 ;	emoji ;	L1 ;	none ;	j	# V6.0 (⏰) ALARM CLOCK
177+23F1 ;	text ;	L2 ;	none ;	x	# V6.0 (⏱) STOPWATCH
178+23F2 ;	text ;	L2 ;	none ;	x	# V6.0 (⏲) TIMER CLOCK
179+23F3 ;	emoji ;	L1 ;	none ;	j w	# V6.0 (⏳) HOURGLASS WITH FLOWING SAND
180+23F8 ;	text ;	L2 ;	none ;	w	# V7.0 (⏸) DOUBLE VERTICAL BAR
181+23F9 ;	text ;	L2 ;	none ;	w	# V7.0 (⏹) BLACK SQUARE FOR STOP
182+23FA ;	text ;	L2 ;	none ;	w	# V7.0 (⏺) BLACK CIRCLE FOR RECORD
183+24C2 ;	text ;	L1 ;	none ;	j	# V1.1 (Ⓜ) CIRCLED LATIN CAPITAL LETTER M
184+25AA ;	text ;	L1 ;	none ;	j w	# V1.1 (▪) BLACK SMALL SQUARE
185+25AB ;	text ;	L1 ;	none ;	j	# V1.1 (▫) WHITE SMALL SQUARE
186+25B6 ;	text ;	L1 ;	none ;	a j w	# V1.1 (▶) BLACK RIGHT-POINTING TRIANGLE
187+25C0 ;	text ;	L1 ;	none ;	a j w	# V1.1 (◀) BLACK LEFT-POINTING TRIANGLE
188+25FB ;	text ;	L1 ;	none ;	j	# V3.2 (◻) WHITE MEDIUM SQUARE
189+25FC ;	text ;	L1 ;	none ;	j w	# V3.2 (◼) BLACK MEDIUM SQUARE
190+25FD ;	emoji ;	L1 ;	none ;	j	# V3.2 (◽) WHITE MEDIUM SMALL SQUARE
191+25FE ;	emoji ;	L1 ;	none ;	j w	# V3.2 (◾) BLACK MEDIUM SMALL SQUARE
192+2600 ;	text ;	L1 ;	none ;	a j	# V1.1 (☀) BLACK SUN WITH RAYS
193+2601 ;	text ;	L1 ;	none ;	a j w	# V1.1 (☁) CLOUD
194+2602 ;	text ;	L2 ;	none ;	a	# V1.1 (☂) UMBRELLA
195+2603 ;	text ;	L2 ;	none ;	a	# V1.1 (☃) SNOWMAN
196+2604 ;	text ;	L2 ;	none ;	x	# V1.1 (☄) COMET
197+260E ;	text ;	L1 ;	none ;	z a j	# V1.1 (☎) BLACK TELEPHONE
198+2611 ;	text ;	L1 ;	none ;	j w	# V1.1 (☑) BALLOT BOX WITH CHECK
199+2614 ;	emoji ;	L1 ;	none ;	a j	# V4.0 (☔) UMBRELLA WITH RAIN DROPS
200+2615 ;	emoji ;	L1 ;	none ;	j	# V4.0 (☕) HOT BEVERAGE
201+2618 ;	text ;	L2 ;	none ;	x	# V4.1 (☘) SHAMROCK
202+261D ;	text ;	L1 ;	secondary ;	j w	# V1.1 (☝) WHITE UP POINTING INDEX
203+2620 ;	text ;	L2 ;	none ;	x	# V1.1 (☠) SKULL AND CROSSBONES
204+2622 ;	text ;	L2 ;	none ;	x	# V1.1 (☢) RADIOACTIVE SIGN
205+2623 ;	text ;	L2 ;	none ;	x	# V1.1 (☣) BIOHAZARD SIGN
206+2626 ;	text ;	L2 ;	none ;	x	# V1.1 (☦) ORTHODOX CROSS
207+262A ;	text ;	L2 ;	none ;	w	# V1.1 (☪) STAR AND CRESCENT
208+262E ;	text ;	L2 ;	none ;	x	# V1.1 (☮) PEACE SYMBOL
209+262F ;	text ;	L2 ;	none ;	w	# V1.1 (☯) YIN YANG
210+2638 ;	text ;	L2 ;	none ;	w	# V1.1 (☸) WHEEL OF DHARMA
211+2639 ;	text ;	L2 ;	secondary ;	w	# V1.1 (☹) WHITE FROWNING FACE
212+263A ;	text ;	L1 ;	secondary ;	j w	# V1.1 (☺) WHITE SMILING FACE
213+2648 ;	emoji ;	L1 ;	none ;	j w	# V1.1 (♈) ARIES
214+2649 ;	emoji ;	L1 ;	none ;	j w	# V1.1 (♉) TAURUS
215+264A ;	emoji ;	L1 ;	none ;	j w	# V1.1 (♊) GEMINI
216+264B ;	emoji ;	L1 ;	none ;	j w	# V1.1 (♋) CANCER
217+264C ;	emoji ;	L1 ;	none ;	j w	# V1.1 (♌) LEO
218+264D ;	emoji ;	L1 ;	none ;	j w	# V1.1 (♍) VIRGO
219+264E ;	emoji ;	L1 ;	none ;	j w	# V1.1 (♎) LIBRA
220+264F ;	emoji ;	L1 ;	none ;	j w	# V1.1 (♏) SCORPIUS
221+2650 ;	emoji ;	L1 ;	none ;	j w	# V1.1 (♐) SAGITTARIUS
222+2651 ;	emoji ;	L1 ;	none ;	j w	# V1.1 (♑) CAPRICORN
223diff --git a/plugins/emoji/emoji.plugin.zsh b/plugins/emoji/emoji.plugin.zsh
224index be761871e98a3b7336a63be2155d5529e33ad086..dbaf2bb9e2dd949f81ad55657bc70d946580802d 100644
225--- a/plugins/emoji/emoji.plugin.zsh
226+++ b/plugins/emoji/emoji.plugin.zsh
227@@ -1,876 +1,149 @@
228-# Make emoji available within the ZSH terminal
229+# emoji plugin
230+#
231+# Makes emoji support available within ZSH
232+#
233+# This plugin provides support for working with emoji characters in zsh using human-readable
234+# identifiers. It provides global variables which map emoji names to the actual
235+# characters, and some anmed groupings of emoji. It also provides associated functions 
236+# for displaying them.
237+#
238+# Global variables:
239+#   $emoji          - Maps emoji names to characters
240+#   $emoji2         - Auxiliary and combining characters
241+#   $emoji_flags    - Maps country names to flag characters (using region-indicators)
242+#   $emoji_skintone - Skin tone modifiers (from Unicode 8.0)
243+#   $emoji_groups   - Named groups of emoji. Keys are group names; values are whitespace-separated 
244+#                       lists of character names
245+#
246+# Functions:
247+#   random_emoji   - Prints a random emoji character
248+#   display_emoji  - Displays emoji, along with their names
249+#
250+# The emoji names and codes are sourced from Unicode Technical Report #51, which provides
251+# information on emoji support in Unicode. It can be found at http://www.unicode.org/reports/tr51/index.html.
252+#
253+# The group definitions are added by this OMZ plugin. They are not based on external definitions.
254+#
255+# The emoji in the main $emoji map are standalone character sequences which can all be output on their
256+# own, without worrying about combining effects. The values may actually be multi-code-point sequences, 
257+# instead of a single code point, and may include combining characters in those sequences. But they're
258+# arranged so their effects do not extend beyond that sequence.
259+#
260+# Usage and Examples:
261 #
262 # To output a specific emoji, use:
263 #    $> echo $emoji[<name>]
264-#    ex: $> echo $emoji[mouse_face]
265+# E.g.: 
266+#    $> echo $emoji[mouse_face]
267 #
268 # To output a random emoji, use:
269 #    $> random_emoji
270-#    $> random_emoji_fruit
271-#    $> random_emoji_animal
272-#    $> random_emoji_vehicle
273-#    $> random_emoji_face
274+# To output a random emoji from a particular group, use:
275+#    $> random_emoji <group>
276+# E.g.:
277+#    $> random_emoji fruits
278+#    $> random_emoji animals
279+#    $> random_emoji vehicles
280+#    $> random_emoji faces
281+# The valid group names can be found with `echo ${(k)emoji_groups}`
282+#
283+# To list all available emoji with their names, use:
284+#    $> display_emoji
285+#    $> display_emoji fruits
286+#    $> display_emoji animals
287+#    $> display_emoji vehicles
288+#    $> display_emoji faces
289 #
290-# To list all available emoji with names, use:
291-#    $> display_all_emoji
292-#    $> display_emoji_fruits
293-#    $> display_emoji_animals
294-#    $> display_emoji_vehicles
295-#    $> display_emoji_faces
296+# To use emoji in a prompt:
297+#    PROMPT="$emoji[penguin]  > ""
298+#    PROMPT='$(random_emoji fruits)  > '
299+#    surfer=$emoji[surfer]
300+#    PROMPT="$surfer  > "
301 #
302-# To use an emoji in a prompt:
303-#    PROMPT='$(echo $emoji[penguin])  > '
304-#    PROMPT='$(random_emoji_fruit)  > '
305-#    eval surfer=$(echo $emoji[surfer])
306-#    PROMPT='$surfer  > '
307 #
308-# emoji codes sourced from http://apps.timwhitlock.info/emoji/tables/unicode
309+# TODO: Move doco to a README
310+# TODO: Factor out parsing from generation in update_emoji.pl
311+# TODO: Incorporate CLDR data for ordering and groupings
312+# TODO: Short :bracket: style names (from gemoji)
313+# TODO: Country codes for flags
314+# TODO: ZWJ combining function?
315+
316+_omz_emoji_plugin_dir="${0:h}"
317+
318+() {
319+
320+local LC_ALL=en_US.UTF-8
321 
322-typeset -A emoji
323-emoji[grinning_face_with_smiling_eyes]='\xF0\x9F\x98\x81'
324-emoji[face_with_tears_of_joy]='\xF0\x9F\x98\x82'
325-emoji[smiling_face_with_open_mouth]='\xF0\x9F\x98\x83'
326-emoji[smiling_face_with_open_mouth_and_smiling_eyes]='\xF0\x9F\x98\x84'
327diff --git a/plugins/emoji/update_emoji.pl b/plugins/emoji/update_emoji.pl
328new file mode 100644
329index 0000000000000000000000000000000000000000..d90c6e31622e362038880a64d26c41dc6f860580
330--- /dev/null
331+++ b/plugins/emoji/update_emoji.pl
332@@ -0,0 +1,113 @@
333+#!/usr/bin/perl -w
334+#
335+# update_emoji.pl
336+#
337+# This script generates the emoji.plugin.zsh emoji definitions from the Unicode
338+# character data for the emoji characters.
339+#
340+# The data file can be found at http://unicode.org/Public/emoji/latest/emoji-data.txt
341+# as referenced in Unicode TR51 (http://www.unicode.org/reports/tr51/index.html).
342+#
343+# This is known to work with the data file from version 1.0. It may not work with later
344+# versions if the format changes. In particular, this reads line comments to get the
345+# emoji character name and unicode version.
346+#
347+# Country names have punctuation and other non-letter characters removed from their name,
348+# to avoid possible complications with having to escape the strings when using them as 
349+# array subscripts. The definition file seems to use some combining characters like accents
350+# that get stripped during this process.
351+
352+use strict;
353+use warnings;
354+use 5.010;
355+use autodie;
356+
357+use Path::Class;
358+use File::Copy;
359+
360+# Parse definitions out of the data file and convert
361+sub process_emoji_data_file {
362+	my ( $infile, $outfilename ) = @_;
363+	my $file = file($infile);
364+	my $outfile = file($outfilename);
365+	my $outfilebase = $outfile->basename();
366+	my $tempfilename = "$outfilename.tmp";
367+	my $tempfile = file($tempfilename);
368+	my $outfh = $tempfile->openw();
369+	$outfh->print("
370+# $outfilebase - Emoji character definitions for oh-my-zsh emoji plugin
371+#
372+# This file is auto-generated by update_emoji.pl. Do not edit it manually.
373+#
374+# This contains the definition for:
375+#   \$emoji         - which maps character names to Unicode characters
376+#   \$emoji_flags   - maps country names to Unicode flag characters using region indicators 
377+
378+# Main emoji
379+typeset -gAH emoji
380+# National flags
381+typeset -gAH emoji_flags
382+# Combining modifiers
383+typeset -gAH emoji_mod
384+
385+");
386+
387+	my $fh = $file->openr();
388+	my $line_num = 0;
389+	while ( my $line = $fh->getline() ) {
390+		$line_num++;
391+		$_ = $line;
392+		# Skip all-comment lines (from the header) and blank lines
393+		# (But don't strip comments on normal lines; we need to parse those for
394+		# the emoji names.)
395+		next if /^\s*#/ or /^\s*$/;
396+
397+		if (/^(\S.*?\S)\s*;\s*(\w+)\s*;\s*(\w+)\s*;\s*(\w+)\s*;\s*(\w.*?)\s*#\s*V(\S+)\s\(.*?\)\s*(\w.*\S)\s*$/) {
398+			my ($code, $style, $level, $modifier_status, $sources, $version, $keycap_name) 
399+				= ($1, $2, $3, $4, $5, $6, $7);
400+			#print "code=$code style=$style level=$level modifier_status=$modifier_status sources=$sources version=$version name=$keycap_name\n";
401+			my @code_points = split /\s+/, $code;
402+			my @sources = split /\s+/, $sources;
403+
404+			my $flag_country = "";
405+			if ( $keycap_name =~ /^flag for (\S.*?)\s*$/) {
406+				$flag_country = $1;
407+			}
408+
409+			my $zsh_code = join '', map { "\\U$_" } @code_points;
410+			# Convert keycap names to valid associative array names that do not require any
411+			# quoting. Works fine for most stuff, but is clumsy for flags.
412+			my $omz_name = lc($keycap_name);
413+			$omz_name =~ s/[^A-Za-z0-9]/_/g;
414+			my $zsh_flag_country = $flag_country;
415+			$zsh_flag_country =~ s/[^\p{Letter}]/_/g;
416+			if ($flag_country) {
417+				$outfh->print("emoji_flags[$zsh_flag_country]=\$'$zsh_code'\n");
418+			} else {
419+				$outfh->print("emoji[$omz_name]=\$'$zsh_code'\n");				
420+			}
421+			# Modifiers are included in both the main set and their separate map,
422+			# because they have a standalone representation as a color swatch.
423+			if ( $modifier_status == "modifier" ) {
424+				$outfh->print("emoji_mod[$omz_name]=\$'$zsh_code'\n");
425+			}
426+		} else {
427+			die "Failed parsing line $line_num: '$_'";
428+		}
429+	}
430+	$fh->close();
431+	$outfh->print("\n");