Recent

Author Topic: GotoXy in terminal (crt) (Linux, FPC 3.2)  (Read 2430 times)

MarkMLl

  • Hero Member
  • *****
  • Posts: 3471
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #15 on: October 27, 2021, 06:52:24 pm »
I've not looked at the code but it's reasonable to assume that crt doesn't really have a buffer... or if it does it's limited at say 50 rows and 132 cols (those being about the largest I remember on TP-era screens, and 132 also being significant for printer paper).

So if you wanted to implement a larger buffer you'd need to do it yourself, hook the various output routines to put text into that buffer rather than simply sending it to the screen at the current cursor position, and then output that part of the buffer which was determined by (a) the physical window size and (b) the scroll position.

You'd know if the window size changed (from hooking WINCH) but knowing when the terminal was scrolling would be more of a problem... these days it might be handled by DBus etc. but I don't know the "legacy" way of doing it (or if the problem was left entirely with Konsole etc.).

Two final thoughts. First, cursor addressing has an inherent compatibility problem with scrolling... you have to consider what happens if the top line gets deleted. Second, you might find GNU Screen worth looking at since it reimplements cursor etc. handling and has its own buffering.

Somewhat later: there is a 1024x1024 backing store in the crt unit, with an assumed display window of 80x25. I don't think it does anything particularly clever to detect window sizes etc. imposed from external to the program, so most of my points above still apply.

MarkMLl
« Last Edit: October 27, 2021, 07:54:15 pm by MarkMLl »
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Warfley

  • Hero Member
  • *****
  • Posts: 601
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #16 on: October 27, 2021, 09:11:59 pm »
Some time ago I had a similar question to you, how all these unix programs can make so fancy stuff with the terminal and how I could use this myself, and like you the first thing I've found was the crt unit.
Well I am not a big fan of the crt unit and I will explain later why, but because of that I went out to try and figure out how this stuff works.

Generally speaking, every operating system and every terminal emulator does this differently. On DOS you basically get a buffer that is what is represented in the console, if you update the buffer the screen updates at the positions accordingly. On windows this is replaced with more traditional api calls, but because windows is backwards compatible to the stone ages, it also supports the dos style. But most modern terminals use so called escape sequences, basically if you write special commands to the output the terminal will interpret this and make things happen.
Each of these different approaches have different capabilities and this is one of the reason why I don't like crt, crt is designed to work on pretty much every system supported by the FPC, therefore it only supports the subset of functions that is available on all platforms.
The second problem is that it tries to simulate some of the functionality not available on the plattform (e.g. the WhereX on Linux by simply counting the characters printed and lines and stuff), for doing this crt basically intercepts every read and write operation, which has the side effect that simply by including crt in the uses clausel, the behavior of your program will change (significantly in some cases) even if you don't use any functionality of crt, which is something I really don't like when using a library of which I only need a few functions.

