Two challenges with struck-through text

I’m working on a game with a fair bit of struck-through text. I know there are fancy ways of doing this (release it with a web-based interpreter like Quixe and do CSS stuff!) but that is way above my pay grade and obviously poses compatibility issues, so I’m taking the easy path which, per this thread, requires putting “[unicode 822]” in front of every character of the struck-through text (well, I guess it’s an easier path, not necessarily easy, and I know not all interpreters handle Unicode gracefully, though from quick testing Gargoyle and Lectrote seem fine).

Because I am not a complete dumbo, I realized that this programming language that’s very good at manipulating text could be used to manipulate text to solve this problem, and without too much difficulty I came up with this:

To strike through (A - a text):
	Repeat with X running from 1 to number of characters in A:
		Let Y be character number X in A;
		Say "[unicode 822][Y]";
	Say "[paragraph break]".

Lovely, works a treat, except for two small flies in the ointment (well, one small, one potentially medium-sized). An example illustrates the point. If I do something like this:

Instead of jumping:
Strike through “You float up in the air, clouds lapping at your feet. Below, the humble precincts of your home shrink, recede; then your town; then, the world.[paragraph break]The surly bonds of gravity catch at you, and you hiccup down, up, down up --[paragraph break]But no, they have no true claim on you. You rise, rise, rise, the stars your destination.”;
Say “No, none of that happens.”

This is the output that I get:

̶Y̶o̶u̶ ̶f̶l̶o̶a̶t̶ ̶u̶p̶ ̶i̶n̶ ̶t̶h̶e̶ ̶a̶i̶r̶,̶ ̶c̶l̶o̶u̶d̶s̶ ̶l̶a̶p̶p̶i̶n̶g̶ ̶a̶t̶ ̶y̶o̶u̶r̶ ̶f̶e̶e̶t̶.̶ ̶ ̶B̶e̶l̶o̶w̶,̶ ̶t̶h̶e̶ ̶h̶u̶m̶b̶l̶e̶ ̶p̶r̶e̶c̶i̶n̶c̶t̶s̶ ̶o̶f̶ ̶y̶o̶u̶r̶ ̶h̶o̶m̶e̶ ̶s̶h̶r̶i̶n̶k̶,̶ ̶r̶e̶c̶e̶d̶e̶;̶ ̶t̶h̶e̶n̶ ̶y̶o̶u̶r̶ ̶t̶o̶w̶n̶;̶ ̶t̶h̶e̶n̶,̶ ̶t̶h̶e̶ ̶w̶o̶r̶l̶d̶.̶
̶
̶T̶h̶e̶ ̶s̶u̶r̶l̶y̶ ̶b̶o̶n̶d̶s̶ ̶o̶f̶ ̶g̶r̶a̶v̶i̶t̶y̶ ̶c̶a̶t̶c̶h̶ ̶a̶t̶ ̶y̶o̶u̶,̶ ̶a̶n̶d̶ ̶y̶o̶u̶ ̶h̶i̶c̶c̶u̶p̶ ̶d̶o̶w̶n̶,̶ ̶u̶p̶,̶ ̶d̶o̶w̶n̶ ̶u̶p̶ ̶-̶-̶
̶
̶B̶u̶t̶ ̶n̶o̶,̶ ̶t̶h̶e̶y̶ ̶h̶a̶v̶e̶ ̶n̶o̶ ̶t̶r̶u̶e̶ ̶c̶l̶a̶i̶m̶ ̶o̶n̶ ̶y̶o̶u̶.̶ ̶ ̶Y̶o̶u̶ ̶r̶i̶s̶e̶,̶ ̶r̶i̶s̶e̶,̶ ̶r̶i̶s̶e̶,̶ ̶t̶h̶e̶ ̶s̶t̶a̶r̶s̶ ̶y̶o̶u̶r̶ ̶d̶e̶s̶t̶i̶n̶a̶t̶i̶o̶n̶.

No, none of that happens.

