Programmatically expand terminal to a specific size - c++

In my output there are certain lines that are refreshed every few seconds. If I resize the terminal by clicking F11, then output is just as I wanted. If terminal isn't big enough some long lines that are refreshed are splitted in two, and because of that, only one part of line is refreshed, and every time line is refreshed I also get new line.
This could be easily avoided if I could specify default size of terminal (resize terminal from my program). Also it would be great if I could forbid user to change terminal size while program is running.
while(1)
{
cout<<"Long line that is refreshed every 5s... \r";
//if line is splited in two lines, \r will return to beginning of that new line
//and the first part of original line would stay as it is(won't be rewrited)
sleep(5);
}
How do I specify a terminal size or stop terminal resizing?

Some terminal emulators (including the default macOS Terminal.app) support being resized/moved/etc in response to printed control sequences. The sequences are fairly standard but not all terminal emulators implement all of them.
For example:
# set terminal width to 50, height to 100
cout << "\e[8;50;100t";
This answer includes an overview of some other available control sequences.

I don't think you can forbid the user to change the terminal size. A better way would be to catch the SIGWINCH signal that is sent to the process everytime the window size is changed, and use the TIOCGWINSZ / TIOCGSIZE ioctl() to get the dimensions.

Related

clearing the output stream c++

Hello I'm trying to build a function grapher on the terminal in c++. I want that every time a new function is added the output will be cleared and the new frame will take its place.
I've tried to do system("clear") but I don't want all the terminal to be cleared and only the output stream. I've also thought about printing '\b' a lot of times but that seems inefficient.
I would also like to know how to delete 1 line.
You may try to work with console code.
Console code about cursor
There are two solution.
Here is some C style code, just to demonstate the idea easier, you may convert it into C++ style.
Clear content
//Clear content after (x,y)
printf("\033[%d,%dH\033[J",y,x);
//x the column number,y the row number
Overwrite the content
//Goto (x,y) then print the next frame, it should overwrite the old content
printf("\033[%d,%dH",y,x);
...
//your code to output the next frame

How to move cursor position when printing data in Linux Terminal using C++? [duplicate]

