How to programmatically determine character dimensions of my terminal window? - perl

I am writing a script which will display a stock chart as ASCII art in a terminal emulator window. I normally use OSX/Terminal.app but a Linux-based solution would be an acceptable alternative.
My script currently has command-line args for screen width and height (again, as measured in CHARACTERS, not pixels), with defaults determined by environment variables of my own invention. I would like these scripts to determine the current window's size (IN CHARACTERS), and use THAT as the default. A typical size for a big window on my 17-inch Macbook Pro might be 200 x 68.
This is a perl script, but if you know a solution in some other language, do tell!
TIA.
Ken

The usual way to do this is tput lines and tput cols; this queries, in order:
$LINES and $COLUMNS environment variables;
termios settings, which are set by terminal emulators when you resize their windows;
the terminfo description identified by $TERM.

From C, you'd use the TIOCGWINSZ option to an ioctl system call on /dev/tty.
This is exposed by the Term::ReadKey module - from man perlfaq8:
How do I get the screen size?
If you have Term::ReadKey module installed from CPAN, you can use it to fetch the width and height in characters and in pixels:
use Term::ReadKey;
($wchar, $hchar, $wpixels, $hpixels) = GetTerminalSize();

When run interactively, bash defines $LINES and $COLUMNS. Otherwise, use curses/ncurses to retrieve the terminal dimensions.

Related

Why is gnuplot failing with "Unknown device: pngalpha"?

I'm running gnuplot on RH7 through a perl script using the Chart::Gnuplot per module.
The perl version is 5.8.8.
The gnuplot version is a bit less obvious, but $VERSION in Gnuplot.pm is set equal to '0.23' (although I get the same results with ver 3.2)
Anyway, When I run this on RH6, it works fine. RH7 is a problem. The error is...
Unknown device: pngalpha
I tried different versions of gnuplot.pm with no success. But from googling around, I think the problem may reside in a utility (a different install) that gnuplot is using to generate png formatted output. I suspect there's something lacking in the RH7 env for that.
Does anyone know what gnuplot uses to translate it's native graphic format to png ?
I realize this isn't what you asked, but nevertheless I suggest it as a way forward.
Having now looked at the documentation and issues tracker for the perl module Graphics::Chart::Gnuplot, my take is that it is both too old and too narrowly focused on a limited set of gnuplot capabilities to be worth fixing or working around the limitations. You can see issues of inadequate png support that are still active on the tracker from 7 years ago.
I have done a fair amount of perl coding using gnuplot for graphics. Early on I looked into custom modules like the one you mention, but I soon found that it was much preferable to simply open a pipe to gnuplot and send the commands directly. I append below a simple example.
#!/usr/bin/perl -w
#
# open pipe to gnuplot and set terminal type
my $gnuplot = "/usr/local/bin/gnuplot";
open(GNUPLOT, "|$gnuplot") or die "can't find gnuplot";
binmode GNUPLOT,":encoding(UTF-8)";
my $outfile = $ARGV[0];
# send some simple commands one at a time
print GNUPLOT "set term pngcairo font 'arial,10' size 600,400\n";
print GNUPLOT "set output '$outfile'\n";
# send a block of commands
print GNUPLOT <<EOFgnu;
set title 'Example of gnuplot from perl'
sinc(x) = (x==0) ? 1.0 : sin(x) / x
plot sinc(x) with lines linecolor 'blue' linewidth 3
EOFgnu
# That's it. We're done.
close GNUPLOT;
And here is the file created by perl example.pl foo.png

gnuplot/pngcairo not rendering UTF-8 character correctly

I have two CentOS 7.4.1708 machines, running gnuplot 4.6 patchlevel 2,
currently behaving differently, and I can't work out why.
Install fonts:
sudo yum install dejavu-sans-mono-fonts
Then create the following GNUplot script:
cat << EOF > test.gnuplot
set terminal pngcairo enhanced font "DejaVuSansMono,10"
set encoding utf8
set title "同"
plot sin(x)
EOF
Finally, pipe it into the application:
cat test.gnuplot | gnuplot > test.png
On one machine I get this:
But on another I get this:
I can't work out the cause of the discrepancy. The desired character is U+540C so it's not like the second machine is interpreting the input bytes any differently; it's just not rendering the glyph.
What differences in system configuration should I be looking for?
More broadly, how can I "fix" the output in the second case? I don't even vastly care if some characters end up getting replaced by placeholders like this (after all, I must recognise that not all fonts implement all glyphs), but those placeholders being rendered at super-size is a problem.
This post is rather a collection of observations than a complete answer, but perhaps it might be useful as well (I tried your example on an almost fresh install of CentOS and it does reproduce the second plot in your post):
judging from the charset table printed by the command
fc-match -v DejaVuSansMono
it seems that 540C is indeed not supported. Perhaps the first machine has some additional fonts installed which are used as a fallback for this particular glyph? How would the output of fc-list differ?
Hard to say if it is complete, but the list of fonts supporting this glyph seems to be rather limited. Nonetheless, for example Google Droid is available via yum, so if I do
sudo yum install google-droid-sans-fonts google-droid-sans-mono-fonts
and rerun the Gnuplot script, the plot renders in an acceptable way.
as for the size of the "fallback" box, I first noticed that its size is directly proportional to the specified font size, i.e., it also doubles if one doubles the font size. From src/wxterminal/gp_cairo.c, it seems that Gnuplot uses by default an "oversampling" strategy to render the text, i.e., it renders everything in plot->oversampling_scale times larger resolution and then scales it back (via the transformation matrix defined in void gp_cairo_initialize_context(plot_struct*)).
For example, when rendering the text, it calls
pango_font_description_set_size(desc, \
(int) (plot->fontsize*PANGO_SCALE*plot->oversampling_scale));
However, for some reason, the "fallback" box is not scaled back and thus is plot->oversampling_scale times larger than the specified font size. The default value of plot->oversampling_scale is set to GP_CAIRO_SCALE which is defined to be 20 in src/wxterminal/gp_cairo.h.
I downloaded the source of Gnuplot 4.6.2 and replaced plot->oversampling = TRUE; with plot->oversampling = FALSE; in void gp_cairo_initialize_plot(plot_struct*) in src/wxterminal/gp_cairo.c. After recompilation, the "fallback" box is rendered with the same size as the rest of text. Unfortunately, I haven't found a way how to change this behavior directly from Gnuplot.

