VIM-like-text-editor/test.py

173 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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()