0

I have a program that is a client, talking to a server with socket.

When the user is inputting a message, if another message comes in, it breaks up the text visually, making it hard to understand for the user.

the scenario can be thought up like this

c=0
p=Thread.new do
    loop {
        # this is the messages coming in
        c+=1
        puts c
        sleep 1
    }
end
g=Thread.new do
    loop {
      #this is the user input
      puts $stdin.gets  
    }
end
p.join
g.join

in the case of some really slow typers, the output looked similar to this

1
h2
el3
l4
o5

hello

6

Is there any way to remove and replace the text when putting a string into the console?

edit

So, now if i can get each character separate, i can add it to a string, and in the thread p when it puts, it will put "\r" + c and then print the string.

this would allow the user to still see what they are typing, as well as not interrupting the p thread.

I dont know how to get each character individually.

this also brings up the problem of "how would backspace work?" and "would i need a switch statement for special characters like return and ctrl+c?"

2 Answers2

0

Your program is multithreaded, and both of your threads are fighting over the same resource: the terminal! The classic way to handle this is to protect the shared resource with a mutex.

The idea is simple: whenever a thread interacts with the shared resource (the terminal) synchronize that access with the shared mutex. That way they don't stomp on each other.

But your situation is tricky, it's easy to see when thread p wants to use the terminal, but it's not easy in thread g because that's just the user typing. What you probably would have to do is use IO#read_nonblock in a tight loop to get the user's input character-by-character. You could then use that to detect when the user pauses their input and take that moment to unlock the mutex, allowing the other thread to dump its output.

Note that this will also make thread p more complicated because it needs to be able to buffer its output while it's waiting for the terminal to become available.

Max
  • 21,123
  • 5
  • 49
  • 71
  • I see how this can be very useful, and for what its worth, it is a really good answer. My issue is that i dont want to have to halt the `p` thread if i dont have to. Imagine having to stop typing to recieve a message in a chat app. If it is the only way, i will make it work. the other thing to keep in mind is that in the actual app, the output from thread `p` isnt going to be consistant, as the output is reliant to the Socket connection – LonelyLittleLucas Oct 03 '19 at 15:52
0

If you are trying to implement a chat app in terminal, the "appropriate" tool is curses. A curses library essentially lets you write a GUI in the terminal. It lets you define separate regions of the screen that you can update separately and also lets you read input without echoing it to the terminal.

Max
  • 21,123
  • 5
  • 49
  • 71
  • I find Curses fairly confusing, can you link me to a tutorial, the documentation isnt enough to teach me how to use it – LonelyLittleLucas Oct 03 '19 at 16:32
  • @LonelyLittleLucas last I used it the curses library was a really thin wrapper around the ncurses C library. Any ncurses tutorial (or just the ncurses man page) should bring you up to speed. – Max Oct 03 '19 at 16:38