So whats the alternative? Well there are a few things that work on any terminal. The CR char (#13) will move  the cursor the the beginning of the current line and the backspace char (#8) moves the cursor one char backwards.
When you write, you write at the current position of your cursor and override anything that is at that position. So if you move your cursor to the start of the line and write something you override the old line.

So if your goal is to only rewrite the last line, you don't need any special libraries or escape sequences, just don't write a newline at the end of the line and when overriding start your string with #13:
Code: Pascal  [Select][+][-]
  1. Write('This line will be replaced');
  2. Write(#13, 'With this line!');

But let's say you wanted to do a more complex application, like for example wget which has like 4 lines to display the current state of the download, you must use something more advanced.
You could do so by using crt, but as I said it's not the best library, but if you don't have a problem with not supporting systems like 16 bit DOS or amiga, you could simply go by using escape sequences, as these are currently supportet on all major operating systems (windows, linux, macos, bsd). Also by doing this you have much more possibilties than with the crt unit (e.g. full 24bit true color support)

The great thing about escape sequences is, they are very easy to implement even without a specialized library, simply write a given string into the console and the magic happens
E.g. to override the last 4 lines:
Code: Pascal  [Select][+][-]
  1. WriteLn('Line 1');
  2. WriteLn('Line 2');
  3. WriteLn('Line 3');
  4. Write('Line 4'); // no newline so we have to go back 1 line less
  5. Write(#27'[3D'); // #27 + '[' is escape sequence, 4D is 3 lines up
  6. WriteLn('Line 1 New');
  7. WriteLn('Line 2 New');
  8. WriteLn('Line 3 New');

To move in any direction us #27'[XY' where X is the number of cells you want to move and Y is A to move to the left, B to move to the right, C to move down and D to move up, so 3D means move 3 up. It will automatically stop at the first visible line (i.e. the first line in the window) so you can't override older lines.
After moving your cursor where you desire, simply rewrite the line with the new content and you are done.

This is what I would recommend if you want to do very simple stuff, no libraries needed, just a few writes. If you want to learn more about escape sequences, the Wikipedia article is quite nice: Link

So what if you want to do more complex stuff, like really interactive console applications such as vim or emacs. Then you could use crt, but again here due to the fact that crt only implements the subset of functionality available on all platforms this also limits your possibilities.
Thats why I a few years ago build my own library that specializes on Escape sequences, it can basically everything crt can, but better because it doesn't need to worry about systems I won't ever use. If you want to take a look at it, check it out: Link
There is one exception to that statement, it can't track the cursor position (WhereX, WhereY of CRT) the reason for this is, that this is actually really hard to do and the main reason why crt has to do all these naughty things with the input and output files changing program behavior. Basically because I wanted to keep my library seperate from the default readln writeln functionality as good as possible there is no way for it to track the current cursor position. If you want to do this you need to implement that functionality for yourself.

But it is pretty powerful, for example the colortest example shows that you can easiely repaint the whole screen at 30-60 fps (60 on linux, 30 on windows because windows console is very slow) so you can easiely use this to print animations or play games (with a very poor resolution, but it works)

There is just one thing you always need to keep in mind when working with escape sequences, the terminal scrolls when your cursor hits the last line. So having one WriteLn instead of a write at the end, might scroll past the first line, resulting in that line not being accessible anymore (as i said you can only move to the window border)
« Last Edit: October 27, 2021, 09:31:38 pm by Warfley »

MarkMLl

  • Hero Member
  • *****
  • Posts: 3471
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #17 on: October 27, 2021, 09:31:17 pm »
Broadly agreed with @Warfley, and I'd note the significance of the term "ansi.sys" in the DOS era. However this does rather sweep scrolling and window size changes under the carpet: it relies entirely on the window manager etc. to get it right.

I'd comment that IBM's TopView attempted to regiment screen-mapped I/O a bit better, and that some of the same approaches were later implemented (with minimal documentation) by the much more popular DesqView for compatibility.

As a fairly early adopter of the OS/2, Windows etc. OSes but a late adopter of their development tools (in part because I was developing for embedded systems in parallel with anything I did on the desktop) I've done /rather/ a lot of investigation of this over the years.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Warfley

  • Hero Member
  • *****
  • Posts: 601
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #18 on: October 27, 2021, 09:36:39 pm »
However this does rather sweep scrolling and window size changes under the carpet: it relies entirely on the window manager etc. to get it right.
With regards to this, I found the easiest solution is to just grab the current terminal size before doing any writing, and compute how you need to do your writing (e.g. a progressbar how many colums are filled and how many are empty). This is the approach most of the linux applications (like wget) use. They don't care if lines are broken once they are "finished", they just redraw the currently active lines according to the current screen size which will overdraw the old version that might have been broken through resizing.

If it is more complex I then go to the other extreme and simply redraw the whole frame whenever a resize occured. Linux terminals like XTerm, Gnome Terminal or Konsole, as well as MacOS Terminal can easiely redraw at 60 frames per second and even the painfully slow windows console can redraw at 30. (Of course dependent on window size and font size, this was for my 4k monitor fullscreen with font size 14)
« Last Edit: October 27, 2021, 09:40:23 pm by Warfley »

MarkMLl

  • Hero Member
  • *****
  • Posts: 3471
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #19 on: October 27, 2021, 10:00:56 pm »
One of the reasons I slipped WINCH monitoring into the Lazarus IDE's console window was that I wanted to test that it did in fact work in the context of something which hadn't been explicitly written as a shell.

However I agree with you: most programs quite simply ignore it unless they're actually using something like Curses.

Handling scrolling is of course a separate issue, and risks getting bogged down in the fundamental difference between Windows and X11 window handling (on Windows, the "furniture" is part of the program, while on X11 it's not).

The Linux kernel's input event handling doesn't get scroll events, so I suspect that anything interested would have to interact with X11... which could be a problem for a non-GUI program.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

big_M

  • New Member
  • *
  • Posts: 41
Re: GotoXy in terminal (crt) (Linux, FPC 3.2)
« Reply #20 on: October 27, 2021, 10:59:08 pm »
Oh, thanks a lot @Warfley for this great explanation, this makes this topic much clearer to me now. I will definitely try both the escape sequences as well as the CR chars. This was really helpful, thank you. I will have to play around a bit with this to get a sense of the possibilities and limitations, but I'm really not after something complex.

Also thanks again @MarkMLl

« Last Edit: October 27, 2021, 11:09:53 pm by big_M »

 

TinyPortal © 2005-2018