How To Obtain Character Cursor Spacing within Terminal Emulators

Background

A character's cursor spacing is the number of columns a terminal emulator advances the cursor after displaying the character's glyph(s). This cursor spacing may vary with the combination of character, terminal emulator and font set. For a given combination, the spacing does not seem to vary with font size, weight, emphasis or underlining. That is, if the terminal emulator has sized its grid cells for a 12 point font, increasing the font size (and all grid cells) to accomodate an 18 or 40 point font does not seem to change the number of columns the cursor advances after displaying a character's glyph(s).

Technique

In order to measure a character's cursor spacing, the bash shell script below puts the cursor in the home position, outputs a character, and then asks the terminal emulator for the new cursor position using terminfo's User string #7 (this string is often \033[6n). The terminal emulator then injects the cursor position into the stdin input stream from which it is read and used to determine the character's cursor spacing.

And so the script does for each character from 0 through 0x10ffff, writing each character's cursor spacing to a file named $TERM-character-cursor-spacing. The spacing will be a number from zero through four, or "exception" if the cursor moved unexpectedly. Often about 90 percent of characters will have a spacing of one column, with most of the rest being two.

#!/bin/bash
output_file=${TERM}-character-cursor-spacing
echo -n "" > ${output_file}
home=`infocmp -1 -l|grep "\shome="|sed "s/.*home=\(.*\),.*/\\1/"|sed "s/^\\\\[Ee]/\\\\033/"`
request=`infocmp -1 -l|grep "\su7="|sed "s/.*u7=\(.*\),.*/\\1/"|sed "s/^\\\\[Ee]/\\\\033/"`
trap "stty echo" EXIT; stty -echo
for i in {0..1114111}; do
  printf -v hex "%06x" $i
  echo -e "${home}_\U${hex}_${request}    "
  if [ $((${i} % 1000)) -eq 0 ]; then
    clear; echo -e "\n\n\nAbout "$(($((1114111-${i}))/11141))" percent remaining "
  fi
  read -d R response
  response=${response##*[}
  column=${response##*;}
  line=${response%%;*}
  width=$((${column}-3))
  if [ x${line} != x1 -o ${width} -lt 0 -o ${width} -gt 4 ]; then
    width=exception
  fi
  echo ${hex},${width} >> ${output_file}
done

Questions or Comments

Contact information

Public Domain

I dedicate this script to the public domain.