import curses class CursesAdapter: def __init__(self) -> None: self.screen = curses.initscr() self.screen.keypad(True) self.cols = curses.COLS self.lines = curses.LINES # init color system curses.start_color() # green color pair curses.init_pair(1, curses.COLOR_MAGENTA, curses.COLOR_BLACK) curses.curs_set(1) # Make cursor visible def Refresh(self) -> None: """Apply changes""" self.screen.refresh() def Cleanup(self) -> None: curses.endwin() def SetCursor(self, x: int, y: int): """set cursor position (x, y)""" self.screen.move(x, y) def SetChar(self, x: int, y: int, code: int): """set char position (x, y)""" self.screen.addch(x, y, code) def SetString(self, x: int, y: int, data: str): """set string begin position (x, y)""" self.screen.addstr(x, y, data) def GetChar(self) -> int: """Wait users input""" return self.screen.getch() def EditModeBar(self, currentLine, totalLines, fileName): """Print edit mode information panel""" self.screen.addstr(self.lines - 1, 0, ' ' * (self.cols - 1)) # Очистка строки self.screen.addstr(self.lines - 1, 0, "FILE: ") self.screen.addstr(fileName, curses.color_pair(1)) # Имя файла self.screen.addstr(" | MODE:") self.screen.addstr(" EDIT", curses.color_pair(1)) self.screen.addstr(" | LINE: ") self.screen.addstr(str(currentLine + 1), curses.color_pair(1)) self.screen.addstr("/") self.screen.addstr(str(totalLines), curses.color_pair(1)) # Общее количество строк def main(): adapter = CursesAdapter() currentCol = 0 # текущий индекс колонки currentLine = 0 # текущий индекс строки scrollY = 0 # вертикальная прокрутка scrollX = 0 # горизонтальная прокрутка displayBuffer = [] # буфер для хранения всех строк mode = "EDIT" # Загрузка файла для редактирования file_path = "example.txt" # Укажите путь к файлу try: with open(file_path, "r") as file: displayBuffer = [list(line.rstrip('\n')) for line in file.readlines()] except FileNotFoundError: print(f"File {file_path} not found. Starting with empty buffer.") while True: # Очистка экрана adapter.screen.clear() # Отображение видимой части текста for i in range(adapter.lines - 1): if i + scrollY < len(displayBuffer): line = ''.join(displayBuffer[i + scrollY]) if scrollX < len(line): adapter.SetString(i, 0, line[scrollX:scrollX + adapter.cols]) else: adapter.SetString(i, 0, '') else: adapter.SetString(i, 0, '') # Отображение панели режима adapter.EditModeBar(currentLine, len(displayBuffer), file_path) # Установка курсора adapter.SetCursor(currentLine - scrollY, currentCol - scrollX) adapter.Refresh() # Ожидание ввода if mode == "EDIT": symbolCode = adapter.GetChar() if symbolCode == 27: # EXIT break elif symbolCode == curses.KEY_LEFT: if currentCol > 0: currentCol -= 1 elif currentLine > 0: currentLine -= 1 currentCol = len(displayBuffer[currentLine]) elif symbolCode == curses.KEY_RIGHT: if currentCol < len(displayBuffer[currentLine]): currentCol += 1 elif currentLine < len(displayBuffer) - 1: currentLine += 1 currentCol = 0 elif symbolCode == curses.KEY_UP: if currentLine > 0: currentLine -= 1 currentCol = min(currentCol, len(displayBuffer[currentLine])) elif symbolCode == curses.KEY_DOWN: if currentLine < len(displayBuffer) - 1: currentLine += 1 currentCol = min(currentCol, len(displayBuffer[currentLine])) # BACKSPACE elif symbolCode in (127, 8): # Backspace if currentCol > 0: # Если символ существует в текущей строке currentCol -= 1 del displayBuffer[currentLine][currentCol] # Удаляем символ elif currentLine > 0: # Если текущая строка не первая # Объединяем текущую строку с предыдущей prev_line_length = len(displayBuffer[currentLine - 1]) displayBuffer[currentLine - 1].extend(displayBuffer[currentLine]) del displayBuffer[currentLine] currentLine -= 1 currentCol = prev_line_length # Переходим в конец предыдущей строки # ENTER elif symbolCode == 10: # Enter # Разделяем текущую строку на две части new_line = displayBuffer[currentLine][currentCol:] displayBuffer[currentLine] = displayBuffer[currentLine][:currentCol] currentLine += 1 # Переходим на следующую строку displayBuffer.insert(currentLine, new_line) # Вставляем новую строку currentCol = 0 # Сбрасываем индекс колонки # Сохранение файла (Ctrl+S) elif symbolCode == 19: # Ctrl+S try: with open(file_path, "w") as file: for line in displayBuffer: file.write(''.join(line) + '\n') adapter.screen.addstr(adapter.lines - 1, 0, f"File {file_path} saved successfully.") except Exception as e: adapter.screen.addstr(adapter.lines - 1, 0, f"Error saving file: {e}") else: if currentCol <= len(displayBuffer[currentLine]): # проверяем, не превышает ли индекс колонки длину строки displayBuffer[currentLine].insert(currentCol, chr(symbolCode)) currentCol += 1 # Прокрутка экрана if currentLine < scrollY: scrollY = currentLine elif currentLine >= scrollY + adapter.lines - 1: scrollY = currentLine - adapter.lines + 2 if currentCol < scrollX: scrollX = currentCol elif currentCol >= scrollX + adapter.cols: scrollX = currentCol - adapter.cols + 1 adapter.Cleanup() if __name__ == "__main__": main()