Print: change string size if it take more than one line

Hi guys, I was thinking about an idea today.

When I use the print method to show a text, I would like: if the size of the string is larger than the size of one line in the terminal, then perform an action, like cut the string or change it.

How can I get the current size of the terminal (I mean in term of characters, not pixels)

I too often want to know the size of the terminal, and there is an old Issues on GitHub.

One way is to create bindings for the readline library. The following project seems to do so.

In Ruby, the Readline binding is a standard library. However, in my opinion, the dependency on libreadline should be optional in Crystal.

My gist from that issue is prob the easiest way at the moment: OS Agnostic way to determine terminal height/width · GitHub. Doesn’t need to link any extra libs other than LibC, and works on Windows, Linux, and Mac.

This is also harder than it sounds due to some characters not having the same width as the amount of characters. I.e. string.size may not equal its width. There isn’t a built-in way to determine this at the moment, but this is something that can/will be solved via Add support for calculating display width of chars and strings · Issue #11038 · crystal-lang/crystal · GitHub.


Needed this myself, and I’m working on my own implementation.
It’s inspired by GitHub - crystal-term/screen: Cross platform terminal screen detection and other implementations.
None of them did exactly what I wanted.

What I needed:

  • The user of the library can control whether variables from the environment get preferred.
  • It works if just COLUMNS is defined, but LINES isn’t.

(so you can override COLUMNS if needed, as intended by

  • some additions: size from zsh, size from tmux, size from CSI 18t escape sequence (i.e. ask the terminal for the size), dependency on Readline is optional (GNU GPL 3 without linking exception)

Todo: POSIX has tcgetwinsize now:

Writing tests is the hard part …

  • because I need a mock terminal etc.
  • because I need Linux, Windows, MacOSX, Android, OpenBSD, Solaris and also PowerPC and MIPS for testing (TIOCGWINSZ has a different value).
1 Like

IIRC I needed to normalize to NFKC first and then use UnicodeCharWidth.truncate from for the calculation of the width to be correct.

UnicodeCharWidth.truncate( string.unicode_normalize(:NFKC), truncate_to)

unless the string is .ascii_only?.

It was great to know about uni_char_width in this thread.
Thanks to it, I can now display cowsay more nicely than before. I would like to add Crys someday.

< クリスタル言語はとてもはやい >
      \   ^__^
       \  (oo)\_______
          (__)\       )\/\
              ||----w |
              ||     ||
1 Like