VIM-like-text-editor/test.py

173 lines
7.1 KiB
Python
Raw Normal View History

2025-02-04 13:06:54 +03:00
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()