How to make multi-line mode line in Emacs 23?

I am using Emacs 23. This comes with OS and I can not change it for some reasons.
Few files I open have long pathnames which are eating all the space and I can not see enabled modes or current line/column. Is there any way to make the mode line multi-line OR some other solution?
Thanks
Perhaps SmartModeLine would help:
Fixed width (if you want): Lets you set a maxium width for the path
name and mode names, and truncates them intelligently
Here is a less complex solution, which may be a little easier for you to modify to suit your own -- it uses a simple function called shorten-directory:
http://amitp.blogspot.com/2011/08/emacs-custom-mode-line.html

Get current terminal color pair in Perl

I'm trying to learn about color text in a terminal window. (In case it matters I'm using Terminal.app on OS X.) I'd like to get the terminal's current foreground and background color pair. It looks like I should be able to get this info in a perl script using the Term::Cap library, but the solution eludes me.
In a perl script how would I query the terminal's current foreground and background color pair value?
The feature is outside the scope of terminfo and termcap, because it deals with terminal responses, while terminfo/termcap describe these capabilities:
how to tell the terminal to do some commonly-implemented feature (such as clearing the screen), or
what sequence of characters might some special key (such as Home) send from the keyboard.
While in principle, there is no limitation on what could be part of a terminal description, there was little commonality across terminals back in the 1980s for responses. A few terminals could report specific features, most of those were constant (e.g., version information). Most of the variable responses came after terminfo/termcap had more or less solidified in X/Open Curses. ncurses extends that, but again, most of the extensions are either features or special keys.
Terminal.app implements the most commonly-used features of xterm, but (like other imitators) omits most of the terminal responses. Among other things, xterm provides terminal responses which can tell an application what the window's colors are currently. There are a couple of command-line utilities (xtermset and xtermcontrol) which have been written to use this information (and again, they cover only a part of the repertoire). Using xtermcontrol demonstrates that Terminal.app is lacking in this area — see screenshot:
I don't think most terminals support reporting this -- and it doesn't look like termcap or terminfo have any entries for it. You're just expected to set the color pair as necessary, not to ask the terminal what it's set to right now. In the ECMA-48 standard (better known as "ANSI" after ANSI X3.64, where it used to live), the only command that makes reference to color is SGR "Set Graphic Rendition", which is purely write-only.
Dunno about perl or Terminal.app, but xterm etc will write foreground/background color control sequences to stdin if you output "\033]10;?\07" or "\033]11;?\07" respectively. Check out http://invisible-island.net/xterm/ctlseqs/ctlseqs.html, http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Controls in particular.

Need to color terminal's output produced with print command Term::ANSIColor

Here is what I have:
use Term::ANSIColor;
print "Blah!".color("green");
The output is
Test←[32m
What am I missing?
The terminal program you are using does not support the ECMA-48 color escape codes. So it does not give them any special treatment, and instead outputs the characters as-is.
What you are missing: a terminal that does. xterm, libvte, putty, are just a few to name that do.
Are you on Windows? I'm fairly certain that the Windows shell isn't compliant with the color codes used by the module.
Actually, it says so right there on the module's documentation.
Note that not all displays are ISO 6429-compliant, or even X3.64-compliant (or are even attempting to be so). This module will not work as expected on displays that do not honor these escape sequences, such as cmd.exe, 4nt.exe, and command.com under either Windows NT or Windows 2000. They may just be ignored, or they may display as an ESC character followed by some apparent garbage.
EDIT:
An addendum to my comment:
C:\>perl -MWin32::Console::ANSI -MTerm::ANSIColor -e "print color(\"green\"), 'test', color(\"reset\");"
Works just fine on Windows XP, Perl 5.12.1, so there's your workaround.