plugin/threesomelib/modes.py @ 47d8db3bb3fc

Add "tests/original" to .hgignore.
author Steve Losh <steve@stevelosh.com>
date Mon, 13 Jun 2011 22:28:56 -0400
parents bc6297aefe4b
children (none)
from __future__ import with_statement

import vim
from util import buffers, keys, windows
from settings import boolsetting, setting


current_mode = None

class Mode(object):
    def __init__(self):
        return super(Mode, self).__init__()


    def diff(self, diffmode):
        with windows.remain():
            getattr(self, '_diff_%d' % diffmode)()

        # Reset the scrollbind to whatever it was before we diffed.
        if not diffmode:
            self.scrollbind(self._current_scrollbind)

    def key_diff(self, diffmode=None):
        next_diff_mode = self._current_diff_mode + 1
        if next_diff_mode >= self._number_of_diff_modes:
            next_diff_mode = 0
        self.diff(next_diff_mode)


    def diffoff(self):
        with windows.remain():
            for winnr in range(2, 2 + self._number_of_windows):
                windows.focus(winnr)
                curbuffer = buffers.current

                for buffer in buffers.all:
                    buffer.open()
                    vim.command('diffoff')
                    if setting('wrap'):
                        vim.command('setlocal ' + setting('wrap'))

                curbuffer.open()


    def key_diffoff(self):
        self.diff(0)


    def scrollbind(self, enabled):
        if self._current_diff_mode:
            return

        with windows.remain():
            self._current_scrollbind = enabled

            for winnr in range(2, 2 + self._number_of_windows):
                windows.focus(winnr)

                if enabled:
                    vim.command('set scrollbind')
                else:
                    vim.command('set noscrollbind')

            if enabled:
                vim.command('syncbind')

    def key_scrollbind(self):
        self.scrollbind(not self._current_scrollbind)


    def layout(self, layoutnr):
        getattr(self, '_layout_%d' % layoutnr)()
        self.diff(self._current_diff_mode)
        self.redraw_hud()

    def key_layout(self, diffmode=None):
        next_layout = self._current_layout + 1
        if next_layout >= self._number_of_layouts:
            next_layout = 0
        self.layout(next_layout)


    def key_original(self):
        pass

    def key_one(self):
        pass

    def key_two(self):
        pass

    def key_result(self):
        pass


    def key_use(self):
        pass


    def activate(self):
        self.layout(self._current_layout)
        self.diff(self._current_diff_mode)
        self.scrollbind(self._current_scrollbind)

    def deactivate(self):
        pass


    def key_next(self):
        self.goto_result()
        vim.command(r'exe "normal! /\=\=\=\=\=\=\=\<cr>"')

    def key_prev(self):
        self.goto_result()
        vim.command(r'exe "normal! ?\=\=\=\=\=\=\=\<cr>"')


    def open_hud(self, winnr):
        windows.split()
        windows.focus(winnr)
        buffers.hud.open()
        vim.command('wincmd K')
        self.redraw_hud()

    def hud_lines(self):
        def pad(lines):
            l = max([len(line) for line in lines])
            return [line.ljust(l) for line in lines]

        sep = '    |    '

        modes = pad([
            r'Threesome Modes',
            r'x[G]rid   y[C]ompare'.replace('x', self._id == 'grid' and '*' or ' ')
                                   .replace('y', self._id == 'comp' and '*' or ' '),
            r'x[L]oupe  y[P]ath'.replace('x', self._id == 'loup' and '*' or ' ')
                                .replace('y', self._id == 'path' and '*' or ' '),
        ])
        diagram = pad(self.hud_diagram())
        commands = pad([
            r'Threesome Commands',
            r'd: cycle diffs   n: next conflict   space: cycle layouts',
            r'D: diffs off     N: prev conflict   s: toggle scrollbind',
        ])

        lines = []
        for line in modes:
            lines.append(line + sep)
        for i, line in enumerate(diagram):
            lines[i] += line + sep
        for i, line in enumerate(commands):
            lines[i] += line + sep

        for i, line in enumerate(lines):
            lines[i] = line.rstrip()

        return lines

    def redraw_hud(self):
        with windows.remain():
            windows.focus(1)

            vim.command('setlocal modifiable')
            buffers.hud.set_lines(self.hud_lines())
            vim.command('setlocal nomodifiable')

            vim.command('set winfixheight')
            vim.command('resize ' + setting('hud_size', '3'))
            vim.command('wincmd =')


