chistedit: move view state from a dict to a custom class
authorMartin von Zweigbergk <martinvonz@google.com>
Mon, 11 Oct 2021 22:47:37 -0700
changeset 48200 b6fc7d188f68
parent 48199 9d0e5629cfbf
child 48201 8ac61257c807
chistedit: move view state from a dict to a custom class Differential Revision: https://phab.mercurial-scm.org/D11636
hgext/histedit.py
--- a/hgext/histedit.py	Wed Oct 13 10:17:27 2021 -0700
+++ b/hgext/histedit.py	Mon Oct 11 22:47:37 2021 -0700
@@ -1197,39 +1197,39 @@
 def movecursor(state, oldpos, newpos):
     """Change the rule/changeset that the cursor is pointing to, regardless of
     current mode (you can switch between patches from the view patch window)."""
-    state[b'pos'] = newpos
-
-    mode, _ = state[b'mode']
+    state.pos = newpos
+
+    mode, _ = state.mode
     if mode == MODE_RULES:
         # Scroll through the list by updating the view for MODE_RULES, so that
         # even if we are not currently viewing the rules, switching back will
         # result in the cursor's rule being visible.
-        modestate = state[b'modes'][MODE_RULES]
+        modestate = state.modes[MODE_RULES]
         if newpos < modestate[b'line_offset']:
             modestate[b'line_offset'] = newpos
-        elif newpos > modestate[b'line_offset'] + state[b'page_height'] - 1:
-            modestate[b'line_offset'] = newpos - state[b'page_height'] + 1
+        elif newpos > modestate[b'line_offset'] + state.page_height - 1:
+            modestate[b'line_offset'] = newpos - state.page_height + 1
 
     # Reset the patch view region to the top of the new patch.
-    state[b'modes'][MODE_PATCH][b'line_offset'] = 0
+    state.modes[MODE_PATCH][b'line_offset'] = 0
 
 
 def changemode(state, mode):
-    curmode, _ = state[b'mode']
-    state[b'mode'] = (mode, curmode)
+    curmode, _ = state.mode
+    state.mode = (mode, curmode)
     if mode == MODE_PATCH:
-        state[b'modes'][MODE_PATCH][b'patchcontents'] = patchcontents(state)
+        state.modes[MODE_PATCH][b'patchcontents'] = patchcontents(state)
 
 
 def makeselection(state, pos):
-    state[b'selected'] = pos
+    state.selected = pos
 
 
 def swap(state, oldpos, newpos):
     """Swap two positions and calculate necessary conflicts in
     O(|newpos-oldpos|) time"""
 
-    rules = state[b'rules']
+    rules = state.rules
     assert 0 <= oldpos < len(rules) and 0 <= newpos < len(rules)
 
     rules[oldpos], rules[newpos] = rules[newpos], rules[oldpos]
@@ -1244,13 +1244,13 @@
         rules[newpos].checkconflicts(rules[r])
         rules[oldpos].checkconflicts(rules[r])
 
-    if state[b'selected']:
+    if state.selected:
         makeselection(state, newpos)
 
 
 def changeaction(state, pos, action):
     """Change the action state on the given position to the new action"""
-    rules = state[b'rules']
+    rules = state.rules
     assert 0 <= pos < len(rules)
     rules[pos].action = action
 
@@ -1258,7 +1258,7 @@
 def cycleaction(state, pos, next=False):
     """Changes the action state the next or the previous action from
     the action list"""
-    rules = state[b'rules']
+    rules = state.rules
     assert 0 <= pos < len(rules)
     current = rules[pos].action
 
@@ -1275,12 +1275,12 @@
 def changeview(state, delta, unit):
     """Change the region of whatever is being viewed (a patch or the list of
     changesets). 'delta' is an amount (+/- 1) and 'unit' is 'page' or 'line'."""
-    mode, _ = state[b'mode']
+    mode, _ = state.mode
     if mode != MODE_PATCH:
         return
-    mode_state = state[b'modes'][mode]
+    mode_state = state.modes[mode]
     num_lines = len(mode_state[b'patchcontents'])
-    page_height = state[b'page_height']
+    page_height = state.page_height
     unit = page_height if unit == b'page' else 1
     num_pages = 1 + (num_lines - 1) // page_height
     max_offset = (num_pages - 1) * page_height
