1

I tried the following code

s='Python is an interpreted high-level programming language for general-purpose programming. Created by Guido van Rossum and first released in 1991, Python has a design philosophy that emphasizes code readability, notably using significant whitespace. It provides constructs that enable clear programming on both small and large scales'
s1='Python features a dynamic type system and automatic memory management. It supports multiple programming paradigms, including object-oriented, imperative, functional and procedural, and has a large and comprehensive standard library'
print(s,end='\r')
print(s1)

Output I got is

Python is an interpreted high-level programming language for general-purpose programming. Created by Guido van Rossum and first released in 1991, Python has a design philosophy that emphasizes code readability, notably using significant whitespace. It provides con
Python features a dynamic type system and automatic memory management. It supports multiple programming paradigms, including object-oriented, imperative, functional and procedural, and has a large and comprehensive standard library

The first string s is printing on two lines. \r then makes the second string print from the start of the 2nd line.

I wanted the second string to print from the beginning of the first string. Is it possible to do it with print or should I use any other functions?

Braiam
  • 1
  • 11
  • 47
  • 78
Sushruth N
  • 191
  • 2
  • 15
  • `\r` can only return you to the start of the line, not go up lines. Imagine the terminal is a typewriter: it's easy to go to the next row, and to the start of the row, but to go up a row you have to twiddle the knob. – Amadan Oct 29 '18 at 09:16
  • @Amadan are you suggesting that it is not possible?. – Sushruth N Oct 29 '18 at 09:20
  • @Amadan passing `end='\r'` to `print` _should_ prevent skipping to the next row. And `print(s1, end='\r'); print(s)` will leave you with only the longer string printed. – Andras Deak -- Слава Україні Oct 29 '18 at 09:21
  • 1
    @AndrasDeak: The row was already skipped by exceeding terminal width, not by outputting `\n` (which, as you said, doesn't happen here). `\r` will return you to the start of the current row. However, the start of the first string is on the previous row, which cannot be that easily returned to. – Amadan Oct 29 '18 at 09:23
  • @Amadan thanks, that wasn't clear from your comment. that explains why it works the other way around (shorter string first). – Andras Deak -- Слава Україні Oct 29 '18 at 09:24
  • 1
    Some terminals can move the cursor up, but this is not per se the case. Since for example you can redirect the output to a file, and a file has no notion of lines – Willem Van Onsem Oct 29 '18 at 09:24
  • @AndrasDeak , Wont the first string not print with scrolling. In that case there will be no problem as the whole first string will be replaced by the second string. – Sushruth N Oct 29 '18 at 09:25
  • Most terminals nowadays will support ANSI sequences: e.g. `print(s1, end="\r\0x1b[2A")` will go up two lines after completing the print (replace `2` with however many lines you want to ascend by). You can use [this](https://stackoverflow.com/questions/566746/how-to-get-linux-console-window-width-in-python) to determine how wide a line is, and calculate how many lines up you need to go from the string length. However, if you pass that into, say, `less`, you'll just get gibberish; and it's definitely not straightforward. – Amadan Oct 29 '18 at 09:28

2 Answers2

1

This is a feature of the terminal emulator you're using. Yes you can use print to do this, you need to output the appropriate terminal escape sequence for your terminal type.

For example, if you're in an xterm like terminal emulator, the escape sequence is described here (that page is for bash, but python had very similar syntax). The escape sequence you'll likely most be interested in is:

  • Save cursor position: \033[s
  • Restore cursor position: \033[u

If you are doing something a lot more complex, you'll likely also be interested in the curses library.

Lie Ryan
  • 62,238
  • 13
  • 100
  • 144
  • It should work on cmd in windows and terminal in linux based installations. Is it possible to generalize? I don't think its possible. I am right? – Sushruth N Oct 29 '18 at 09:40
  • Thanks for the answer. Just one more query. Should I use curses library for the same in Linux? – Sushruth N Oct 29 '18 at 09:46
  • Hm, I can't seem to make it work... not on Mac, not on Centos (both on `xterm-256color`). Don't have Windows at hand to check. – Amadan Oct 29 '18 at 09:50
  • @Amadan: Other sequences you may want to try: `\0337` and `\0337`. – Lie Ryan Oct 29 '18 at 10:21
  • You read my mind - see my answer (`\0337` and `\0338` are exactly what `sc` and `rc` map to on my TERM). – Amadan Oct 29 '18 at 10:22
1

It's tricky. First of all, not all terminals have same capabilities. For example, \033[s and \033[r that Lie Ryan talked about don't work on my terminal. It is safer to read the control sequences from the terminal database:

import os
sc = os.popen('tput sc').read()
rc = os.popen('tput rc').read()
print(sc + s, end='\r')
print(rc + s1, end='\r')

However, this will not work on Windows. Also, it just saves the coordinates of the cursor in view, not in scroll history; so if you save the cursor on the last line, print something that scrolls the screen and restore cursor, you will not move at all (as it will go back to - the last line!)

The workaround I was suggesting in comments before is this:

import os
columns = int(os.popen('tput cols').read())
need_for_up = (len(s) - 1) // columns
cuu = os.popen('tput cuu %s' % need_for_up).read()
print(s, end='\r' + cuu)
print(s1)

Because this doesn't work with coordinates but actually moves cursor up from its position, it works whether at the bottom or not.

Since this also queries the Terminfo database using tput, it won't work on Windows either. Whether or not it would work if you hardcode cuu = "\033[%sA" % need_for_up, I don't know (not a Windows person).

Amadan
  • 191,408
  • 23
  • 240
  • 301