class GridMode(Mode):
    """
    Layout 0                 Layout 1                        Layout 2
    +-------------------+    +--------------------------+    +---------------+
    |     Original      |    | One    | Result | Two    |    |      One      |
    |2                  |    |        |        |        |    |2              |
    +-------------------+    |        |        |        |    +---------------+
    |  One    |    Two  |    |        |        |        |    |     Result    |
    |3        |4        |    |        |        |        |    |3              |
    +-------------------+    |        |        |        |    +---------------+
    |      Result       |    |        |        |        |    |      Two      |
    |5                  |    |2       |3       |4       |    |4              |
    +-------------------+    +--------------------------+    +---------------+
    """

    def __init__(self):
        self._id = 'grid'
        self._current_layout = int(setting('initial_layout_grid', 0))
        self._current_diff_mode = int(setting('initial_diff_grid', 0))
        self._current_scrollbind = boolsetting('initial_scrollbind_grid')

        self._number_of_diff_modes = 2
        self._number_of_layouts = 3

        return super(GridMode, self).__init__()


    def _layout_0(self):
        self._number_of_windows = 4
        self._current_layout = 0

        # Open the layout
        windows.close_all()
        windows.split()
        windows.split()
        windows.focus(2)
        windows.vsplit()

        # Put the buffers in the appropriate windows
        windows.focus(1)
        buffers.original.open()

        windows.focus(2)
        buffers.one.open()

        windows.focus(3)
        buffers.two.open()

        windows.focus(4)
        buffers.result.open()

        self.open_hud(5)

        windows.focus(5)

    def _layout_1(self):
        self._number_of_windows = 3
        self._current_layout = 1

        # Open the layout
        windows.close_all()
        windows.vsplit()
        windows.vsplit()

        # Put the buffers in the appropriate windows
        windows.focus(1)
        buffers.one.open()

        windows.focus(2)
        buffers.result.open()

        windows.focus(3)
        buffers.two.open()

        self.open_hud(4)

        windows.focus(3)

    def _layout_2(self):
        self._number_of_windows = 4
        self._current_layout = 2

        # Open the layout
        windows.close_all()
        windows.split()
        windows.split()

        # Put the buffers in the appropriate windows
        windows.focus(1)
        buffers.one.open()

        windows.focus(2)
        buffers.result.open()

        windows.focus(3)
        buffers.two.open()

        self.open_hud(4)

        windows.focus(3)


    def _diff_0(self):
        self.diffoff()
        self._current_diff_mode = 0

    def _diff_1(self):
        self.diffoff()
        self._current_diff_mode = 1

        for i in range(2, self._number_of_windows + 2):
            windows.focus(i)
            vim.command('diffthis')


    def key_original(self):
        if self._current_layout == 0:
            windows.focus(2)
        elif self._current_layout == 1:
            return
        elif self._current_layout == 2:
            return

    def key_one(self):
        if self._current_layout == 0:
            windows.focus(3)
        elif self._current_layout == 1:
            windows.focus(2)
        elif self._current_layout == 2:
            windows.focus(2)

    def key_two(self):
        if self._current_layout == 0:
            windows.focus(4)
        elif self._current_layout == 1:
            windows.focus(4)
        elif self._current_layout == 2:
            windows.focus(4)

    def key_result(self):
        if self._current_layout == 0:
            windows.focus(5)
        elif self._current_layout == 1:
            windows.focus(3)
        elif self._current_layout == 2:
            windows.focus(3)


    def _key_use_0(self, target):
        targetwin = 3 if target == 1 else 4

        with windows.remain():
            self.diffoff()

            windows.focus(5)
            vim.command('diffthis')

            windows.focus(targetwin)
            vim.command('diffthis')

    def _key_use_12(self, target):
        targetwin = 2 if target == 1 else 4

        with windows.remain():
            self.diffoff()

            windows.focus(3)
            vim.command('diffthis')

            windows.focus(targetwin)
            vim.command('diffthis')


    def key_use1(self):
        current_diff = self._current_diff_mode

        if self._current_layout == 0:
            self._key_use_0(1)
        elif self._current_layout == 1:
            self._key_use_12(1)
        elif self._current_layout == 2:
            self._key_use_12(1)

        if buffers.current == buffers.result:
            vim.command('diffget')
        elif buffers.current in (buffers.one, buffers.two):
            vim.command('diffput')

        self.diff(current_diff)

    def key_use2(self):
        current_diff = self._current_diff_mode

        if self._current_layout == 0:
            self._key_use_0(2)
        elif self._current_layout == 1:
            self._key_use_12(2)
        elif self._current_layout == 2:
            self._key_use_12(2)

        if buffers.current == buffers.result:
            vim.command('diffget')
        elif buffers.current in (buffers.one, buffers.two):
            vim.command('diffput')

        self.diff(current_diff)


    def goto_result(self):
        if self._current_layout == 0:
            windows.focus(5)
        elif self._current_layout == 1:
            windows.focus(3)
        elif self._current_layout == 2:
            windows.focus(3)


    def activate(self):
        keys.bind('u1', ':ThreesomeUse1<cr>')
        keys.bind('u2', ':ThreesomeUse2<cr>')
        return super(GridMode, self).activate()

    def deactivate(self):
        keys.unbind('u1')
        keys.unbind('u2')
        return super(GridMode, self).deactivate()


    def hud_diagram(self):
        if self._current_layout == 0:
            return [
                r'           Original',
                r'Layout ->  One  Two',
                r'            Result',
            ]
        elif self._current_layout == 1:
            return [
                r'',
                r'Layout ->  One  Result  Two',
                r'',
            ]
        elif self._current_layout == 2:
            return [
                r'           One',
                r'Layout ->  Result',
                r'           Two',
            ]

