Ada and the (ansi) console

Hi, I’m studying with the Ada Craft (95) manual, but I have a big issue, in that I am autistic. I have an idea of how I want to do it, what seems the most intuitive to me, regardless of the language’s capabilities or how much of it I learnt.

Here’s an exemple:

Change the way that appointments are listed so that they are displayed a screenful at a time (or just under a screenful to allow room for prompts etc.) on the system that you’re using. Provide the ability to go either forwards or backwards a screen or half a screen at a time.

In my head, I need to know how to :

  • Clear the screen
  • define the type and object “page” made of (Page_Length) lines of (Line_Length) characters.
  • Reformat the output to fit “page”, populate “page” and outputs it

But I’m pretty sure I shouldnt do that, but I can’t figure out, and waiting is not gonna help, because I’m autistic. I can not think “simply”. I would like a tutorial for dealing with terminals in Ada…

Also, I have debian, and I can only clear the screen and change the line with ANSI codes. New_Page and Set_Line have no effect, beside adding two new lines for the former. The line number is reset alright, but with no change to the terminal. Checked on bash, fish, urxvt and foot. Seems like Ada.Text_IO can’t controll the standard input, and can’t request line length either.
So I don’t understand how to do the exo, since I’m pretty sure I’m not expected to use a binding to ncurse…

You can use a library to output ANSI control sequence for the terminal, like this, for example:

2 Likes

ANSI-control strings are available from package PragmARC.Ansi_Tty_Control.

However, nothing in your requirements indicates that you need to do this. You can simply output a screen-full of information, scrolling the existing information off the screen, and wait for user input.

1 Like

I know I am missing something obvious, but I do not know how to define a “screenful”.

If your screen/terminal emulator has N lines, then a screenful is usually N - 1 lines, with the Nth line reserved for prompts/input. N is often 24. Consider

with Ada.Text_IO;

procedure Screens_Full is
   Screen_Lines : constant := 23; -- Presume 24-line terminal, with last line for prompts/input
   
   procedure Display (Start : in Positive);
   -- Display a screenful of lines, starting with line Start
   
   procedure Display (Start : in Positive) is
      -- Empty
   begin -- Display
      All_Lines : for L in Start .. Start + Screen_Lines - 1 loop
         Ada.Text_IO.Put_Line (Item => "Line" & L'Image);
      end loop All_Lines;
   end Display;
   
   Next    : Positive := 1;
   Command : Character;
begin -- Screens_Full
   All_Screens : loop
      Display (Start => Next);
      
      Get_Command : loop
         Ada.Text_IO.Get_Immediate (Item => Command);
         
         case Command is
         when 'n' => -- Next screen
            Next := Next + Screen_Lines;
            
            exit Get_Command;
         when 'p' => -- Previous screen
            Next := Integer'Max (1, Next - Screen_Lines);
            
            exit Get_Command;
         when 'q' => -- Quit
            return;
         when others =>
            null;
         end case;
      end loop Get_Command;
   end loop All_Screens;
end Screens_Full;

“Often” 24. I suppose I can’t request the real number. And What happens if “Line” becomes a long string, that spans more than one one line ?
I wish I could just take in all the output and refactor it in pages of appropriate width and height. But I’m not supposed to think so hard, ok.

The answer to those questions may be implementation dependent and may also change based on terminal settings. I know for BASH shells I can do “echo $LINES” to get the number of lines in the terminal, but that number can change if the person stretches the window. In my case stuff that is longer than the terminal line just extends out into space and I can use the scroll bar to see it.

But it may very with different terminals and different OS versions.

So pretty much “no you can’t / won’t” :sweat_smile:
It’s one of those cases, when in school I would refuse the assignment whose instructions are not clear enough.

Possibly yeah. Unfortunately the practical implications of how systems exist can make general solutions tough or even in some cases impossible. In those cases you either have to bite your lip and just do a suboptimal solution (relative to your preferences) or abandon the process all together.

If you know the appropriate width and height then you know the number of lines. If you don’t know them, and have to deal with the possibility of them being different from run to run, then displaying a “screenful” becomes pretty much impossible. I don’t know a portable way to obtain those values. Possibly some combination of the ANSI position-cursor and report-cursor codes could do it.

But as this is a pedagogical exercise, I suspect you’re over-thinking things. No doubt the intention is that you assume the default size of the console/terminal emulator you are using, and ignore the possibility that it might be different.

I would look at libcurses (don’t know whether there are Ada bindings, but the API is not that extensive in practice). It will let you query terminal size, write characters are specific positions on the screen, and so on. For inspiration, take a look at the curses package in python possibly, or the doc of libcurses itself

Ahahah, far above my paygrade for now… But yeah, I figured that it’s the only portable way on linux, which is the only system I care for anyway.

I see that Alire has a crate ncursesada which might help, though at a first glance it doesn’t seem to be designed for use by humans (i.e. me).

There is an issue if you’re on a Mac, but ISTR you aren’t?

There’s a much much simpler crate ansiada.

Also trendy_terminal.

I’m a little late, but Ncurses is overkill for this. All of this can very easily be done without a library and, while I used the DEVICE STATUS REPORT control function which makes the terminal send an ACTIVE POSITION REPORT control function I then parsed to get the current position of the cursor and from that the dimensions, an Ada program would be better suited to binding the C language bullshit that returns this value more easily. Unlike Common Lisp, Ada makes it very easy to bind to such routines.

I didn’t know DSR, yes that seems to be what I was looking for. I need to read more about terminal control, just for curiosity.

I link to the ECMA-48 standard from this article:
http://verisimilitudes.net/2017-12-31

That article is documentation for the library which forms the foundation of this library:
http://verisimilitudes.net/2018-04-04

I almost wrote a shitty Ada library like this, but the lack of metaprogramming swayed me. Only a handful of these control functions are needed for most programs, so a library is superfluous. I may as well continue to use mine, however.