Problem the first: the strike-through character is getting applied to the paragraph breaks, leading to those unsightly dashes in the empty lines. Ideally, I’d be able to include a conditional like "if Y is not “[paragraph break]”, say “[unicode 822][Y]; otherwise, say “[Y]”.” That compiles but doesn’t change the output, sadly, so either I’ve misdiagnosed the cause or misapplied the solution (or maybe I’ve messed things up in yet some third way!)

Obviously I could just make each paragraph of text its own invocation of the strike through phrase, but for obscure reasons of personal style I’d rather not do that, and besides now that I’ve run into the issue I’m curious how to resolve it the proper way.

Problem the second: even generating these relatively short couple of paragraphs leads to a noticeable lag in the IDE, a shorter one in Lectrote, and a still shorter but still noticeable hitch in Gargoyle. My laptop isn’t the fastest thing out there, but it’s not too bad, and given how prolix this post is you’ll perhaps be unsurprised to learn that the game involves much longer passages of struck-through text than this example – so I’m concerned about performance.

Is there anything to be done on this front? The answer could be “release it with a web-based interpreter like Quixe and do CSS stuff” but I’m really hoping it’s not. Alternately, I suppose I could write a separate I7 program that outputs the code which I can then paste into the main program, which would at least cut out the loops so might be a little faster – obviously that would make revisions much much harder, though. So would welcome any genius ideas here, though I suspect this might just be One Of Those Things.

Inform is actually medium-bad at manipulating text. :)

3 Likes

Do only static pieces of text need to be struck through? That is, things without any substitutions? If so, I’d recommend using a simple Python script to do this and output strings you can paste into the IDE.

Apart from that, [paragraph break] isn’t a single character, but I believe [line break] is. Try comparing against that one.

Alternately, have Inform break the text into lines before breaking it into characters, process each line, then output a line break in between.

2 Likes

This works somewhat better:

To strike through (A - a text):
	let litbreak be the substituted form of "[line break]";
	Repeat with X running from 1 to number of characters in A:
		Let Y be character number X in A;
		if Y is litbreak:
			say Y;
		else:
			say "[Y][unicode 822]";
	Say "[paragraph break]".

First, the 822 needs to come after the character it modifies.

Comparing Y to a line break every time is going to be slow, but if we set litbreak to a pre-substituted string, it’s not quite as terrible.

6 Likes

There are I6 approaches which will be quite a bit faster, but I don’t know how much headache you want.

3 Likes

Well, in case you do, this is the headachiest:

To strike through (A - a text): (- PrintWithStrikethrough({A}); -);

Include (-
[ AddUnicode822 ch;
	glk_put_char_uni(ch);
	if (ch ~= 10)
		glk_put_char_uni(822);
];

[ PrintWithStrikethrough text;
	@setiosys 1 AddUnicode822;
	TEXT_TY_Say(text);
	@setiosys 2 0;
	new_line;
];
-);
9 Likes

I had completely forgotten about setiosys 1. That’s a really elegant way to do it.

1 Like

It is not very headachey when all I have to do is paste in some zarf-written I6! Thanks, this speeds it up immeasurably.

…Okay, I guess there is maybe a little headache, which is that there’s a reason I put the Unicode 822 before, not after – here’s what the output looks like in Lectrote:

image

It looks like the strikethrough isn’t being applied to the first character, which leads to an annoying lack of alignment on the left margin when the text goes to a second line. Despite knowing no I6, I am at least a sufficiently clever monkey to realize that I can add an additional “glk_put_char_uni(822);” to the start of the PrintWithStrikethrough function, which takes care of the first paragraph, but with more messing around I’m not figuring out a way to do the same for subsequent paragraphs, in the case where I’m feeding multiple paragraphs in at once, without getting those annoying “orphan” strikethroughs in the empty lines.

So unless I’m missing something obvious, seems like the best approach is to just invoke it paragraph by paragraph, but I can live with that. Thanks again!

2 Likes

When I test this in Lectrote, it fails completely in a lot of the default fonts.

Courier and Helvetica work, and then my original code does apply the mark to the first character. (This is easy to see in Courier.)

