Release 0.2d: An ongoing (but final) issue

Hacktoberfest 2019 is ending in 28 hours and 24 minutes as I am writing this and I am so happy to complete the challenge with 1 PR beyond expectation!


I will have my shirt soon!

This Week's Issue

I have done my final PR. Instead of solving an issue in a large project as I planned last week, I decided to put my effort into an ongoing issue in a project that I found on Day 1 of Hacktoberfest, the tmessage project.

The issue is essentially a UI problem in displaying incoming messages from other users when the current user is typing a new one. Specifically, when a user is typing a message but did not send it while there is an incoming message, the new message is displayed on the same line, right after the message being typed.

The reason I want to take on this issue is that I have seen the issue sitting there for quite a while and no one seems to be working on it. I feel comfortable with the project since I worked on it before (releasee 0.2b) and want to contribute more to it. Besides that, I also want to dig into a problem that I have no clear idea of where to start in the first place which is a higher level for me.

The issue is a known problem in multi-threaded programs when the output is being displayed in 2 different threads. The usual solution is that you only allow 1 thread to handle output to the screen which is not technically possible here.

After doing some Google research, I went over an article about Cursor Movement in the terminal. It gives me an idea that I can use it to move the cursor to the beginning of the current input line and print the new message there. The problem now is that doing that will erase the message being typed from the screen which is still in the keyboard buffer. I must find a way to reprint those characters to a new line below the new incoming message, or in other words, to print the keyboard buffer to the screen.

I believe that there are tools out there that can help me with this but I did not manage to find one that suits my purpose. So, I went ahead and built my own input buffer.
""" Handle input/keystroke for outgoing message """
from readchar import readkey, key


class Input:
    """ Custom Input class buffering every typed characters """
    buffer = ""

    def get_buffer(self):
        """ Get buffered content as a string """
        return str(self.buffer)

    def get_input(self):
        """ Retrieve input from user with every keystroke buffered """
        while True:
            keypress = readkey()
            if keypress == key.CTRL_C:
                raise KeyboardInterrupt('Ctrl + C combination detected')
            if keypress in (key.ENTER, key.CR):
                print('\n\r', end='')
                break
            if keypress in (key.UP, key.DOWN, key.LEFT, key.RIGHT):
                continue
            if keypress in (key.BACKSPACE, "\b", "\x08", "KEY_BACKSPACE"):
                self.buffer = self.buffer[:-1]
            else:
                self.buffer = self.buffer + keypress
            print("\r\033[K" + self.buffer, end='', flush=True)
        result = str(self.buffer)
        self.buffer = ""
        return result
My Input class mimics relatively the same functionality as the input() function of Python with one extra method allowing users to retrieve the current state of the buffer.

With that in mind, I changed the client code to use my Input object to get input from users and to print the buffer on a new line every time a new message is received.

And the result after the change is more than satisfactory.

The Story about the Pull Request

I was excited that I fixed an ongoing issue for the project so I immediately made my Pull Request. Guess what? I  wasn't done! There were reviewers immediately reported that my solution just... did not work at all.

I was surprised and shocked initially since, apparently according to the gif above, the problem seems to exist no more. I dived into diagnosing it intensively for days before I realized that their executable was of an older version of the code based on their screenshots I asked for as feedback. So... they simply had to rebuild the code, right? Wrong!

As they did that, they reported that I kind of only... fixed half of the problem.

At this point, I realize that the problem is a platform-dependent issue as I can see that the 2 reviewers of my issue are using either Ubuntu or macOS while I am on Windows. I suspect the bug is at the difference between the "newline character" notations of Windows and Linux-liked systems so I made some changes to make sure the solution is cross-platform. This includes the handling of newline characters (\n) and carriage-return characters (\r). A noticeable change would be:
if keypress in (key.ENTER, key.CR):
        print('\n\r', end='')
        break
However, I have no mean to test the changes I made since I do not have access to a Linux-liked system. I thought this is the end until I thought of setting up a virtual machine on my Windows laptop. It takes me a few more days to set up an Ubuntu system and configure it to work as a developing environment.

As I managed to reproduce the bug on the Ubuntu virtual system, I also managed to fix it.

The issue now is still under review... but I hope it is a success!

Comments

Popular posts from this blog

Release 0.1b: Contributing a new feature... Why not?

Release 0.1a: My First Contribution

Release 0.2b: #js-vs-py - Fianlly learning Python!