Closed ccoupe closed 7 years ago
Nice idea ! PTY,spawn works for me (in your example) in linux, though... well, i don't have a good understanding of all this term/tty/pty thing Don't we need a IO.pipe like in the official doc of PTY to interact with gnome_terminal ?
otherwise, i can send a 'ls' command, for example, that way and get back the result in a para
PTY.spawn('ls') do |output, input, pid|
input.write "hi\n"
output.each { |line| @ret.text = @ret.text + line }
end
There is also this, don't know if it's useful, (for the present case , i mean) http://ruby-doc.org/stdlib-2.0.0/libdoc/io/console/rdoc/IO.html
Shell library too
I had many attempts using such techniques on Windows to integrate the real IRB in Shoes but without success.
I've done something maybe similar, connecting Shoes, IRB and some Gimp input/output : https://github.com/passenger94/Gimp-Ruby/blob/master/lib/plug-ins/irbconsole.rb https://github.com/passenger94/Gimp-Ruby/blob/master/lib/plug-ins/shoes_console.rb. Works nice on my system
A bit long winded.
Actually, the Windows code for the new console is pretty nice as is - one could re write the Shoes.irb to use it (but read on before doing that)
Remember that the console works by replacing the low level file_descriptors for stdin/stdout/stderr so they point one side of pty (think one side some pipes) and the other side of the pty(pipes) is a terminal emulator. For nix/osx, that is a poorly written emulator in the same process. Clever but still a hack.
Updated sample:
Shoes.app do
stack do
para "Demonstrate Pty.spawn with new Terminal"
button "Try It" do
if RUBY_PLATFORM =~ /darwin/
puts 'darwin'
`/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal`
else
require 'pty.so'
puts "linux stdin = #{$stdin.fileno} stdout = #{$stdout.fileno}"
rd, wr, pid = PTY.spawn("gnome-terminal")
wr.puts "new #{pid} pty?"
end
end
end
end
Sadly, gnome-terminal has some problems used this way. It runs a shell (and .bashrc.) and changes it's stdin/out/err to that shell process so it's no longer talking to our pty. OSX would have the same problem (probably) What would be better for the nix's is when shoes.show_console is called that the code does a fork() and the new (subprocess) runs a terminal emulator. (which is pretty close to the code above, if gnome-terminal worked here) There's also an issue that gnome-terminal is not in all Linux installs.
conceptually in C,
long pty[3] = create_pty();
char *[] command_line(args)
if (pid = fork()) {
// in child subprocess
start_terminal(pty[0], pty[1], pty[2], command_line) // something we wrote or the user already has
// never returns
}
For now that's the tesi based 'thing' but now it's running in a different process and doesn't have to call back to Shoes/ruby to display things. It couldn't because its a different process We'd have to manage the subprocess pid at quit time.
There are several use case to consider: (1) test-unit/rspec, (2) byebug/remote, (3) other gems that think they have a terminal on stdin/out/err, (4) Shoes/irb
1 and 3 are satisfied by this proposal. (2) Byebug/remote is too complicated. Let's create a 'shoesbug' method (which starts the byebug remote in the Shoes process and then creates the console with the byebug command to connect to the (parent process). Details left undiscovered and they are important. We do have Shoes & ruby in the console subprocess so we can execute the ruby code to make the server connection. Irb(4) use case: Unless it has some sort of server mode, we can't poke inside the parent process BUT the existing implementation could just read/write stdin/stdout (if irb uses readline) after creating a console. No need to manage keystrokes in Shoes or call Shoes to display things. Again, details matter. Also, we don't have to do anything for Irb.
There are many terminal emulators in the OSS world we so can get better code than tesi. (search terminal in syntapic) For linux , we also have gtk's vte. On OSX, there are not as many OSS emulators (lots of binary only shareware) and they seem designed to replace Apples terminal which is a lot more code than we need. There are other OSS state machines for handling the vt102/vt220 escapes instead of tesi and we do have OSX code to create a window, set the font, draw characters arriving from the pty and send key strokes to it. Don't have the color stuff or bold or ...
That said, the difference between what we have now and this proposal is a lot of C/Obj-C code. The difference between that start_terminal and a full app with menus .... is
main(argc,argv) {
start_terminal(stdin, stdout, stderr, "/bin/sh")
}
Not much different except we don't need to create or handle lots of menus or font selection, and we control what the command line args are.
I'm leaning towards using https://github.com/kika/libtsm because it could/should work with OSX as well as Linux and it has a gtk example we can start from. It's not documented in a way most of us would like -- aka misleading and confusing - pty/tty is already a deep dive for the young folk ;^). It's much better than the tesi crap.
Clone it and cd in
./autoconf.sh
./configure --enable-gtktsm
make
The Kids Are Alright !! :stuck_out_tongue:
indeed more complete library !
Actually the way to build libtsm is
./autoconf.sh
./configure
./make
./make install
./make gtktsm
gtktsm is a properly written program. Much can be learned. I suspect 90% can be copied for Shoes purposes. libtsm (in /usr/local here) or /usr if installed from apt-get) is a new dependency and a new lib to copy into Tight Shoes. Getting gtktsm/libtsm working in OSX will be the larger challenge. I've created a remote branch 'tsm_con' since it's going to change things a lot and we don't know if it's worth it.
Now for the problems. There are many. Deal Breakers? The gtktsm sample was not written to handle pty the way we need. I knew that from the beginning but it runs deep in the sample. Secondly, on OSX, the rules for fork() are pretty strict - its needs to be followed by an exec..(path_to_executable) before the child does anything to confuse cocoa. This is true of Gtk apps as well. We need a real executable - not some functions in the duped code. This is a big issue for OSX (new app and build and all the rake files). It also turns out that the gtktsm sample doesn't handle scrolling (and the backing buffer may not be handled). That's a lot of work just to discover it might not work well in a separate process for all the use cases.
Perhaps the current design isn't all that bad, just incomplete (can't handle multi char escapes for setting colors...) There is a lot to like about using NSTextView and GtkTextView if we could handle insert/delete char/line/range which is suspiciously like issue #144 requirements only called from the terminal state machine(tesi or libtsm) -> shoes_nativetextedit set_font_color(). That would be a lot of methods to add to text_edit but that's the point, text_edit is not edit_box and new methods are desired. And, it wouldn't change the windows implementation of show_console since Windows will never call the pty state machine - no ptys on Windows. (and that's OK in this scheme).
The tesi/llibtsm/vt102/xterm escape sequences can help define what the Shoes native methods need to be for the text_edit widget. Tonight, there's a lot to like about this approach.
too much problems ?
What the shoes console code does is backwards to what gtktsm and tesi was writtten for - their assumption is they a collecting key strokes and pass that to /bin/sh is a subprocess. and output from the subprocess is routed to gtk display methods. What Shoes wants is different.
Tesi is not impossible to use or to understand. It does needs as serious clean up and better comments plus function names that fit the purpose (libtsm has that problem too when used in the Shoes way).
Parsing all and responding to all escape sequences in the xterm-256 definition would be very difficult and useless since most will never be used. I short circuited tesi handling at tesi.c:54 and duped some processing into haveChar in gtk-terminal/cocoa-terminal. That hack needs to be undone. Use the 'tesi', Luke!
i've made some basic escape sequence parsing for a ri based Ruby doc Shoes app https://github.com/passenger94/Dance_floor/blob/master/ruby_doc.rb#L87
A Jedi craves not these things !
This is even harder than I thought. Tesi had bugs and never could parse xterm-color escapes in a useful manner. On OSX, with it's missing stdout, pty related things are going to be much different. Tesi may not be used for OSX - too soon to say.
gtk-terminal.c (only used on Linux) may switch to using Gtk vte instead of gtk_text_view (because VTE does all the missing stuff and seems to be part of every Linux except Raspbian which is a low value target when downloads are counted and they are used to do sudo apt-get install libvte-2.90
One last thing. I'm going to call it Shoes Terminal, visually, verbally and in the code to avoid confusion with Shoes Console in log.rb
Gtk terminal has an icon, just like osx! Windows can't play that game. Bonus points to use the packaged app name instead of "Shoes". Here's samples/expert-console.rb
There is a lot to like with VTE - except it's a moving target. The api changes and Shoes has no idea if the destination has the API Shoe was compiled against and the internet doc is pathetic. The /usr/share/gtk-doc is better but version specific. I'll commit the gtk-terminal.c code for VTE (version 0.34 api)- who knows what your libvte-2.90 implements. Maybe someone else wants to deal with it.
vte 2.90.34
but no luck with tests in colorized output (like tests for vlc, here testing Shoes::Color)
There are some important things missing in the VTE version. (like scrolling and keyboard input). VTE is the core of gnome-terminal so it parses all the escape sequences of an xterm and responds as an xterm. That also means every Linux out there has a slightly different version of 2.90 with slightly different incompatible .so
is it a lost cause then ? looks better ...
We would have to include libvte.so with Shoes (might work) and doesn't screw up gtk3 on the running system. Odds are high the x86 linux build machine has an older vte than either of us and much older than the guy running 15.10 and the color picker.
Font's and colors can be set in the older terminal and I believe we can support attributes like color, bold, an so on. Just a matter of predefining text tags for them and then creative use of iterators to mark the start and end. Then apply the tag to the text buffer. And then something similar but different on osx.
Here's the Gtk_TextView version of the console:
There's much to be done but if we're clever I think we can work in all the attributes and quite likely the very odd scroll regions and xterm cursor movement (aka ncurses)
The gtk_text_view terminal continues to improve.
As noted in the commit, there is a tesi bug dealing with ;
in combined sequences (set bold and red for example) and they don't span properly - like underline, green,text,red, text,end_underline. That will take a more clever data structure - I'm not sure its worth the effort.
:high_heel: :high_heel: :high_heel: Yes, sir ! (with some intended failure)
After much thinking and tinkering, It's hard to do xterm cursor movement in gkt_text_view. Not impossible, just difficult (and probably not very useful when working). Lines in gtk_text_buffers are variable length, null terminated. Asking for a character position past the end of a line segfaults (or returns the last character at best) -- not a lot of flexibility for moving the insertion point on the X axis. Worst of all there's no way to detect that you aren't really pointing to where you asked.
One path I started down was to convert the first 24/25 lines to have 80 characters each when involved in a cursor based escape sequence but that's difficult too, However, we could have two gtk_text_buffers and switch them in the gtk_text_view, the log_buffer that @passenger94 shows as working above this comment, and a 'legacy_buffer' which is just 24|25 lines of 80 spaces to be moved to and replaced. Since there can be only one Shoes Terminal because there's only one stdin/stdout/stderr device, these buffers can be global vars (they are just C pointers) and gtk_text_view * could be stored a global too since it will never change. The terminal would start in log mode by default and attempts to move the cursor with with escape sequences (and clear screen, erase line. etc) would be ignored.
We should have a way for the Shoes scriptwriter to select which mode to start in. Might as well also specifying the terminal size (row, columns), background and foreground colors - because some people like black backgrounds and the window title (like we for dialogs). The redundant 'Shoes Terminal' in the 'menu panel' could be replaced with 'legacy_mode' checkbox that could switch the buffers and mode setting. If Windows can't do all those changes (it probably can't), so be it. If OSX can't all of if, thats OK too. Please advise.
From your comments i understand that gtk_text_view don't play well with escape sequence related to cursor movement (they require a well defined buffer?), so looks like a good plan to separate both ...
Looks like gtk_text_view is doing his royal picky huge kludge Princess, separation of concern is a mantra in development area, i've been told !
Shoes.app do
stack do
para "Terminal test"
button "do it" do
#Shoes.show_console
Shoes.terminal columns: 64, rows: 12, fontsize: 9, title: "Bug236",
fg: "yellow", bg: "black"
#if RUBY_PLATFORM =~ /darwin/
# $stderr.puts "Filenums #{STDOUT.fileno} #{STDERR.fileno}"
# $stdout = $stderr
#end
$stderr.puts "STDERR OK"
$stdout.puts "STDOUT OK"
puts "Way to go!"
puts "\033[32mGood in green?\033[00m or is \033\[35mthis better\033\[00m"
puts "\033[31m\033[40mRed on Black\033[0m OK? \033[01mBold?\033[0m"
puts "And \033[04;33;46mUnderline joy?\033\[0m"
end
end
end
Produces
:high_heel: :high_heel: :high_heel: :high_heel: :high_heel: :high_heel: Nice
Windows is totally oblivious to all of the Linux fun
haha
we now have Shoes.terminal in lieu of Shoes.console, right ?
We have both Shoes.show_console
(old) and Shoes.terminal {hash}
(new). Either one works, only one has {args}. Command line -w calls Shoes.show_console for backwards compatibility.
Edit: I should also mention that Windows won't need a game/log mode since it kind of does the right thing if you send the "correct" escape sequences which may not be xterm. Can't fix that. Windows will also display stderr before buffered stdout. Can't fix that either.
Tried with videovlc tests and it launches a bunch of terminal now ? Single test are ok, seems something allows to have several terminal windows.
app.c:628 is the controlling variable and the code is just below that. Is it multiple consoles? I can see a potential for that. If it's multiple terminals then I'm missing something.
app.c lines 640 & 641 shoukd look like this
shoes_native_terminal(dir_path, 1, 80, 24, 10, "black", "white", "Shoes Terminal");
shoes_global_terminal = 1;
not in sync with those line numbers (though i just pull from terminal) and don't match ! i'm going to retry a pull/fetch yes terminal i mean (from Shoes.show_console, haha, confusing now !)
shoes_native_terminal(dir_path, 1, 80, 24, 10, "black", "white", "Shoes Terminal"); shoes_global_terminal = 1;
no i have the same thing than in terminal branch here at github https://github.com/Shoes3/shoes3/blob/terminal/shoes/app.c#L640 and https://github.com/Shoes3/shoes3/blob/terminal/shoes/app.c#L678
and git says i'm in synch ... difference in line numbers is simply because there isn't the app_finished commit incorporated (so this is expected)
it's fine with Shoes.terminal though (not Shoes.show_terminal, didn't pay attention at first try)
those are the lines to insert in your copy. shoes_native_terminal is void() so you have to set the shoes_global_terminal to 1. Mine is fixed but not committed yet.
ok, fixed ! :-)
I'm working on the 'game' mode for the terminal (cursor placement) and as you should expect from me, I may have gone down the wrong rabbit hole and missed some warning signs like there is one more line in the gtk_text_buffer than you create. The newline at the end is part of the line width, I could have set 'overwrite' mode and I should use text_view instead of text_buffer for some things, but not others. It's a good learning experience and doesn't affect the log mode which does continue to work.
Gaining ground (gtk linux)
Shoes.app do
stack do
para "Game Mode Terminal test"
button "do it" do
columns = 80
rows = 24
Shoes.terminal columns: columns, rows: rows, fontsize: 12, title: "Test Cursor Movements",
mode: 'game'
ruler1 = ''
ruler2 = ''
(1..columns).each do |i|
tens = i/10
ones = i%10
ruler1 << (tens == 0 ? ' ' : tens.to_s)
ruler2 << ones.to_s
end
puts ruler1
puts ruler2
(3..rows+2).each {|row| puts row }
(3..rows).each { |ln| $stdout.write "\033[#{ln};1H#{ln}"; $stdout.flush }
$stdout.write "\033[10;10H10,10\033[20;20H20,20"
$stdout.flush
$stdout.write "\033[24;79HEND\033[1;1H"
$stdout.flush
end
end
end
You might notice that line numbers 3..2x are drawn twice in two different ways. Part of the test. Last one wins, because that's how old school terminals work.
Getting closer.
Now that I almost know what I'm doing on OSX, setting colors from escape sequences should be relatively easy except I should never have used two classes in Cocoa when one would do and I need to change code names from console to terminal.
There is still much to do.
Clear eyes will notice there is no bold. On OSX thats a font change thing and not so easily done, yet. Keydown doesn't work and there are mamy strange problems with Tests/test_video_vlc.rb only works in certain situations and without color and have #224 issues.
Warning! I'm likely to merge the terminal branch into master soon. OSX may still have some issues but the branch is much better than what's in master.
If any one is bored and would like to write some ruby, we need an sample/expert-console.rb that uses some of the things found here
Just when I was almost done with this issue, I got to thinking about Windows (and it's too ugly for Shoes) console. Windows has pipes, and handles and even explicit calls to set/redirect stdin/stdout/stderr. We already have the xterm behavior in tesi/gtk-terminal. We just need to periodically move bytes from stdout pipe to gtk-terminal in a similar way to the osx implementation (probably much easier to do in Windows, BTW just add a gtk idle routine?. Like linux and choes on osx, choes.exe has a launch terminal which works fine (except for xterm escapes). A call to Shoes.terminal would bring up a Shoes window instead of (another) DOS console. Cross platform.
The win-terminal branch may have hit a dead end. Without a tty/pty, readline just won't work. if you look at the code for the pure ruby readline (rb-readline gem) you'll see that it too depends on external things (infocmp command, and tty calls) that would be damn near impossible to implement in Shoes. Particularly on Windows.
The good new is that it should be possible to use the g_io_channel structure to monitor the pty fds for stdout/stderr which is noticeably faster on Linux compared to the timer method.
Closed in Shoes 3.3.2
The new console in Shoes 3.2 is kind of miserable - particularly on OSX but the tesi/gtk is not a shining example of perfection either. Windows is OK. The nix's use a pty that talks to a secondary event poll in Shoes. What if we could create a subprocess that runs a terminal and communicates over a PTY. Turns out there is a Ruby sdtlib for this.
That doesn't wire up stdout<->stdin between processes but the API and we don't really want bash in the subprocess but lets wave our hands and pretend that is something we can control (probably)
Shoes goes odd if you require 'pty'
Yet if you use the Shoes irb (alt-=) you can type the same IRB commands above without error.
OSX is more like Windows. If you start a terminal from an app and you have a terminal on screen it uses that one. If you have no terminals open then it does create a new one (with a error message on it) I don't understand why you can't `PTY,spawn(...) in a Shoes script. Some sort of scope/method missing magic?