Setting non-canonical mode on stdin with Ruby - ruby

I'm playing around with making a simple terminal-based game with Ruby, and I'm currently trying to come up with a way of reading input from the terminal.
So far I've been using gets, but I'd like to have the game react instantly without requiring a newline (so you don't need to press a key, THEN enter).
I've figured out I need to put the terminal in non-canonical mode, and I'm assuming I can do that by calling $stdin.ioctl. The problem is, I'm not sure what arguments or flags I should be passing to this, and the documentation and searches just lead to information about the underlying C function.
Can anyone tell me what I should be calling $stdin.ioctl with? I'm using Terminal.app/tcsh on OSX Leopard.
Edit: This is what I ended up using, thanks to MarkusQ:
%x{stty -icanon -echo}
key = STDIN.read(1)

Your problem is outside of ruby.
Easiest answer: wrap your IO in %x{stty -raw echo} and %x{stty -raw echo} to change the mode with stty.
You'll probably want to do and ensure an exit handler to make certain the mode is set back when you exit.
-- MarkusQ

Related

Golang get command tty output

I'm using go's exec Run command to get command output, which works great when the command 'Stdout' field is set to os.Stdout, and the error is sent to os.Stderr.
I want to display the output and the error output to the console, but I also want my program to see what the output was.
I then made my own Writer type that did just that, wrote both to a buffer and printed to the terminal.
Here's the problem—some applications change their output to something much less readable by humans when it detects it's not writing to a tty. So the output I get changes to something ugly when I do it in the latter way. (cleaner for computers, uglier for humans)
I wanted to know if there was some way within Go to convince whatever command I'm running that I am a tty, despite not being os.Stdout/os.Stderr. I know it's possible to do using the script bash command, but that uses a different flag depending on Darwin/Linux, so I'm trying to avoid that.
Thanks in advance!
The only practical way to solve this is to allocate a pseudo terminal (PTY) and make your external process use it for its output: since PTY is still a terminal, a process checking whether it's connected to a real terminal thinks it is.
You may start with this query.
The github.com/creack/ptyis probably a good starting point.
The next step is to have a package implementing a PTY actually allocate it, and connect "the other end" of a PTY to your custom writer.
(By the way, there's no point in writing a custom "multi writer" as there exist io.MultiWriter).

Ruby open interactive sub process within the shell

I want to use ruby and in one moment open another program (cfdisk) and let the user interact with it, then return to my code
I can use
exec "cfdisk; ruby another.rb"
but that is very hacky and certainly not the right thing to do
I know about Open3 but i dont know how to use it properly for my usecase. I know that when I use capture3 on irb on Windows it says:
["Running under a virtual console, enabling 256/true-color support\n", "Screen size 28640x499 is not supported; limit 500x500.\nCheck the TERM environment variable.\n", #]
In Arch it opens it but the graphical output isnt present, the keystrokes are registered, they work (for example mc exits with F10) but the window isnt there, just blinking cursor.
parted exits immediately
Tried popen3 but I had no luck with it either
What is wrong with system for this case?
The exec ruby command replaces the running process, so it will not return to your code.
The Open3 library is used when you want to capture stdout and stderr.
Isn't this what you are looking for?
puts "here"
system "cfdisk"
puts 'there'
If you have some screen related issues, this is another issue that you might be able to resolve with different TERM value in the environment variable.

Is it possible to create an event driven service in shells

Hi I would like to create a small program that listens for copy comands copied content for later retrival in bash. Is it possible to listen to key strokes while still keeping the shell interactive? And how can this be don arcitectualy. I don't need the whole program just a hint at how it can be done. I have no preferance when it comes to language exept that it should be implemented in a scripting language or maby c++.
Pherhaps this needs to be written like a shell extension or somthing. just a hint would be fine.
Consider the way that the script program works (see man script). I havn't done this in a while, but basically you write your pseudo terminal in C and push that into the stream, then launch the shell.
See tcgetattr/tcsetattr, grantpt, unlockpt, and ptsname, with ptem, ldterm and possibly ttcompat to be pushed using ioctl.
A simpler, though less efficient, is to run script into a pipe and capture the output. You probably will need script -f to flush the buffer (I think the -f is only in the GNU version).

Emacs: some programs only work in ansi-term, some programs only work in shell

Relative Emacs newbie here, just trying to adapt my programming workflow to fit with emacs. So far I've discovered shell-pop and I'm quite enjoying on-demand terminals that pop up when needed for banging out the odd commands.
What I understand so far about Emacs is that shell is a "dumb" terminal that doesn't support any ansi control codes, and that makes it incompatible with things like ncurses that attempt to draw complex UI's on a terminal emulator. This is why you can't use less or top or similar in shell-mode.
However, I seem to be having trouble with ansi-term, it's not the be-all, end-all that it's cracked up to be. Sure, it has no problems running less or git log or even nano, but there are a few things that can't quite seem to display properly when they're running in an ansi-term, such as apt-get and nosetests. I'm not sure quite what the name is for it, but apt-get's output is characterised by live-updating what is displayed on the very last line, and then having unchanging lines of text scroll out above that line. It seems to be halfway between something like less and something dumber, like cat. Somehow ansi-term doesn't like this at all, and I get very garbled output, where it seems to output everything on one line only or just generally lose it's place and output things all over, randomly. In the case of nosetests, it starts off ok, but if any libraries spew out any STDERR, the output all goes to hell in a similar way.
With some fiddling it seems possible to fix this by mashing C-l and RET, but it's not always reliable.
Does anybody know what's going on here? Is there some way to fix ansi-term so that it can display everything properly? Or is there perhaps some other mode that I don't know about that is way better? Ideally I'd like something that "just works" as effortlessly as, eg, Gnome Terminal, which can run all of the above mentioned programs without a single hiccup.
Thanks!
I resolved this issue by commenting out my entire .emacs.el and then uncommenting and restarting emacs for every single line in the file. I discovered that the following line alone was responsible for the issue:
'(fringe-mode 0 nil (fringe))
(this line disables the fringes from inside custom-set-variables).
I guess this is a bug in Emacs, that disabling the fringe causes term-mode to garble it's output really badly whenever any output line exceeds $COLUMN columns.
Anyway, I don't really like the fringes much at all, and it seems I was able to at least disable the left fringe without triggering this issue:
(set-fringe-mode (cons 0 8))
Maybe apt-get does different things based on the $TERM environment variable. What happens if you set TERM=dumb? If that makes things work, then you can experiment with different values until you find one that supports enough features but still works.
Note that git 2.0.1 (June 25th, 2014) now better detects dumb terminal when displaying verbose messages.
That might help Emacs better display some of the messages received from git, but the fringe-mode bug reported above is certainly the main cause.
See commit 38de156 by Michael Naumov (mnaoumov)
sideband.c: do not use ANSI control sequence on non-terminal
Diagnostic messages received on the sideband #2 from the server side are sent to the standard error with ANSI terminal control sequence "\033[K" that erases to the end of line appended at the end of each line.
However, some programs (e.g. GitExtensions for Windows) read and interpret and/or show the message without understanding the terminal control sequences, resulting them to be shown to their end users.
To help these programs, squelch the control sequence when the standard error stream is not being sent to a tty.

Win32 Console -- Backspace to Last Line

I'm writing a command interpreter like BASH, and a \ followed by a newline implies a continuation of the input stream; how can I implement that in Win32?
If I use the console mode with ENABLE_LINE_INPUT, then the user can't press backspace in order to go back to the previous line; Windows prevents him from doing so. But if I don't set ENABLE_LINE_INPUT, then I have to manually reposition the cursor, which is rather tedious given that (1) the user might have redirected the input stream, and that (2) it might be prone to race conditions, and I'd rather have Windows do it if I can.
Any way to have my newline and eat it too?
Edit:
If this would require undocumented CSRSS port requests, then I'm still interested!
Assuming you want this to run in a window, like command prompt does by default, rather than full screen, you could create a GUI application with a large textbox. Users would type into the textbox, and you could parse whatever was entered, and output to the same box (effectively emulated the Win32 Console).
This way whatever rules you want to set for how the console behaves is completely up to you.
I might be mistaken is saying this, but I believe that the Win32 Console from XP onward works exactly like this, and it just listens for output on stdout; there shouldn't be any reason you can't do the same.
Hope this was helpful.

Resources