class LoupeMode(Mode):
    def __init__(self):
        self._id = 'loup'
        self._current_layout = int(setting('initial_layout_loupe', 0))
        self._current_diff_mode = int(setting('initial_diff_loupe', 0))
        self._current_scrollbind = boolsetting('initial_scrollbind_loupe')

        self._number_of_diff_modes = 1
        self._number_of_layouts = 1

        self._current_buffer = buffers.result

        return super(LoupeMode, self).__init__()


    def _diff_0(self):
        self.diffoff()
        self._current_diff_mode = 0


    def _layout_0(self):
        self._number_of_windows = 1
        self._current_layout = 0

        # Open the layout
        windows.close_all()

        # Put the buffers in the appropriate windows
        windows.focus(1)
        self._current_buffer.open()

        self.open_hud(2)

        windows.focus(2)


    def key_original(self):
        windows.focus(2)
        buffers.original.open()
        self._current_buffer = buffers.original
        self.redraw_hud()

    def key_one(self):
        windows.focus(2)
        buffers.one.open()
        self._current_buffer = buffers.one
        self.redraw_hud()

    def key_two(self):
        windows.focus(2)
        buffers.two.open()
        self._current_buffer = buffers.two
        self.redraw_hud()

    def key_result(self):
        windows.focus(2)
        buffers.result.open()
        self._current_buffer = buffers.result
        self.redraw_hud()


    def key_use(self):
        pass


    def goto_result(self):
        self.key_result()


    def hud_diagram(self):
        buf = buffers.labels[self._current_buffer.name]

        if self._current_layout == 0:
            return [
                r'',
                r'Layout ->  %s ' % (buf,),
                r'',
            ]

