Cut the main loop into smaller functions to have more modularity
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
This commit is contained in:
		@@ -73,102 +73,7 @@ class Squinnondation:
 | 
			
		||||
                squirrel.hazelnuts[(instance.args.client_address, instance.args.client_port)] = hazelnut
 | 
			
		||||
 | 
			
		||||
            Worm(squirrel).start()
 | 
			
		||||
 | 
			
		||||
            while True:
 | 
			
		||||
                squirrel.refresh_history()
 | 
			
		||||
                squirrel.refresh_input()
 | 
			
		||||
                if not instance.no_emoji:
 | 
			
		||||
                    squirrel.refresh_emoji_pad()
 | 
			
		||||
                key = screen.getkey(curses.LINES - 1, 3 + len(squirrel.nickname) + squirrel.input_index)
 | 
			
		||||
                if key == "\x7f":  # backspace
 | 
			
		||||
                    if squirrel.input_index:
 | 
			
		||||
                        squirrel.input_index -= 1
 | 
			
		||||
                        squirrel.input_buffer = squirrel.input_buffer[:squirrel.input_index] \
 | 
			
		||||
                            + squirrel.input_buffer[squirrel.input_index + 1:]
 | 
			
		||||
                    continue
 | 
			
		||||
                elif key == "KEY_LEFT":
 | 
			
		||||
                    squirrel.input_index = max(0, squirrel.input_index - 1)
 | 
			
		||||
                    continue
 | 
			
		||||
                elif key == "KEY_RIGHT":
 | 
			
		||||
                    squirrel.input_index = min(len(squirrel.input_buffer), squirrel.input_index + 1)
 | 
			
		||||
                    continue
 | 
			
		||||
                elif key == "KEY_UP":
 | 
			
		||||
                    squirrel.last_line = min(max(curses.LINES - 3, squirrel.last_line - 1), len(squirrel.history) - 1)
 | 
			
		||||
                    continue
 | 
			
		||||
                elif key == "KEY_DOWN":
 | 
			
		||||
                    squirrel.last_line = min(len(squirrel.history) - 1, squirrel.last_line + 1)
 | 
			
		||||
                    continue
 | 
			
		||||
                elif key == "KEY_PPAGE":
 | 
			
		||||
                    squirrel.last_line = min(max(curses.LINES - 3, squirrel.last_line - (curses.LINES - 3)),
 | 
			
		||||
                                             len(squirrel.history) - 1)
 | 
			
		||||
                    continue
 | 
			
		||||
                elif key == "KEY_NPAGE":
 | 
			
		||||
                    squirrel.last_line = min(len(squirrel.history) - 1, squirrel.last_line + (curses.LINES - 3))
 | 
			
		||||
                    continue
 | 
			
		||||
                elif key == "KEY_HOME":
 | 
			
		||||
                    squirrel.input_index = 0
 | 
			
		||||
                    continue
 | 
			
		||||
                elif key == "KEY_END":
 | 
			
		||||
                    squirrel.input_index = len(squirrel.input_buffer)
 | 
			
		||||
                    continue
 | 
			
		||||
                elif key == "KEY_RESIZE":
 | 
			
		||||
                    continue
 | 
			
		||||
                elif key == "KEY_MOUSE":
 | 
			
		||||
                    try:
 | 
			
		||||
                        _, x, y, _, attr = curses.getmouse()
 | 
			
		||||
                    except curses.error:
 | 
			
		||||
                        # This is not a valid click
 | 
			
		||||
                        continue
 | 
			
		||||
                    if not instance.no_emoji:
 | 
			
		||||
                        if y == curses.LINES - 1 and x >= curses.COLS - 3:
 | 
			
		||||
                            # Click on the emoji
 | 
			
		||||
                            squirrel.emoji_panel_page *= -1
 | 
			
		||||
                        elif squirrel.emoji_panel_page > 0 and y == curses.LINES - 4 and x >= curses.COLS - 5:
 | 
			
		||||
                            squirrel.emoji_panel_page += 1
 | 
			
		||||
                        elif squirrel.emoji_panel_page > 1 and y == curses.LINES - curses.LINES // 2 - 1 \
 | 
			
		||||
                                and x >= curses.COLS - 5:
 | 
			
		||||
                            squirrel.emoji_panel_page -= 1
 | 
			
		||||
                        elif squirrel.emoji_panel_page > 0 and y >= curses.LINES // 2 - 1 and x >= curses.COLS // 2 - 1:
 | 
			
		||||
                            pad_y, pad_x = y - (curses.LINES - curses.LINES // 2) + 1,\
 | 
			
		||||
                                (x - (curses.COLS - curses.COLS // 3)) // 2
 | 
			
		||||
                            height, width = squirrel.emoji_pad.getmaxyx()
 | 
			
		||||
                            height -= 1
 | 
			
		||||
                            width -= 1
 | 
			
		||||
 | 
			
		||||
                            emojis = list(unicode_codes.UNICODE_EMOJI)
 | 
			
		||||
                            emojis = [c for c in emojis if len(c) == 1]
 | 
			
		||||
                            size = (height - 2) * (width - 4) // 2
 | 
			
		||||
                            page = emojis[(squirrel.emoji_panel_page - 1) * size:squirrel.emoji_panel_page * size]
 | 
			
		||||
                            index = pad_y * (width - 4) // 2 + pad_x
 | 
			
		||||
                            char = page[index]
 | 
			
		||||
                            if char:
 | 
			
		||||
                                demojized = emoji.demojize(char)
 | 
			
		||||
                                if char != demojized:
 | 
			
		||||
                                    for c in reversed(demojized):
 | 
			
		||||
                                        curses.ungetch(c)
 | 
			
		||||
                        continue
 | 
			
		||||
                elif len(key) > 1:
 | 
			
		||||
                    squirrel.add_system_message(f"unmanaged key press: {key}")
 | 
			
		||||
                    continue
 | 
			
		||||
                elif key != "\n":
 | 
			
		||||
                    squirrel.input_buffer = squirrel.input_buffer[:squirrel.input_index] + key \
 | 
			
		||||
                        + squirrel.input_buffer[squirrel.input_index:]
 | 
			
		||||
                    squirrel.input_index += 1
 | 
			
		||||
                    continue
 | 
			
		||||
 | 
			
		||||
                msg = squirrel.input_buffer
 | 
			
		||||
                squirrel.input_buffer = ""
 | 
			
		||||
                squirrel.input_index = 0
 | 
			
		||||
 | 
			
		||||
                if not msg:
 | 
			
		||||
                    continue
 | 
			
		||||
 | 
			
		||||
                msg = f"<{squirrel.nickname}> {msg}"
 | 
			
		||||
                squirrel.add_message(msg)
 | 
			
		||||
 | 
			
		||||
                for hazelnut in list(squirrel.hazelnuts.values()):
 | 
			
		||||
                    pkt = Packet.construct(DataTLV.construct(msg))
 | 
			
		||||
                    squirrel.send_packet(hazelnut, pkt)
 | 
			
		||||
            squirrel.wait_for_key()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TLV:
 | 
			
		||||
@@ -238,8 +143,7 @@ class Pad1TLV(TLV):
 | 
			
		||||
 | 
			
		||||
    def handle(self, squirrel: "Squirrel", sender: "Hazelnut") -> None:
 | 
			
		||||
        # TODO Add some easter eggs
 | 
			
		||||
        squirrel.add_system_message(f"For each byte in the packet that I received, you will die today. "
 | 
			
		||||
                                    "And eat cookies.")
 | 
			
		||||
        squirrel.add_system_message("For each byte in the packet that I received, you will die today. And eat cookies.")
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def tlv_length(self) -> int:
 | 
			
		||||
@@ -312,7 +216,7 @@ class HelloTLV(TLV):
 | 
			
		||||
                                    + (":3_hearts:" if self.is_long else "smiling_eyes:"))
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def is_long(self):
 | 
			
		||||
    def is_long(self) -> bool:
 | 
			
		||||
        return self.length == 16
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -608,6 +512,140 @@ class Squirrel(Hazelnut):
 | 
			
		||||
        """
 | 
			
		||||
        return self.socket.recvfrom(1024)
 | 
			
		||||
 | 
			
		||||
    def wait_for_key(self) -> None:
 | 
			
		||||
        """
 | 
			
		||||
        Infinite loop where we are waiting for a key of the user.
 | 
			
		||||
        """
 | 
			
		||||
        while True:
 | 
			
		||||
            self.refresh_history()
 | 
			
		||||
            self.refresh_input()
 | 
			
		||||
            if not self.squinnondation.no_emoji:
 | 
			
		||||
                self.refresh_emoji_pad()
 | 
			
		||||
            key = self.squinnondation.screen.getkey(curses.LINES - 1, 3 + len(self.nickname) + self.input_index)
 | 
			
		||||
 | 
			
		||||
            if key == "KEY_MOUSE":
 | 
			
		||||
                try:
 | 
			
		||||
                    _, x, y, _, attr = curses.getmouse()
 | 
			
		||||
                except curses.error:
 | 
			
		||||
                    # This is not a valid click
 | 
			
		||||
                    pass
 | 
			
		||||
                else:
 | 
			
		||||
                    self.handle_mouse_click(y, x, attr)
 | 
			
		||||
                finally:
 | 
			
		||||
                    continue
 | 
			
		||||
 | 
			
		||||
            self.handle_key_pressed(key)
 | 
			
		||||
 | 
			
		||||
    def handle_key_pressed(self, key: str) -> None:
 | 
			
		||||
        """
 | 
			
		||||
        Process the key press from the user.
 | 
			
		||||
        """
 | 
			
		||||
        if key == "\x7f":  # backspace
 | 
			
		||||
            # delete character at the good position
 | 
			
		||||
            if self.input_index:
 | 
			
		||||
                self.input_index -= 1
 | 
			
		||||
                self.input_buffer = self.input_buffer[:self.input_index] + self.input_buffer[self.input_index + 1:]
 | 
			
		||||
            return
 | 
			
		||||
        elif key == "KEY_LEFT":
 | 
			
		||||
            # Navigate in the message to the left
 | 
			
		||||
            self.input_index = max(0, self.input_index - 1)
 | 
			
		||||
            return
 | 
			
		||||
        elif key == "KEY_RIGHT":
 | 
			
		||||
            # Navigate in the message to the right
 | 
			
		||||
            self.input_index = min(len(self.input_buffer), self.input_index + 1)
 | 
			
		||||
            return
 | 
			
		||||
        elif key == "KEY_UP":
 | 
			
		||||
            # Scroll up in the history
 | 
			
		||||
            self.last_line = min(max(curses.LINES - 3, self.last_line - 1), len(self.history) - 1)
 | 
			
		||||
            return
 | 
			
		||||
        elif key == "KEY_DOWN":
 | 
			
		||||
            # Scroll down in the history
 | 
			
		||||
            self.last_line = min(len(self.history) - 1, self.last_line + 1)
 | 
			
		||||
            return
 | 
			
		||||
        elif key == "KEY_PPAGE":
 | 
			
		||||
            # Page up in the history
 | 
			
		||||
            self.last_line = min(max(curses.LINES - 3, self.last_line - (curses.LINES - 3)), len(self.history) - 1)
 | 
			
		||||
            return
 | 
			
		||||
        elif key == "KEY_NPAGE":
 | 
			
		||||
            # Page down in the history
 | 
			
		||||
            self.last_line = min(len(self.history) - 1, self.last_line + (curses.LINES - 3))
 | 
			
		||||
            return
 | 
			
		||||
        elif key == "KEY_HOME":
 | 
			
		||||
            # Place the cursor at the beginning of the typing word
 | 
			
		||||
            self.input_index = 0
 | 
			
		||||
            return
 | 
			
		||||
        elif key == "KEY_END":
 | 
			
		||||
            # Place the cursor at the end of the typing word
 | 
			
		||||
            self.input_index = len(self.input_buffer)
 | 
			
		||||
            return
 | 
			
		||||
        elif len(key) > 1:
 | 
			
		||||
            # Unmanaged complex key
 | 
			
		||||
            return
 | 
			
		||||
        elif key != "\n":
 | 
			
		||||
            # Insert the pressed key in the current message
 | 
			
		||||
            self.input_buffer = self.input_buffer[:self.input_index] + key + self.input_buffer[self.input_index:]
 | 
			
		||||
            self.input_index += 1
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        # Send message to neighbours
 | 
			
		||||
        msg = self.input_buffer
 | 
			
		||||
        self.input_buffer = ""
 | 
			
		||||
        self.input_index = 0
 | 
			
		||||
 | 
			
		||||
        if not msg:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        msg = f"<{self.nickname}> {msg}"
 | 
			
		||||
        self.add_message(msg)
 | 
			
		||||
 | 
			
		||||
        pkt = Packet.construct(DataTLV.construct(msg))
 | 
			
		||||
        for hazelnut in list(self.hazelnuts.values()):
 | 
			
		||||
            self.send_packet(hazelnut, pkt)
 | 
			
		||||
 | 
			
		||||
    def handle_mouse_click(self, y: int, x: int, attr: int) -> None:
 | 
			
		||||
        """
 | 
			
		||||
        The user clicks on the screen, at coordinates (y, x).
 | 
			
		||||
        According to the position, we can indicate what can be done.
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        if not self.squinnondation.no_emoji:
 | 
			
		||||
            if y == curses.LINES - 1 and x >= curses.COLS - 3:
 | 
			
		||||
                # Click on the emoji, open or close the emoji pad
 | 
			
		||||
                self.emoji_panel_page *= -1
 | 
			
		||||
            elif self.emoji_panel_page > 0 and y == curses.LINES - 4 and x >= curses.COLS - 5:
 | 
			
		||||
                # Open next emoji page
 | 
			
		||||
                self.emoji_panel_page += 1
 | 
			
		||||
            elif self.emoji_panel_page > 1 and y == curses.LINES - curses.LINES // 2 - 1 \
 | 
			
		||||
                    and x >= curses.COLS - 5:
 | 
			
		||||
                # Open previous emoji page
 | 
			
		||||
                self.emoji_panel_page -= 1
 | 
			
		||||
            elif self.emoji_panel_page > 0 and y >= curses.LINES // 2 - 1 and x >= curses.COLS // 2 - 1:
 | 
			
		||||
                pad_y, pad_x = y - (curses.LINES - curses.LINES // 2) + 1, \
 | 
			
		||||
                    (x - (curses.COLS - curses.COLS // 3) + 1) // 2
 | 
			
		||||
                # Click on an emoji on the pad to autocomplete an emoji
 | 
			
		||||
                self.click_on_emoji_pad(pad_y, pad_x)
 | 
			
		||||
 | 
			
		||||
    def click_on_emoji_pad(self, pad_y: int, pad_x: int) -> None:
 | 
			
		||||
        """
 | 
			
		||||
        The emoji pad contains the list of all available emojis.
 | 
			
		||||
        Clicking on a emoji auto-complete the emoji in the input pad.
 | 
			
		||||
        """
 | 
			
		||||
        height, width = self.emoji_pad.getmaxyx()
 | 
			
		||||
        height -= 1
 | 
			
		||||
        width -= 1
 | 
			
		||||
 | 
			
		||||
        emojis = list(unicode_codes.UNICODE_EMOJI)
 | 
			
		||||
        emojis = [c for c in emojis if len(c) == 1]
 | 
			
		||||
        size = (height - 2) * (width - 4) // 2
 | 
			
		||||
        page = emojis[(self.emoji_panel_page - 1) * size:self.emoji_panel_page * size]
 | 
			
		||||
        index = pad_y * (width - 4) // 2 + pad_x
 | 
			
		||||
        char = page[index]
 | 
			
		||||
        if char:
 | 
			
		||||
            demojized = emoji.demojize(char)
 | 
			
		||||
            if char != demojized:
 | 
			
		||||
                for c in reversed(demojized):
 | 
			
		||||
                    curses.ungetch(c)
 | 
			
		||||
 | 
			
		||||
    def add_message(self, msg: str) -> None:
 | 
			
		||||
        """
 | 
			
		||||
        Store a new message into the history.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user