Lacking Natural Simplicity

Random musings on books, code, and tabletop games.

install-font.sh - The simple approach

The simple approach to using install-font.sh to install fonts for groff probably works for almost everybody.

First, make sure that FontForge is installed; it is free and open source and available for installation in most distributions. Second, call the install-font.sh command with one argument, the font file, and answer the prompts.

This will install the fonts for groff's use in the appropriate directories under /usr/local/share/groff, creating the directories if necessary. If you need to install into /usr/share/groff you should specify the -s option to the script. For instance:

$ install-font.sh Lora-Regular.ttf

will install the Regular variant of the font, leading you through four prompts, for three of which you just need to take the default.

The only prompt where you need to do something other than accept the default is the prompt for the style. For Lora-Regular you'd specify +R. For italic, bold, and bold italic, the other traditional troff font styles, you'd specify +I, +B, and +BI. The prompt lists them all for you to choose from.

Here's a walk-through of installing the Lora font, assuming that install-font.sh is in your path. (If your /usr/local/share/groff directory isn't writable for your normal user, you should prefix the command with sudo.)

install-font.sh does produce a lot of output, but the colorizing helps pick out the important things. I've put the responses the user types in bold and red, and added “<RETURN>” where the user presses the RETURN key to accept defaults.

$ install-font.sh Lora-Regular.ttf
/usr/local/share/groff/site-font not found; creating.
/usr/local/share/groff/site-font/devps not found; creating.
/usr/local/share/groff/site-font/devpdf not found; creating.
Processing Lora-Regular.ttf...
Running fontforge...
Copyright (c) 2000-2020. See AUTHORS for Contributors.
 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
 with many parts BSD <http://fontforge.org/license.html>. Please read LICENSE.
 Version: 20201107
 Based on sources from 2020-11-16 19:11 UTC-D.
The following table(s) in the font have been ignored by FontForge
  Ignoring 'STAT' style attributes table
Done.
Family name (default = Lora): <RETURN>
  =>Lora-Regular (Lora-Regular.ttf) assigned to family 'Lora'.
Enter +STYLE (eg +R, +I, +B, +BI), or a unique groff name for Lora-Regular.
Leave blank to set name to 'Lora-Regular': +R
  =>Lora-Regular assigned groff fontname 'LoraR'.
Creating LoraR...
afmtodit: both uni00B5 and uni03BC map to mc at /Users/tkb/sw/versions/groff/git/bin/afmtodit line 6441.
Done.
Installing LoraR in /usr/local/share/groff/site-font/devps/... Done.
Make LoraR available to gropdf? (y/n; default = y) <RETURN>
Checking for gropdf executable and devpdf directory... gropdf found.
Installing LoraR in /usr/local/share/groff/site-font/devpdf/... Done.
Copy Lora-Regular.ttf to /usr/local/share/fonts/truetype/Lora/
  (y/n; default = n) <RETURN>
Install Lora-Regular.ttf manually to make it available system-wide.
$ install-font.sh Lora-Italic.ttf
Processing Lora-Italic.ttf...
Running fontforge...
Copyright (c) 2000-2020. See AUTHORS for Contributors.
 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
 with many parts BSD <http://fontforge.org/license.html>. Please read LICENSE.
 Version: 20201107
 Based on sources from 2020-11-16 19:11 UTC-D.
The following table(s) in the font have been ignored by FontForge
  Ignoring 'STAT' style attributes table
Done.
Family name (default = Lora): <RETURN>
  =>Lora-Italic (Lora-Italic.ttf) assigned to family 'Lora'.
Enter +STYLE (eg +R, +I, +B, +BI), or a unique groff name for Lora-Italic.
Leave blank to set name to 'Lora-Italic': +I
  =>Lora-Italic assigned groff fontname 'LoraI'.
Creating LoraI...
afmtodit: both uni00B5 and uni03BC map to mc at /Users/tkb/sw/versions/groff/git/bin/afmtodit line 6441.
Done.
Installing LoraI in /usr/local/share/groff/site-font/devps/... Done.
Make LoraI available to gropdf? (y/n; default = y) <RETURN>
Checking for gropdf executable and devpdf directory... gropdf found.
Installing LoraI in /usr/local/share/groff/site-font/devpdf/... Done.
Copy Lora-Italic.ttf to /usr/local/share/fonts/truetype/Lora/
  (y/n; default = n) <RETURN>