class CompareMode(Mode):
    def __init__(self):
        self._id = 'comp'
        self._current_layout = int(setting('initial_layout_compare', 0))
        self._current_diff_mode = int(setting('initial_diff_compare', 0))
        self._current_scrollbind = boolsetting('initial_scrollbind_compare')

        self._number_of_diff_modes = 2
        self._number_of_layouts = 2

        self._current_buffer_first = buffers.original
        self._current_buffer_second = buffers.result

        return super(CompareMode, self).__init__()


    def _diff_0(self):
        self.diffoff()
        self._current_diff_mode = 0

    def _diff_1(self):
        self.diffoff()
        self._current_diff_mode = 1

        windows.focus(2)
        vim.command('diffthis')

        windows.focus(3)
        vim.command('diffthis')


    def _layout_0(self):
        self._number_of_windows = 2
        self._current_layout = 0

        # Open the layout
        windows.close_all()
        windows.vsplit()

        # Put the buffers in the appropriate windows
        windows.focus(1)
        self._current_buffer_first.open()

        windows.focus(2)
        self._current_buffer_second.open()

        self.open_hud(3)

        windows.focus(3)

    def _layout_1(self):
        self._number_of_windows = 2
        self._current_layout = 1

        # Open the layout
        windows.close_all()
        windows.split()

        # Put the buffers in the appropriate windows
        windows.focus(1)
        self._current_buffer_first.open()

        windows.focus(2)
        self._current_buffer_second.open()

        self.open_hud(3)

        windows.focus(3)


    def key_original(self):
        windows.focus(2)
        buffers.original.open()
        self._current_buffer_first = buffers.original
        self.diff(self._current_diff_mode)

        self.redraw_hud()

    def key_one(self):
        def open_one(winnr):
            buffers.one.open(winnr)
            if winnr == 2:
                self._current_buffer_first = buffers.one
            else:
                self._current_buffer_second = buffers.one
            self.diff(self._current_diff_mode)
            self.redraw_hud()

        curwindow = windows.currentnr()
        if curwindow == 1:
            curwindow = 2

        # If file one is showing, go to it.
        windows.focus(2)
        if buffers.current == buffers.one:
            return

        windows.focus(3)
        if buffers.current == buffers.one:
            return

        # If both the original and result are showing, open file one in the
        # current window.
        windows.focus(2)
        if buffers.current == buffers.original:
            windows.focus(3)
            if buffers.current == buffers.result:
                open_one(curwindow)
                return

        # If file two is in window 1, then we open file one in window 1.
        windows.focus(2)
        if buffers.current == buffers.two:
            open_one(2)
            return

        # Otherwise, open file one in the current window.
        open_one(curwindow)

    def key_two(self):
        def open_two(winnr):
            buffers.two.open(winnr)
            if winnr == 2:
                self._current_buffer_first = buffers.two
            else:
                self._current_buffer_second = buffers.two
            self.diff(self._current_diff_mode)
            self.redraw_hud()

        curwindow = windows.currentnr()
        if curwindow == 1:
            curwindow = 2

        # If file two is showing, go to it.
        windows.focus(2)
        if buffers.current == buffers.two:
            return

        windows.focus(3)
        if buffers.current == buffers.two:
            return

        # If both the original and result are showing, open file two in the
        # current window.
        windows.focus(2)
        if buffers.current == buffers.original:
            windows.focus(3)
            if buffers.current == buffers.result:
                open_two(curwindow)
                return

        # If file one is in window 2, then we open file two in window 2.
        windows.focus(3)
        if buffers.current == buffers.two:
            open_two(3)
            return

        # Otherwise, open file two in window 2.
        open_two(curwindow)

    def key_result(self):
        windows.focus(3)
        buffers.result.open()
        self._current_buffer_second = buffers.result
        self.diff(self._current_diff_mode)

        self.redraw_hud()


    def key_use(self):
        active = (self._current_buffer_first, self._current_buffer_second)

        if buffers.result not in active:
            return

        if buffers.one not in active and buffers.two not in active:
            return

        current_diff = self._current_diff_mode
        with windows.remain():
            self._diff_1()  # diff the windows

        if buffers.current == buffers.result:
            vim.command('diffget')
        elif buffers.current in (buffers.one, buffers.two):
            vim.command('diffput')

        self.diff(current_diff)


    def goto_result(self):
        self.key_result()


    def hud_diagram(self):
        first = buffers.labels[self._current_buffer_first.name]
        second = buffers.labels[self._current_buffer_second.name]

        if self._current_layout == 0:
            return [
                r'',
                r'Layout ->  %s %s' % (first, second),
                r'',
            ]
        elif self._current_layout == 1:
            return [
                r'',
                r'Layout ->  %s' % first,
                r'           %s' % second,
            ]