I'm currently designing a CLI interface for linux, and for various reasons I am not able to use ncurses. I am using exclusively C++ and the Qt framework.
Therefore, in order to have a user-friendly interface, I have to run this getch loop in a separate thread:
https://stackoverflow.com/a/912796/3605689
Which basically means I have to implement all basic functionalities (such as backspace) by myself. I have already implemented command completion and command history(like when you press tab or uparrow/downarrow in linux), but I can't figure out how to implement leftarrow/rightarrow (aka seeking through the typeahead).
Normally, I implement it like this: upon every gech which is not equal to -1, I check whether the user has pressed a special key (one that modifies the typeahead somehow). I then clear the stdout using the following function:
void inputobject::clear_line(int nletters)
{
QTextStream(stdout) << "\033[2K";
for(int i = 0; i < nletters;i++){
QTextStream(stdout) << "\b";
}
rewind(stdout);
}
And replace it with something else, effectively simulating the typeahead. For example, in the case of backspace, I would save the command call clear_line, and print the command out again, just with one less letter, behaving exactly as a normal console application would.
My real problem is with the cursor, in the case of left/rightarrow, I need to move the cursor visual in order to be able to indicate where in the text is the user seeking:
Because of the nature of how I rewrite the given stdout line to simulate the typeahead, it does not really matter where the cursor REALLY is, as long as it stays on the same line - it is just the visual that matters. How can I achieve moving the cursor visual on linux?
The answer was provided in the comment by Evilruff:
Cursor Movement
ANSI escape sequences allow you to move the cursor around the screen at will. This is more useful for full screen user interfaces generated by shell scripts, but can also be used in prompts. The movement escape sequences are as follows:
Position the Cursor:
\033[;H
Or
\033[L;Cf
puts the cursor at line L and column C.
Move the cursor up N lines:
\033[NA
Move the cursor down N lines:
\033[NB
Move the cursor forward N columns:
\033[NC
Move the cursor backward N columns:
\033[ND
Clear the screen, move to (0,0):
\033[2J
Erase to end of line:
\033[K
Save cursor position:
\033[s
Restore cursor position:
\033[u
Not using ncurses and co is a serious limitation.
It is hell to make correct input/output on shell for displaying anything.
The only others real solutions (I can't think as a solution to reimplement a ncurse-like library) I think of are:
making call to dialog (for some example www.linuxjournal.com/article/2807 and for the doc: http://linux.die.net/man/1/dialog)
using the framebuffer mecanism with Qt4 (here)

Displaying large output on terminal window

int a[10000];
for(int i=0;i<10000;i++)
{
a[i]=i; cout<<a[i]<<endl;
}
Suppose this is the code and on the terminal screen I need all outputs (0-9999) But it only displays (9704-9999) at the end
I want to see all the numbers on the terminal window but it removes the upper part of the data. I guess I have to change some settings.
Increase the console buffering. Depending on which terminal you're using it'll be different. For example on Windows conhost.exe is the default console used by cmd and PowerShell. Just click the icon on the top left > Properties > Layout and set Screen Buffer Size to a large enough number
But the better solution would be redirecting to file, because no one wants to read 10000 lines on the console, and there's no guarantee that the console will have a buffer of infinite length or length of more than 10000 lines. conhost for example only supports maximum 9999 lines so you'll miss at least the command you typed and the first output line. Besides that'll often remove other commands' output from the history which is undesirable
Either do that from the command line with the redirection operator >
yourapp.exe >output.txt
or save to file directly from your code

Linux - moving the console cursor visual

I'm currently designing a CLI interface for linux, and for various reasons I am not able to use ncurses. I am using exclusively C++ and the Qt framework.
Therefore, in order to have a user-friendly interface, I have to run this getch loop in a separate thread:
https://stackoverflow.com/a/912796/3605689
Which basically means I have to implement all basic functionalities (such as backspace) by myself. I have already implemented command completion and command history(like when you press tab or uparrow/downarrow in linux), but I can't figure out how to implement leftarrow/rightarrow (aka seeking through the typeahead).
Normally, I implement it like this: upon every gech which is not equal to -1, I check whether the user has pressed a special key (one that modifies the typeahead somehow). I then clear the stdout using the following function:
void inputobject::clear_line(int nletters)
{
QTextStream(stdout) << "\033[2K";
for(int i = 0; i < nletters;i++){
QTextStream(stdout) << "\b";
}
rewind(stdout);
}
And replace it with something else, effectively simulating the typeahead. For example, in the case of backspace, I would save the command call clear_line, and print the command out again, just with one less letter, behaving exactly as a normal console application would.
My real problem is with the cursor, in the case of left/rightarrow, I need to move the cursor visual in order to be able to indicate where in the text is the user seeking:
Because of the nature of how I rewrite the given stdout line to simulate the typeahead, it does not really matter where the cursor REALLY is, as long as it stays on the same line - it is just the visual that matters. How can I achieve moving the cursor visual on linux?
The answer was provided in the comment by Evilruff:
Cursor Movement
ANSI escape sequences allow you to move the cursor around the screen at will. This is more useful for full screen user interfaces generated by shell scripts, but can also be used in prompts. The movement escape sequences are as follows:
Position the Cursor:
\033[;H
Or
\033[L;Cf
puts the cursor at line L and column C.
Move the cursor up N lines:
\033[NA
Move the cursor down N lines:
\033[NB
Move the cursor forward N columns:
\033[NC
Move the cursor backward N columns:
\033[ND
Clear the screen, move to (0,0):
\033[2J
Erase to end of line:
\033[K
Save cursor position:
\033[s
Restore cursor position:
\033[u
Not using ncurses and co is a serious limitation.
It is hell to make correct input/output on shell for displaying anything.
The only others real solutions (I can't think as a solution to reimplement a ncurse-like library) I think of are:
making call to dialog (for some example www.linuxjournal.com/article/2807 and for the doc: http://linux.die.net/man/1/dialog)
using the framebuffer mecanism with Qt4 (here)

cursor blinking removal in terminal, how to?

I use the following lines to output my simulation's progress info in my c++ program,
double N=0;
double percent=0;
double total = 1000000;
for (int i; i<total; ++i)
{
percent = 100*i/total;
printf("\r[%6.4f%%]",percent);
}
It works fine!
But the problem is I see the terminal cursor keeps blinking cyclically through the numbers, this is very annoying, anyone knows how to get rid of this?
I've seen some programs like wget or ubuntu apt, they use progress bar or percentages too, but they seems no blinking cursor issue, I am wondering how did they do that?
Thanks!
You can hide and show the cursor using the DECTCEM (DEC text cursor enable mode) mode in DECSM and DECRM:
fputs("\e[?25l", stdout); /* hide the cursor */
fputs("\e[?25h", stdout); /* show the cursor */
Just a guess: try to use a proper number of '\b' (backspace) characters instead of '\r'.
== EDIT ==
I'm not a Linux shell wizard, but this may work:
system("setterm -cursor off");
// ...display percentages...
system("setterm -cursor on");
Don't forget to #include <cstdlib> or <iostream>.
One way to avoid a blinking cursor is (as suggested) to hide the cursor temporarily.
However, that is only part of the solution. Your program should also take this into account:
after hiding the cursor and modifying the screen, before showing the cursor again move it back to the original location.
hiding/showing the cursor only keeps the cursor from noticeably blinking when your updates take only a small amount of time. If you happened to mix this with some time-consuming process, your cursor will blink.
The suggested solution using setterm is not portable; it is specific to the Linux console. And running an executable using system is not really necessary. But even running
system("tput civis");
...
system("tput cnorm");
is an improvement over using setterm.
Checking the source-code for wget doesn't find any cursor-hiding escape sequences. What you're seeing with its progress bar is that it leaves the cursor in roughly the same place whenever it does something time-consuming. The output to the terminal takes so little time that you do not notice the momentary rewrite of the line (by printing a carriage return, then writing most of the line over again). If it were slower, then hiding the cursor would help — up to a point.
By the way — this cursor-hiding technique is used in the terminal drivers for some editors (vim and vile).
Those apps are probably using ncurses. See mvaddstr
The reason the cursor jumps around is because stdout is buffered, so you don't know actually how many characters are being printed at some point in time. The reason wget does not have a jumping cursor is that they are actually printing to stderr instead, which is unbuffered. Try the following:
fprintf(stderr, "\r[%6.4f%%]", percent);
This also has the advantage of not cluttering the file if you are saving the rest of the output somewhere using a pipe like:
$ ./executable > log.data
Press insert key...if that doesn't work then press the fn key in your keyboard.
This will definitely work
Hope this helps