Install Lora-Italic.ttf manually to make it available system-wide.
$ install-font.sh Lora-Bold.ttf
Processing Lora-Bold.ttf...
Running fontforge...
Copyright (c) 2000-2020. See AUTHORS for Contributors.
 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
 with many parts BSD <http://fontforge.org/license.html>. Please read LICENSE.
 Version: 20201107
 Based on sources from 2020-11-16 19:11 UTC-D.
The following table(s) in the font have been ignored by FontForge
  Ignoring 'STAT' style attributes table
Glyph bounding box data exceeds font bounding box data for GID 4
  Subsequent errors will not be reported.
In GID 769 the advance width (1316) is greater than the stated maximum (1291)
  Subsequent errors will not be reported.
Done.
Family name (default = Lora): <RETURN>
  =>Lora-Bold (Lora-Bold.ttf) assigned to family 'Lora'.
Enter +STYLE (eg +R, +I, +B, +BI), or a unique groff name for Lora-Bold.
Leave blank to set name to 'Lora-Bold': +B
  =>Lora-Bold assigned groff fontname 'LoraB'.
Creating LoraB...
afmtodit: both uni00B5 and uni03BC map to mc at /Users/tkb/sw/versions/groff/git/bin/afmtodit line 6441.
Done.
Installing LoraB in /usr/local/share/groff/site-font/devps/... Done.
Make LoraB available to gropdf? (y/n; default = y) <RETURN>
Checking for gropdf executable and devpdf directory... gropdf found.
Installing LoraB in /usr/local/share/groff/site-font/devpdf/... Done.
Copy Lora-Bold.ttf to /usr/local/share/fonts/truetype/Lora/
  (y/n; default = n) <RETURN>
Install Lora-Bold.ttf manually to make it available system-wide.
$ install-font.sh Lora-BoldItalic.ttf
Processing Lora-BoldItalic.ttf...
Running fontforge...
Copyright (c) 2000-2020. See AUTHORS for Contributors.
 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
 with many parts BSD <http://fontforge.org/license.html>. Please read LICENSE.
 Version: 20201107
 Based on sources from 2020-11-16 19:11 UTC-D.
The following table(s) in the font have been ignored by FontForge
  Ignoring 'STAT' style attributes table
Glyph bounding box data exceeds font bounding box data for GID 4
  Subsequent errors will not be reported.
In GID 776 the advance width (1297) is greater than the stated maximum (1273)
  Subsequent errors will not be reported.
Done.
Family name (default = Lora): <RETURN>
  =>Lora-BoldItalic (Lora-BoldItalic.ttf) assigned to family 'Lora'.
Enter +STYLE (eg +R, +I, +B, +BI), or a unique groff name for Lora-BoldItalic.
Leave blank to set name to 'Lora-BoldItalic': +BI
  =>Lora-BoldItalic assigned groff fontname 'LoraBI'.
Creating LoraBI...
afmtodit: both uni00B5 and uni03BC map to mc at /Users/tkb/sw/versions/groff/git/bin/afmtodit line 6441.
Done.
Installing LoraBI in /usr/local/share/groff/site-font/devps/... Done.
Make LoraBI available to gropdf? (y/n; default = y) <RETURN>
Checking for gropdf executable and devpdf directory... gropdf found.
Installing LoraBI in /usr/local/share/groff/site-font/devpdf/... Done.
Copy Lora-BoldItalic.ttf to /usr/local/share/fonts/truetype/Lora/
  (y/n; default = n) <RETURN>
Install Lora-BoldItalic.ttf manually to make it available system-wide.

Last edited: 2021-07-20 12:40:30 EDT

groff and install-font.sh and installing fonts for use in groff

Note

This was originally a post to the groff mailing list. It has been slightly modified.

Currently install-font.sh is not part of groff. We've had some discussion on the list recently and in the past about integrating it into the groff distribution, and in response to recent discussion there is a new bug, #60930, requesting integrating it, including documentation, etc.

In the meantime, if you want to install fonts in OpenType or TrueType formats for use with devps and devpdf, install-font.sh greatly simplifies the process.

The install-font.sh script was written by Peter Schaffter, the author of the mom macros for groff, and is distributed on mom's download page and can be downloaded directly. It has a -H option that prints the documentation for it.

Fontforge is a free and open source font editor. It can run scripts to manipulate fonts and convert between font formats. (I only use fontforge to install fonts with install-font.sh, so I use a version that is command line only, but the normal build has a GUI for interactively building fonts.) The install-font.sh script uses Fontforge to convert OpenType and TrueType fonts to PostScript Type42 (.t42) and Type1 (.pfa), from which a groff font is generated by the groff utility afmtodit. Then the necessary files are moved to site-font/devps and registered in its download file for use by grops. Optionally the same can be done for site-font/devpdf for the use of gropdf. Then the fonts are available for use by groff -Tps and groff -Tpdf.

