This time I tried adding a full page on how to do it but the model reached the maximum tokens (thexe include both input and output).

# https://wasimlorgat.com/posts/editor.html

import curses
import sys
import argparse

class Window:
    def __init__(self, n_rows, n_cols, row=0, col=0):asked 
        self.n_rows = n_rows
        self.n_cols = n_cols
        self.row = row
        self.col = col

    @property
    def bottom(self):
        return self.row + self.n_rows - 1

    def up(self, cursor):
        if cursor.row == self.row - 1 and self.row > 0:
            self.row -= 1
            
    def down(self, buffer, cursor):
        if cursor.row == self.bottom + 1 and self.bottom < buffer.bottom:
            self.row += 1

    def translate(self, cursor):
        return cursor.row - self.row, cursor.col - self.col
        
    def horizontal_scroll(self, cursor, left_margin=5, right_margin=2):
        n_pages = cursor.col // (self.n_cols - right_margin)
        self.col = max(n_pages * self.n_cols - right_margin - left_margin, 0)

class Cursor:
    def __init__(self, row=0, col=0, col_hint=None):
        self.row = row
        self._col = col
        self._col_hint = col if col_hint is None else col_hint

    @property
    def col(self):
        return self._col

    @col.setter
    def col(self, col):
        self._col = col
        self._col_hint = col

    def _clamp_col(self, buffer):
        self._col = min(self._col_hint, len(buffer[self.row]))

    def up(self, buffer):
        if self.row > 0:
            self.row -= 1
            self._clamp_col(buffer)

    def down(self, buffer):
        if self.row < len(buffer) - 1:
            self.row += 1
            self._clamp_col(buffer)
            
    def left(self, buffer):
        if self.col > 0:
            self.col -= 1
        elif self.row > 0:
            self.row -= 1
            self.col = len(buffer[self.row])

    def right(self, buffer):
        if self.col < len(buffer[self.row]):
            self.col += 1
        elif self.row < buffer.bottom:
            self.row += 1
            self.col = 0

class Buffer:
    def __init__(self, lines):
        self.lines = lines

    def __len__(self):
        return len(self.lines)

    def __getitem__(self, index):
        return self.lines[index]
        
    @property
    def bottom(self):
        return len(self) - 1

    def insert(self, cursor, string):
        row, col = cursor.row, cursor.col
        current = self.lines.pop(row)
        new = current[:col] + string + current[col:]
        self.lines.insert(row, new)

    def split(self, cursor):
        row, col = cursor.row, cursor.col
        current = self.lines.pop(row)
        self.lines.insert(row, current[:col])
        self.lines.insert(row + 1, current[col:])

    def delete(self, cursor):
        row, col = cursor.row, cursor.col
        if row < len(self.lines):
            if col < len(self.lines[row]):
                # Delete within the line
                self.lines[row] = self.lines[row][:col] + self.lines[row][col+1:]
            else:
                # We're at the end of a line, merge with the next line if possible
                if row + 1 < len(self.lines):
                    self.lines[row] += self.lines.pop(row + 1)

def right(window, buffer, cursor):
    cursor.right(buffer)
    window.down(buffer, cursor)
    window.horizontal_scroll(cursor)
    
def left(window, buffer, cursor):
    cursor.left(buffer)
    window.up(cursor)
    window.horizontal_scroll(cursor)
    
...

Then asked LLMs to add a menu on presssing Escape, make it warp from -1 to size-1 and size to 0. To my surprise it used current_row = (current_row - 1) % len(menu) which works both ways.

# https://wasimlorgat.com/posts/editor.htm
# 4 prompts

...

def show_menu(stdscr):
    curses.curs_set(0)  # Hide the cursor
    # Options for the menu
    menu = ['Return', 'Save', 'Exit']
    choice = -1
    current_row = 0

    def print_menu(stdscr, selected_row_idx):
        stdscr.clear()
        h, w = stdscr.getmaxyx()
        for idx, row in enumerate(menu):
            x = w // 2 - len(row) // 2
            y = h // 2 - len(menu) // 2 + idx
            if idx == selected_row_idx:
                stdscr.attron(curses.color_pair(1))
                stdscr.addstr(y, x, row)
                stdscr.attroff(curses.color_pair(1))
            else:
                stdscr.addstr(y, x, row)
        stdscr.refresh()

    # Initialize colors
    curses.start_color()
    curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)

    # Print the initial menu
    print_menu(stdscr, current_row)

    while True:
        key = stdscr.getch()

        if key == 27: # Escape = Return
            choice = -1
            break
        elif key == curses.KEY_UP:
            current_row = (current_row - 1) % len(menu)  # Wrap around
        elif key == curses.KEY_DOWN:
            current_row = (current_row + 1) % len(menu)  # Wrap around
        elif key == curses.KEY_ENTER or key in [10, 13]:
            choice = current_row
            break

        print_menu(stdscr, current_row)

    # Handle the selected action
    if choice == 0:
        return ""
    elif choice == 1:
        return "save"
    elif choice == 2:
        return "exit"
    else:
        return ""

...

        if k in ("KEY_ESCAPE", '\x1b'):
            action = show_menu(stdscr)

            if action == "save":
                save_file(stdscr, buffer, args.filename)
            elif action == "open":
                stdscr.addstr(2, 0, "File opened!")
            elif action == "exit":
                break

            curses.curs_set(1)
            stdscr.refresh()

...

I used lmsys so tne models kept switching and I also counted the prompts that did not produce usefull answers. And finally, add s border around that menu.

# https://wasimlorgat.com/posts/editor.htm
# 7 prompts

...

def draw_box(stdscr, y1, x1, y2, x2):
    # Draw top and bottom borders
    stdscr.addstr(y1, x1 + 1, "─" * (x2 - 1 - x1 + 1))
    stdscr.addstr(y2, x1 + 1, "─" * (x2 - 1 - x1 + 1))

    #stdscr.box()

    # Draw left and right borders
    for i in range(y1 + 1, y2):
        stdscr.addstr(i, x1, "│")
        stdscr.addstr(i, x2, "│")
        
    stdscr.addstr(y1, x1, "┌")
    stdscr.addstr(y2, x1, "└")
    stdscr.addstr(y1, x2, "┐")
    stdscr.addstr(y2, x2, "┘")

...

    def print_menu(stdscr, selected_row_idx):
        stdscr.clear()
        h, w = stdscr.getmaxyx()

        # Draw a border around the entire window
        draw_box(stdscr, 9, 33, 15, 45)  # Draw a box

...

While I also tried to add Copy and Paste key-bindings these fell short since Ctrl+C emits the Term signal and closes the application.