Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Escape sequence for deleting next/trailing character?

Tags:

ruby

escaping

Is it possible, in addition to deleting a leading character using \x08, to also delete a trailing character? Is there an escape sequence that will delete the next character instead of the previous one?

I see that delete is apparently mapped to ASCII 127, which is Hex 7F, but the following code:

puts "a\x08b\x7fcd"

produces

b⌂cd

I expected that \x7f would delete the 'c' character following it, but it does not.

like image 591
mydoghasworms Avatar asked Dec 10 '12 08:12

mydoghasworms


People also ask

What is the meaning of '\ n escape sequence?

For example, \n is an escape sequence that denotes a newline character.

What is use of \0 escape sequence?

\0 just places the character with code 0 there, but it happens anyway. The good use of this is where array bounds are not given, as the extra 0 will count in, or where you have more characters after the 0.


3 Answers

You aren't actually deleting anything with \x08 , you are merely overwriting the "a" with a "b".

Imagine the very old days when you used a teletype paper terminal. What you would actually see on the paper is an "a" printed, the teletype would back up one space and then print a "b" over it. All the non-printing ascii codes were invented to control the movement of teletype paper terminals.

That's exactly what the output above does, only the terminal screen does not keep the pixels lit for the previous "a".

The "del" char does not have this special meaning to the basic terminal screen. It might mean something to a program such as an editor or a shell, but to STDOUT it's just another ascii char to print.

The original meaning of "del" is ignore this char as input, see :

http://en.wikipedia.org/wiki/Delete_character

There is nothing I know of that you can put before a char that STDOUT will treat as a signal not to print the next CHAR. However if your output is to a terminal emulation program such as xterm, you can do many things using escape codes to accomplish what you want. See for example:

http://ascii-table.com/ansi-escape-sequences-vt-100.php

The "standard" library for abstracting out all these complex codes is ncurses, of which there are a couple ruby interfaces. see

Best gem for working with ncurses and ruby

like image 89
Fred the Magic Wonder Dog Avatar answered Oct 30 '22 19:10

Fred the Magic Wonder Dog


The backspace character (charcode ?\x08, its alias ?\b and its frequent ?\C-H (Ctrl+H) mapping) is not the same as the delete character (charcode ?\x7f, meaning ascii 127). Out of the box, the difference between the two is that backspace moves the cursor position left before deleting.

Note that in both cases on unix platforms, deleting usually stands for the kill escape sequence, and that the latter stands for killing the line from the cursor right (i.e. like the Ctrl+K mapping in Terminal). Put another way, ?\b is equivalent to "\e[D\e[K" (left, kill) and ?\x7f is equivalent to "\e[K" (kill). Sample output in IRB (Ruby 2.0.0, OSX) to illustrate this:

>> print "abc\b"            # abc, backspace
ab=> nil
>> print "abc\e[D\b"        # abc, left, backspace
a=> nil
>> print "abc\x7f"          # abc, delete
abc=> nil
>> print "abc\e[D\x7f"      # abc, left, delete
ab=> nil
>> print "abc\e[D\e[D\x7f"  # abc, left, left, delete
a=> nil
>> print "abc\e[D\e[D\e[K"  # abc, left, left, kill
a=> nil

The operating word in the above is usually. If you play with getch in a terminal, the behavior will be quite different from that of IRB. (If memory serves, the delete key will then move the character left without killing the line, or something to that order.)

Getting back to your question with this clarified: to the best of my knowledge, there is no escape sequence to kill a single character at the cursor's position; only sequences to kill a line to the left, right, or both of the cursor. The reference posted by Fred is quite good in case you want to dive in:

http://ascii-table.com/ansi-escape-sequences-vt-100.php

At any rate, I'm guessing that you're playing with getch or something to that order. What you'd want to do, in order to delete a single character, is to maintain a buffer and the cursor's position at the same time as you're printing characters to stdout. This will allow you to map ?\b or ?\x7f as you see fit, using something like:

def refresh
  rest = @buffer[@position..-1]
  @stdout.print "\e[K"
  @stdout.print rest, "\e[#{rest.length}D" if rest && !rest.empty?
  nil
end

Alternatively, try the usual suspects to spare yourself the headaches: readline, ncurses, the highline gem, etc.

like image 25
Denis de Bernardy Avatar answered Oct 30 '22 20:10

Denis de Bernardy


The main problem here is: standard IO has no short-term memory. That says there is no magic operating entity to act on forthcoming symbols. The following code snippet shows that “delete,” even supplied with a modern way, has no clue about symbols from the future:

> puts "a#{`tput dch1`}b"
# ⇒ ab

Whether you really need to “delete prospective symbol,” I would suggest you to use plain ruby monkeypatch for that:

class String
  DEL = '␡'
  def postprocess
    self.gsub /#{DEL}./, ''
  end
end

puts "a␡bc".postprocess
# ⇒ ac

Actually, this is not an answer directly to your question, but it might give a suggestion.

like image 45
Aleksei Matiushkin Avatar answered Oct 30 '22 21:10

Aleksei Matiushkin