So, suppose you wanted to use Cormorant Garamond, a free font. You could download the Regular, Italic, Bold, and Bold Italic variants of the font, since groff tends to expect there to be R, I, B, and BI variants of the fonts it uses, though that is not mandatory. This would give you the files CormorantGaramond-Regular.ttf, CormorantGaramond-Italic.ttf, CormorantGaramond-Bold.ttf, and CormorantGaramond-BoldItalic.ttf. You would then use install-font.sh to convert them and install the resulting files into proper places under groff's site-font directory.

So, for instance, you'd cd to the directory that holds the .ttf files you downloaded. Then, to install the Regular variant of Cormorant Garamond you'd run the command

$(IFDIR)/install-font.sh -n -P "$DEST" -d -F CormorantGaramond -f +R CormorantGaramond-Regular.ttf

where IFDIR is an environment variable indicating the directory where install-font.sh is located and DEST is an environment variable indicating the directory that contains groff's site-font directory (not the actual site-font directory itself). The -n option means don't try to copy the TrueType file to where the system font files are located. The -P option takes as its argument the directory that contains the groff's site-font directory. Usually this is some place like /usr/share/groff or /usr/local/share/groff, but not all distributions create the site-font directory. If you don't specify -P install-font.sh will guess the location. (If the site-font directory doesn't exist, or you don't have write access to it I think you can use the environment variable GROFF_FONT_PATH to tell groff where to find it, but I've never used that and don't know the specifics. I often build groff from git and install it someplace my normal user has write access to, so I haven't had to worry about it.) The -d option says to make the font available to gropdf. The -F option takes an argument that specifies the font family name to use. This is the name that you would use with the .fam request or the -f option to groff to let it know you want to use this font family. The -f option takes an argument that specifies the font style to use, +R, +I, +B, or +BI. (The -f option can instead take a name, but I don't use that form and can't explain the distinctions.) The style (R, I, B, or BI) is appended to the font family name specified with -F to produce the name of the groff font, and consequently the name of the groff font file that is written to the devps and devpdf directories under site-font. So, in this example, the name of the groff font and the groff font file would be CormorantGaramondR. The last argument to the script is the name of the Truetype or OpenType file you are converting.

To complete the example, here are the commands to install the Italic, Bold, and Bold Italic variants of Cormorant Garamond:

$(IFDIR)/install-font.sh -n -P "$DEST" -d -F CormorantGaramond -f +I CormorantGaramond-Italic.ttf
$(IFDIR)/install-font.sh -n -P "$DEST" -d -F CormorantGaramond -f +B CormorantGaramond-Bold.ttf
$(IFDIR)/install-font.sh -n -P "$DEST" -d -F CormorantGaramond -f +BI CormorantGaramond-BoldItalic.

As I said in an earlier email to the list, I tend to put all four commands into a script so I can run them again if something goes wrong or when I need to install them on a new machine or in a new installation of groff. In the case of Cormorant Garamond I named the file install-cormorant-garamond.sh.

Later: Peter Schaffter pointed out that the simple use of install-font.sh is:

sudo install-font.sh fontfile

and then answer the questions the script asks. He also pointed out that it creates the site-font directory and necessary subdirectories if needed in, and here I quote: “the only two locations it's ever likely to be”. Looking at install-font.sh reveal those locations are /usr/local/share/groff and /usr/share/groff, defaulting to /usr/local/share/groff; to get it to use /usr/share/groff you specify the -s option.

For a walk-through of the simple use see the follow-up.

Last edited: 2021-07-15 17:46:40 EDT

Sorting words separated by commas

I often have lists of "words", separated by commas, possibly on multiple lines, like this example from a Makefile:

#    bookman, schoolbook, palatino, times,
#    helvetica, helvetica-narrow, optima, cormorant-garamond,
#    or ebgaramond.

I find these lists are always getting out of order, or they end up with some short lines and some long lines. I want to be able to reformat them automatically, like this:

#    bookman, cormorant-garamond, ebgaramond, helvetica, helvetica-narrow,
#    optima, palatino, schoolbook, or times.

So, I wrote three scripts to deal with them, sort-with-commas, strip-leading-hash to get rid of the leading hashes and spaces, and prefix to put the leading hashes and spaces back.

Now, above I said "words", because really it's anything separated by commas, so the "words" can contain space, etc.

Also, notice that the period after "ebgaramond" and the "or" before "ebgaramond"` in the original list disappear, and an "or " appears before the new end of the list, "times", and a period follows it. And you can have have the same situation with "and". So, the -p option to sort-with-commas adds a period after the last word, the -a option adds and "and " before the last word, and the -o option adds an "or " before the last word. If you are sorting only part of a list, you want to have a comma after the last "word", so there is the option -f for that. And to remove the the period from the original list, so it doesn't end up in the middle of the new list, or to remove "and " or "or ", there is the -r option.

The default is to return the sorted list as one long line, but you can easily reformat it to multiple lines by running it through the Unix command fmt.

Although in this case the list is prefixed with a "#" and some spaces because it comes from a comment in a Makefile, you have to remove those to sort the list. I wrote the script strip-leading-hash to do that, too, rather than having to remember the sed command to so that all the time.

So, to sort the original list I'd run the command

strip-leading-hash | sort-with-commas -r -p -o | fmt | prefix "#    "

which means “strip the leading hashes and spaces, remove the trailing period and the "and " or "or ", add a final period after the last word, add an "or " before the final word, reformat as a paragraph, and prefix the lines with the hash and spaces.”

When I use this I'm usually in emacs and using M-| to run it on the region (the currently selected text), often with the C-u to replace the region with results.

Here's the main script, sort-with-commas:

sort-with-commas (Source)

#! /usr/bin/env bash
###############################################################################
# Sort a list of words that are seperated by commas, optionally followed by
# a newline into a single line seperated by commas followed by spaces.
#
# For example: it translates (ignore the "# +" at the beginning of lines)
#    bookman, schoolbook,palatino,
#    times, helvetica, helvetica-narrow,
# to
#    bookman, helvetica, helvetica-narrow, palatino, schoolbook, times
###############################################################################

AND_OPT=off                     # Insert "and " before last word.
FINAL_OPT=off                   # Leave "," after last word.
OR_OPT=off                      # Insert "or " before last word.
PERIOD_OPT=off                  # Insert a final period after last word.
REMOVE_AND_OR_PERIOD_OPT=off


let errors=0
while getopts "?afhopr" opt
do
    case "$opt" in
        (\?|h) let errors++ ;;
        (a) AND_OPT=on ;;
        (f) FINAL_OPT=on ;;
        (o) OR_OPT=on ;;
        (p) PERIOD_OPT=on ;;
        (r) REMOVE_AND_OR_PERIOD_OPT=on ;;
    esac
done

shift $((OPTIND-1))

[[ $# > 0 ]] || [[ $errors > 0 ]] && {
    cat <<EOF
usage: sort-with-commas [OPTION]

This reads its standard input and sorts a line or multiple lines with
"words" separated by commas, then reassembles the line, words
separated by a comma and s space, optionally leaving a final comma
after the last word, or a period, and optionally putting "and " or "or
" before the last word.

Options

-? -h   This message.
-a      Insert "and " before last word.
-f      Leave final comma after last word.
-o      Insert "or " before last word.
-p      Insert a period after the last word.
-r      Remove "and " or "or " that occur at the beginning of a "word" in the
        original list.

Note that combining -a and -o, or -f and -p do what you say, but the results
are silly.
EOF
    exit 1
}

tr ',' '\n' | sed -E -e 's/^[ \t]+//' -e '/^$/d' |
    ([[ "$REMOVE_AND_OR_PERIOD_OPT" = "on" ]] &&
         sed -E -e 's/^(and|or)[ \t]+//' -e 's/\.[ \t]*$//' || cat) |
    sort -u |
    sed -E -e 's/$/,/' |
    (if [[ "$AND_OPT" = "on" ]]; then sed -e '$s/^/and /'; else cat; fi) |
    (if [[ "$FINAL_OPT" = "on" ]]; then cat; else sed -e '$s/,//'; fi) |
    (if [[ "$OR_OPT" = "on" ]]; then sed -e '$s/^/or /'; else cat; fi) |
    (if [[ "$PERIOD_OPT" = "on" ]]; then sed -e '$s/$/./'; else cat; fi) |
    tr '\n' ' ' | sed -E -e 's/[ ]$//'

Here's strip-leading-hash:

strip-leading-hash (Source)

#! /usr/bin/env bash

sed -E -e 's/^#[ \t]*//'

And here's prefix:

prefix (Source)

#! /usr/bin/env bash

sed "s/^/$1/"

troff Memorandum Macros documentation

TL;DR: Look here for documentation for the Documenter's Workbench mm Memorandum Macros for groff, based on the original paper MM - Memorandum Macros. If you read that far there is a bonus at the end.

When I learned troff it was actually on a VAX running VMS (used by MPL Corporation) using a port of troff called xroff 1, probably around 1986. (The VAX also had TeX and LaTeX, and I used them too. Both supported the DEC LNO3 laserprinter that MPL had.) While I don't know who produced xroff and can't find anything out about it on the Internet, it was a complete port of troff to VMS, including all the standard utilities and macro packages, including documentation for ms, me, and, significantly for this post mm.

The mm documentation was the paper MM - Memorandum Macros, by D. W. Smith, J. R. Mashey, E. C. Pariser, and N. W. Smith, AT&T Bell Laboratories, June 1980. I tried out all the macro packages, but found mm most to my liking. I think a large part of that was the mm documentation — it described the many features of that macro package pretty well, in a user guide sort of way, teaching you how to use the features as it went along, rather than being a pure reference manual. And I found mm most comparable in features to LaTeX of the troff macro packages. While configuring mm documents is somewhat quirky 2, I felt that the added features over those found in me and ms made it worthwhile. So I wrote a lot of documents using mm.

Years later when I first got access to groff on Unix machines (early 90s?) the documentation supplied with it for mm was the groff_mm(7) man page. It was very complete as a reference, but very poor for teaching you how to use mm. I continued to use mm off and on, but I think the lack of the user guide documentation of the mm paper made mm less popular among the users of groff than it could have been. So when modern features for PDF appeared for groff later on (the pdfmark macros), they were adapted to ms but not mm. (me was left out, as well.) I was sad to see mm's apparently low popularity, and the mm paper apparently is not available on the Internet in a form that copyright allows to be copied around, unlike the papers on ms and me, which come with groff. I suspect this is because mm was used heavily in AT&T's Documenter's Workbench, a commercial product that was distributed separately from UNIX System V, if I understand correctly.

However, eventually the sources to the Documenter's Workbench became available under the Eclipse Public License, and they are available in the n-t-roff github repository (along with Heirloom Docutils, a descendant of the original ditroff with native UTF-8 input and easy use of fonts). This includes the source to documentation that is derived from the mm paper! Unfortunately, I haven't been able to find a PDF of this on the Internet.

I think that having this available might help those who might want to try out mm, or are returning to it after a long break, so I've posted a version that I built a while ago here.


As a bonus for reading down this far, here is how I add PDF outline/table-of-contents entries for sections in groff mm, using the HZ user-defined heading exit macro (see groff_mm(7)):

.\" pdf outline fold level
.nr PDFOUTLINE.FOLDLEVEL 3
.\" start out in outline view
.pdfview /PageMode /UseOutlines
.de HZ
.pdfhref O \\$2 \\*[}0] \\$3
..

And here's how to do it in Heirloom Docutils troff:

.de HY
.nr HYtmp (\\$1-1)
\\X'PDFMark: Bookmark \\n[HYtmp] \\$3'
..

This version uses the HY user-defined heading exit macro and doesn't include the section numbers.

I'm not sure why the two use different macros. All I can say is that I wrote them at different times for slightly different purposes.

1

While I still maintain a descendant of the VAX I where I used xroff (emulated using Charon-VAX), sometime in the past the xroff software disappeared from it. I have no idea what happened to it. I blame user PDL!

2

The page offset, page width, and page length have to be set before the mm macros were loaded, so while on Unix it is easy to set those values on the command line, on VMS due to oddities in its command line it was easiest to use .so and load the macros directly

Last edited: 2021-07-17 19:09:27 EDT

In AFF 1E armour didn't make magic harder

Going back to Axel Wolfric, one of the example characters for Advanced Fighting Fantasy 1st Edition, he has spells despite being a sorcery-hating barbarian. This works in AFF 1E because every Hero and adversary is assumed to be wearing appropriate armour. If they remove their armour then all rolls on the Damage Table against them adds 2 to the roll. (See Dungeoner, p. 163 and 164. That's also where it talks about shields.) So any character can put points into the Magic Special Skill (at the cost of reducing their SKILL characteristic by an equal amount), so anybody can have magic.

I've always liked fantasy RPG systems where anybody can cast spells. (Thanks, DragonQuest!)

Unfortunately, this doesn't work as well in Advanced Fighting Fantasy 2nd Edition. AFF 2E allows anybody to put points into the MAGIC characteristic (similarly reducing the number of points that can be allocated to other characteristics), but casting spells in armour requires additional magic points, the better the armour the more magic points must be spent. (See Advanced Fighting Fantasy, 2nd Edition, p. 72, bottom of the 1st column and the top of the 2nd column.)

I wonder how much it would affect things in a game if I just ignored that rule? I'll have to try it sometime.

Later

Of course, that takes away some from the users of Sorcery in AFF 2E, who spend STAMINA instead of MAGIC POINTS to cast a completely different set of spells (many of which require material components) than Wizardry, and can cast in armour. Hmm. I'll have to think about it.

Last edited: 2021-08-09 23:55:19 EDT

Monks can't use potions (and scrolls) in OD&D and AD&D 1E!

Wow, I didn't realize that monks in OD&D and AD&D 1E can't use potions! (And scrolls, but that didn't surprise me.) OD&D states it explicitly on page 3 of Blackmoor. AD&D 1E doesn't state it explicitly, but they are not among the allowed magic items listed (appropriate weapons, rings, and miscellaneous magic that can be used by theives) and it says all other magic items are not allowed.

I have do not know if this is how we played AD&D 1E back in the day. I have a sneaking suspicion that we missed this restriction, but I just don't know.

It was Swords & Wizardry Complete that clued me into this, as I was comparing the monk class in it with AD&D 1E, and then I confirmed it in OD&D.

There are so many differences among all the editions of pre-3E D&D! Some are quite subtle, but really change how things play: no healing potions for monks!

defadvice lets you improve existing functions!

I used defadvice in emacs lisp and it made the world so much better!

Specifically, I use the function smart-unicode-hyphen from xmlunicode.el 1 when entering text that is to be typeset. The first time you hit hyphen it inserts a hyphen. The second time you hit hyphen it changes it to an em dash. The third time you hit hyphen it changes it to an en dash. If you hit it again it changes it back to a hyphen. Unfortunately, I’ve never found a monospaced font that has em dashes and en dashes that are distinguishable from hyphens visually. (Not to mention the minus character, which is also important to enter correctly for typesetting.) So it is hard to tell what character you have just inserted, especially since you have to remember which comes after which in the sequence.

1

Specifically, I have a very small minor mode that makes hyphens, double and single quotes, and periods smart, so they insert the proper Unicode characters in the right situations.

But I have a function tkb-describe-character that looks up the character under the cursor (or before, if you specified a prefix interactively or a value when called non-interactively) that looks up the character in the variable unicode-character-list (which is defined in unichars.el) and contains the character values and unicode names for the characters.

So, I wrote a defadvice function that runs (tkb-describe-character t) after smart-unicode-hyphen runs, so it looks at the character just before it and describes it, so I know what it is!

It works wonderfully!

That's the thing about defadvice: it lets you customize functions to better adapt them to how you need to work. Another way emacs lets you customize it to better suit your needs.

I got my copies of xmlunicode.el (copyright 2003 by Norman Walsh) and unichars.el (unattributed) off the Internet long ago. It looks like you can get xmlunicode.el from his xmlunicode github repository, and it looks like the replacement for unichars.el is xmlunicode-character-list.el.

Here's my code:

;; look at https://github.com/ndw/xmlunicode for xmlunicode.el and a way
;; to make something like unichars.el.  xmlunicode.el provides the
;; "smart-unicode-*" functions.
(load-library "xmlunicode")
(load-library "unichars")

(defun tkb-describe-character (before)
  "Describe the character after point (before if a prefix was specified)
if it is a unicode character."
  (interactive "P")
  (let* ((char (if before (char-before) (char-after)))
         (info (assoc (encode-char char 'ucs) unicode-character-list))
         (info (cons (format "#x%X" (car info)) info)))
    (message "%S" info)))
(tkb-keys ((kbd "C-c k d") #'tkb-describe-character))

(define-minor-mode tkb-smart-unicode-mode
  "Toggle smart unicode punctuation" nil " ♻⚔☣☥☸◉⅙✽☮" ; "✘▧▧⚅☑☢☹☺♠♥♦♣♨"
  '(("\"" . unicode-smart-double-quote)
    ("'"  . unicode-smart-single-quote)
    ("-"  . unicode-smart-hyphen)
    ("."  . unicode-smart-period)))

(defadvice unicode-smart-hyphen (after tkb-after-unicode-smart-hyphen last
                                       activate compile)
  (tkb-describe-character t))

Here's a gist, and the raw gist if you want to download it directly.