2 Likes

That’s not the I6’s fault, that’s the font not properly overlaying the strikethrough character onto the text. Unfortunately there’s not much you can do about that apart from using better fonts. COMBINING LONG STROKE OVERLAY wasn’t originally meant for this purpose, after all: Unicode used to have the philosophy that formatting things don’t belong in the text itself, since strikethrough like this makes the text unsearchable and has to render it on a character-by-character level instead of on an entire word, sentence, or paragraph.

1 Like

That’s all true, but this thread disposed of the honorable CSS approach in the first paragraph. So here we are.

Although it is worth noting that compatibility issues are exactly what we’ve got. Just at the font level rather than the using-CSS-at-all level.

2 Likes

Ha, funny (“funny”), on Windows at least I’m seeing it work on all the built-Lectrote fonts except Courier (the first character overlap looks a little funny on some of them, though). So as you and Daniel say, not ideal, but it shouldn’t be too much trouble to build in a little test at the beginning of the game and if a player’s not seeing the strikethrough working well, allow for a fallback mode where we all pretend italic text is really struck-through or something like that.

Thanks again to you both for the help!

1 Like

Italic text then normal text is a real “snap back to reality” moment:

You push off against the ground and feel yourself rise through the air. The world disappears below your feet and you rush into the empty beauty of space…

Oh, there goes gravity. You’re on the ground, back in the real world.

2 Likes

If you haven’t looked yet at Aaron Reed’s Keyword Interface extension, it might be worth looking at to see how it handles this, if only for ideas. It allows players to choose a text style that displays appropriately on their interpreter. For what it’s worth, once I had Keyword Interface doing what I wanted it to do (I ended up adding some more display options that I hoped would be more screen reader friendly, in case a screen reader didn’t announce that the text was bold or whatever), I remember it being pretty simple to add CSS to make it work in Quixe. I wasn’t doing strike-through specifically, though.

1 Like

@DeusIrae

The speed seems reasonable with a slightly efficient loop that isn’t transmuting/untransmuting the text twice per character.

lab is a room.
strikethrough is always unicode 822.
newline is always unicode 10.

when play begins:
repeat for c in chars of wotw  begin;
  say c;
  if c is not newline, say strikethrough;
end repeat;

To repeat with/for (c - nonexisting unicode character variable) running/-- through/in chars/characters of/in/for (t - text) begin -- end loop:
(-
  {-my:0} = {t}-->0;
  @push {-my:0};
  {-my:1} = TEXT_TY_Temporarily_Transmute({-by-reference:t});
  @push {-my:1};
  for ( {-my:1} = 0, {c} = BlkValueRead({-by-reference:t}, 0) : {c} : {c} = BlkValueRead({-by-reference:t}, ++{-my:1} ))
    {-block}
   @pull {-my:1};
   @pull {-my:0};
   TEXT_TY_Untransmute({-by-reference:t}, {-my:1}, {-my:0});
-)

wotw is initially "No one would have believed in the last years of the nineteenth century that this world
was being watched keenly and closely by intelligences greater than man's and yet as mortal as his
own; that as men busied themselves about their various concerns they were scrutinised and studied,
perhaps almost as narrowly as a man with a microscope might scrutinise the transient creatures that
swarm and multiply in a drop of water. With infinite complacency men went to and fro over this globe
about their little affairs, serene in their assurance of their empire over matter. It is possible
that the infusoria under the microscope do the same. No one gave a thought to the older worlds of
space as sources of human danger, or thought of them only to dismiss the idea of life upon them as
impossible or improbable. It is curious to recall some of the mental habits of those departed days.
At most terrestrial men fancied there might be other men upon Mars, perhaps inferior to themselves
and ready to welcome a missionary enterprise. Yet across the gulf of space, minds that are to our
minds as ours are to those of the beasts that perish, intellects vast and cool and unsympathetic,
regarded this earth with envious eyes, and slowly and surely drew their plans against us. And early
in the twentieth century came the great disillusionment.";

[ Edited to replace code with an improved version ]

3 Likes