VIM-like-text-editor/mvc/controllers.py

123 lines
5.0 KiB
Python

import tools
from abc import ABC, abstractmethod
from mvc.views import CursesAdapter
from mvc.models import VimModel, ReturnCode
def CommonInput(HandleInputFunc):
"""common actions for all strategies decorator"""
def wrapper(self, symbolCode: int) -> int:
result = self.HandleCommonInput(symbolCode)
if result != ReturnCode.CONTINUE: # an action common to all strategies occurred
self.model.Scroll()
return result
return_code = HandleInputFunc(self, symbolCode)
self.model.Scroll()
return return_code
return wrapper
class BaseStrategy(ABC):
def __init__(self, model: VimModel, adapter: CursesAdapter, mode: str):
self.model = model
self.adapter = adapter
self.mode = model.mode = mode
def HandleCommonInput(self, symbolCode: int) -> int:
"""common actions for all strategies"""
match symbolCode:
case self.adapter.KEY_ESCAPE: return ReturnCode.SET_BASIC_MODE
case self.adapter.KEY_LEFT: self.model.MoveLeft()
case self.adapter.KEY_RIGHT: self.model.MoveRight()
case self.adapter.KEY_UP: self.model.MoveUp()
case self.adapter.KEY_DOWN: self.model.MoveDown()
case self.adapter.KEY_CTRL_S: self.model.SaveFile()
return ReturnCode.CONTINUE
@abstractmethod
def HandleInput(self, symbolCode: int) -> int:
pass
class Controller:
def __init__(self, strategy: BaseStrategy):
self.strategy = strategy
def SetStrategy(self, strategy: BaseStrategy):
self.strategy = strategy
def HandleInput(self, symbolCode: int):
return self.strategy.HandleInput(symbolCode)
class CommandStrategy(BaseStrategy):
"""command input mode"""
def __init__(self, model: VimModel, adapter: CursesAdapter):
super().__init__(model, adapter, mode="COMMAND")
@CommonInput
def HandleInput(self, symbolCode) -> int:
"""user input processing"""
returnCode = ReturnCode.GOOD
match symbolCode:
case self.adapter.KEY_ENTER:
returnCode = self.model.EnterCommand()
case self.adapter.KEY_BACKSPACE_1 | self.adapter.KEY_BACKSPACE_2:
self.model.BackspaceCommand()
case _:
if not tools.isAscii(symbolCode): return ReturnCode.GOOD
self.model.InsertCommandSymbol(symbolCode)
return returnCode
class EditStrategy(BaseStrategy):
"""edit mode"""
def __init__(self, model: VimModel, adapter: CursesAdapter):
super().__init__(model, adapter, mode="EDIT")
@CommonInput
def HandleInput(self, symbolCode) -> int:
"""user input processing"""
match symbolCode:
case self.adapter.KEY_ENTER: self.model.Enter()
case self.adapter.KEY_BACKSPACE_1 | self.adapter.KEY_BACKSPACE_2:
self.model.Backspace()
case _:
if not tools.isAscii(symbolCode): return ReturnCode.GOOD
if not self.model.inputAfterCursor:
self.model.InsertSymbol(symbolCode)
else:
self.model.InsertSymbolAfterCursor(symbolCode)
return ReturnCode.GOOD
class NormalStrategy(BaseStrategy):
"""navigation mode"""
def __init__(self, model: VimModel, adapter: CursesAdapter):
super().__init__(model, adapter, mode="NORMAL")
@CommonInput
def HandleInput(self, symbolCode) -> int:
"""user input processing"""
self.model.UpdateKeyLog(symbolCode)
match symbolCode:
case self.adapter.KEY_TWO_DOTS: return ReturnCode.SET_COMMAND_MODE
case self.adapter.KEY_NULL | self.adapter.KEY_XOR: self.model.ToLineStart()
case self.adapter.KEY_DOLLAR: self.model.ToLineEnd()
case self.adapter.KEY_p: self.model.Paste()
case self.adapter.KEY_w:
if self.model.CombinationCheck("diw", 3): self.model.DeleteWord()
elif self.model.CombinationCheck("yw", 3): self.model.CopyWord()
else: self.model.ToWordEnd()
case self.adapter.KEY_b: self.model.ToWordStart()
case self.adapter.KEY_d:
if self.model.CombinationCheck("dd", 3): self.model.CutLine()
case self.adapter.KEY_y:
if self.model.CombinationCheck("yy", 3): self.model.CopyLine()
case self.adapter.KEY_x: self.model.DeleteNext()
case self.adapter.KEY_U: self.model.RecoverLine()
case self.adapter.KEY_G:
num, ind = tools.ExtracrtNumBeforeLastKey(''.join([chr(item[0]) for item in self.model.keyLog]))
if num != None and ind != None: self.model.MoveToLine(num)
else: self.model.ToFileEnd()
case self.adapter.KEY_g:
if self.model.CombinationCheck("gg", 3): self.model.ToFileStart()
case self.adapter.KEY_PG_UP: self.model.PageUp()
case self.adapter.KEY_PG_DOWN: self.model.PageDown()
return ReturnCode.GOOD