7

Here's the situation, I want to make some terminal interaction, I want to start child thread to refresh the first N lines, and use the main thread to handle user input.

After that the program will print changeable string, maybe some logs.

The child thread like this:

    let mut count: i32 = 0;
    loop {
        println!("\x1B[2F\x1B[2KHi user1, count:{}\n", count);
        count += 1;
        let ten_millis = time::Duration::from_millis(1000);
        thread::sleep(ten_millis);
    }

e.g.:

----------------
Hi user1, count: 0


Input:  1+1
Output: 2
----------------

The refresher code works well, but the cursor will reset to the start of line, and I want to move it always to the end of the last line. How can I do this trick?

Any help would be great appreciated.

McGrady
  • 10,869
  • 13
  • 47
  • 69
  • 1
    What programming language is this? It is not bash. Please remove the `bash` tag and add the appropriate tag. This will attract more attention from people who can better answer your question. – Adam Katz Dec 18 '18 at 17:46
  • @AdamKatz Actually, I think the same principle applies to other languages, my code is just an example. – McGrady Dec 19 '18 at 01:37

3 Answers3

10

When it boils down to moving the cursor around, you might be interested in simple ANSI escape Sequences:

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:

Description Sample
Put the cursor at line L and column C \033[<L>;<C>H
Put the cursor at line L and column C \033[<L>;<C>f
Move the cursor up N lines \033[<N>A
Move the cursor down N lines \033[<N>B
Move the cursor forward N columns \033[<N>C
Move the cursor backward N columns \033[<N>D
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

source: Bash Prompt HOWTO: Cursor movement

While these ANSI escape sequences work very nicely, you might, from time to time be interested in the usage of tput as it gives you more readablilty of your scripts. Explaining tput here would be a bit overkill, but the above commands can be done as:

Description Sample
Put the cursor at line L and column C tput cup <L> <C>
Move the cursor up N lines tput cuu <N>
Move the cursor down N lines tput cud <N>
Move the cursor forward N columns tput cuf <N>
Move the cursor backward N columns tput cub <N>
Clear the screen, move to (0,0) tput clear
Erase to end of line tput el
Save cursor position tput sc
Restore cursor position tput rc

There are many many many other options available. See

  • man tput
  • man 5 terminfo
Reishin
  • 1,854
  • 18
  • 21
kvantour
  • 25,269
  • 4
  • 47
  • 72
0

You could make the child "know" that input is in progress, and in that case, follow the println!

  • with an additional cursor-down (i.e., \x1B[B) or next-line (\x1B[E),
  • followed by a movement in that line using the length of the prompt plus the length of the current input, e.g., cursor-forward (i.e., \x1B[C with the number of columns as a parameter before the C).

Something like

if (input_length) {
    cursor_down();
    cursor_forward(prompt_length + input_length);
}
Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
  • ,let me try it. – McGrady Dec 14 '18 at 11:06
  • But if the input string is changeable, maybe multiple lines, can I reset the cursor to the end of last line? what about `\033[s` to save cursor position? – McGrady Dec 14 '18 at 11:31
  • That depends upon the terminal (see [this](https://stackoverflow.com/questions/28986776/ansi-escape-sequence-save-restore-cursor-position-support)). – Thomas Dickey Dec 14 '18 at 22:29
0

While not quite answering your question, the standard bash way to do this is watch

For example:

watch df -h

MrMartin
  • 411
  • 5
  • 18