@@ -1294,9 +1294,9 @@
     This takes the current state and based on the current character input from
     the user we change the state.
     """
-    selected = state[b'selected']
-    oldpos = state[b'pos']
-    rules = state[b'rules']
+    selected = state.selected
+    oldpos = state.pos
+    rules = state.rules
 
     if ch in (curses.KEY_RESIZE, b"KEY_RESIZE"):
         return E_RESIZE
@@ -1305,7 +1305,7 @@
     if ch is not None and b'0' <= ch <= b'9':
         lookup_ch = b'0'
 
-    curmode, prevmode = state[b'mode']
+    curmode, prevmode = state.mode
     action = KEYTABLE[curmode].get(
         lookup_ch, KEYTABLE[b'global'].get(lookup_ch)
     )
@@ -1391,8 +1391,8 @@
 
 
 def patchcontents(state):
-    repo = state[b'repo']
-    rule = state[b'rules'][state[b'pos']]
+    repo = state.repo
+    rule = state.rules[state.pos]
     displayer = logcmdutil.changesetdisplayer(
         repo.ui, repo, {b"patch": True, b"template": b"status"}, buffered=True
     )
@@ -1403,6 +1403,28 @@
     return displayer.hunk[rule.ctx.rev()].splitlines()
 
 
+class _chistedit_state(object):
+    def __init__(
+        self,
+        repo,
+        rules,
+    ):
+        self.repo = repo
+        self.rules = rules
+        self.pos = 0
+        self.selected = None
+        self.mode = (MODE_INIT, MODE_INIT)
+        self.page_height = None
+        self.modes = {
+            MODE_RULES: {
+                b'line_offset': 0,
+            },
+            MODE_PATCH: {
+                b'line_offset': 0,
+            },
+        }
+
+
 def _chisteditmain(repo, rules, stdscr):
     try:
         curses.use_default_colors()
@@ -1433,8 +1455,8 @@
     def rendercommit(win, state):
         """Renders the commit window that shows the log of the current selected
         commit"""
-        pos = state[b'pos']
-        rules = state[b'rules']
+        pos = state.pos
+        rules = state.rules
         rule = rules[pos]
 
         ctx = rule.ctx
@@ -1497,7 +1519,7 @@
 
     def renderhelp(win, state):
         maxy, maxx = win.getmaxyx()
-        mode, _ = state[b'mode']
+        mode, _ = state.mode
         for y, line in enumerate(helplines(mode)):
             if y >= maxy:
                 break
@@ -1505,10 +1527,10 @@
         win.noutrefresh()
 
     def renderrules(rulesscr, state):
-        rules = state[b'rules']
-        pos = state[b'pos']
-        selected = state[b'selected']
-        start = state[b'modes'][MODE_RULES][b'line_offset']
+        rules = state.rules
+        pos = state.pos
+        selected = state.selected
+        start = state.modes[MODE_RULES][b'line_offset']
 
         conflicts = [r.ctx for r in rules if r.conflicts]
         if len(conflicts) > 0:
@@ -1518,7 +1540,7 @@
             addln(rulesscr, -1, 0, line, curses.color_pair(COLOR_WARN))
 
         for y, rule in enumerate(rules[start:]):
-            if y >= state[b'page_height']:
+            if y >= state.page_height:
                 break
             if len(rule.conflicts) > 0:
                 rulesscr.addstr(y, 0, b" ", curses.color_pair(COLOR_WARN))
@@ -1574,8 +1596,8 @@
         win.noutrefresh()
 
     def renderpatch(win, state):
-        start = state[b'modes'][MODE_PATCH][b'line_offset']
-        content = state[b'modes'][MODE_PATCH][b'patchcontents']
+        start = state.modes[MODE_PATCH][b'line_offset']
+        content = state.modes[MODE_PATCH][b'patchcontents']
         renderstring(win, state, content[start:], diffcolors=True)
 
     def layout(mode):
@@ -1601,29 +1623,14 @@
         y += size[0]
         return win, y, x
 
-    state = {
-        b'pos': 0,
-        b'rules': rules,
-        b'selected': None,
-        b'mode': (MODE_INIT, MODE_INIT),
-        b'page_height': None,
-        b'modes': {
-            MODE_RULES: {
-                b'line_offset': 0,
-            },
-            MODE_PATCH: {
-                b'line_offset': 0,
-            },
-        },
-        b'repo': repo,
-    }
+    state = _chistedit_state(repo, rules)
 
     # eventloop
     ch = None
     stdscr.clear()
     stdscr.refresh()
     while True:
-        oldmode, unused = state[b'mode']
+        oldmode, unused = state.mode
         if oldmode == MODE_INIT:
             changemode(state, MODE_RULES)
         e = event(state, ch)
@@ -1631,19 +1638,19 @@
         if e == E_QUIT:
             return False
         if e == E_HISTEDIT:
-            return state[b'rules']
+            return state.rules
         else:
             if e == E_RESIZE:
                 size = screen_size()
                 if size != stdscr.getmaxyx():
                     curses.resizeterm(*size)
 
-            curmode, unused = state[b'mode']
+            curmode, unused = state.mode
             sizes = layout(curmode)
             if curmode != oldmode:
-                state[b'page_height'] = sizes[b'main'][0]
+                state.page_height = sizes[b'main'][0]
                 # Adjust the view to fit the current screen size.
-                movecursor(state, state[b'pos'], state[b'pos'])
+                movecursor(state, state.pos, state.pos)
 
             # Pack the windows against the top, each pane spread across the
             # full width of the screen.