class PathMode(Mode):
    def __init__(self):
        self._id = 'path'
        self._current_layout = int(setting('initial_layout_path', 0))
        self._current_diff_mode = int(setting('initial_diff_path', 0))
        self._current_scrollbind = boolsetting('initial_scrollbind_path')

        self._number_of_diff_modes = 5
        self._number_of_layouts = 2

        self._current_mid_buffer = buffers.one

        return super(PathMode, self).__init__()


    def _diff_0(self):
        self.diffoff()
        self._current_diff_mode = 0

    def _diff_1(self):
        self.diffoff()
        self._current_diff_mode = 1

        windows.focus(2)
        vim.command('diffthis')

        windows.focus(4)
        vim.command('diffthis')

    def _diff_2(self):
        self.diffoff()
        self._current_diff_mode = 2

        windows.focus(2)
        vim.command('diffthis')

        windows.focus(3)
        vim.command('diffthis')

    def _diff_3(self):
        self.diffoff()
        self._current_diff_mode = 3

        windows.focus(3)
        vim.command('diffthis')

        windows.focus(4)
        vim.command('diffthis')

    def _diff_4(self):
        self.diffoff()
        self._current_diff_mode = 4

        windows.focus(2)
        vim.command('diffthis')

        windows.focus(3)
        vim.command('diffthis')

        windows.focus(4)
        vim.command('diffthis')


    def _layout_0(self):
        self._number_of_windows = 3
        self._current_layout = 0

        # Open the layout
        windows.close_all()
        windows.vsplit()
        windows.vsplit()

        # Put the buffers in the appropriate windows
        windows.focus(1)
        buffers.original.open()

        windows.focus(2)
        self._current_mid_buffer.open()

        windows.focus(3)
        buffers.result.open()

        self.open_hud(4)

        windows.focus(4)

    def _layout_1(self):
        self._number_of_windows = 3
        self._current_layout = 1

        # Open the layout
        windows.close_all()
        windows.split()
        windows.split()

        # Put the buffers in the appropriate windows
        windows.focus(1)
        buffers.original.open()

        windows.focus(2)
        self._current_mid_buffer.open()

        windows.focus(3)
        buffers.result.open()

        self.open_hud(4)

        windows.focus(4)


    def key_original(self):
        windows.focus(2)

    def key_one(self):
        windows.focus(3)
        buffers.one.open()
        self._current_mid_buffer = buffers.one
        self.diff(self._current_diff_mode)
        windows.focus(3)
        self.redraw_hud()

    def key_two(self):
        windows.focus(3)
        buffers.two.open()
        self._current_mid_buffer = buffers.two
        self.diff(self._current_diff_mode)
        windows.focus(3)
        self.redraw_hud()

    def key_result(self):
        windows.focus(4)


    def key_use(self):
        current_diff = self._current_diff_mode
        with windows.remain():
            self._diff_3()  # diff the middle and result windows

        if buffers.current == buffers.result:
            vim.command('diffget')
        elif buffers.current in (buffers.one, buffers.two):
            vim.command('diffput')

        self.diff(current_diff)


    def goto_result(self):
        windows.focus(4)


    def hud_diagram(self):
        if self._current_mid_buffer == buffers.one:
            buf = 'One'
        else:
            buf = 'Two'

        if self._current_layout == 0:
            return [
                r'',
                r'Layout ->  Original  %s  Result' % buf,
                r'',
            ]
        elif self._current_layout == 1:
            return [
                r'           Original',
                r'Layout ->  %s' % buf,
                r'           Result',
            ]


grid = GridMode()
loupe = LoupeMode()
compare = CompareMode()
path = PathMode()


def key_grid():
    global current_mode
    current_mode = grid
    grid.activate()

def key_loupe():
    global current_mode
    current_mode = loupe
    loupe.activate()

def key_compare():
    global current_mode
    current_mode = compare
    compare.activate()

def key_path():
    global current_mode
    current_mode = path
    path.activate()