Commits

Steve Losh committed cefc901

Factor out a bunch of stuff into autoload/.

Comments (0)

Files changed (22)

autoload/threesome.py

+import vim, os, sys
+
+
+# Add the library to the Python path.
+for p in vim.eval("&runtimepath").split(','):
+   plugin_dir = os.path.join(p, "autoload")
+   if os.path.exists(os.path.join(plugin_dir, "threesomelib")):
+      if plugin_dir not in sys.path:
+         sys.path.append(plugin_dir)
+      break
+
+
+import threesomelib.init as threesome
+
+# Wrapper functions ----------------------------------------------------------------
+
+def ThreesomeInit():
+    threesome.init()
+
+
+def ThreesomeOriginal():
+    threesome.modes.current_mode.key_original()
+
+def ThreesomeOne():
+    threesome.modes.current_mode.key_one()
+
+def ThreesomeTwo():
+    threesome.modes.current_mode.key_two()
+
+def ThreesomeResult():
+    threesome.modes.current_mode.key_result()
+
+
+def ThreesomeGrid():
+    threesome.modes.key_grid()
+
+def ThreesomeLoupe():
+    threesome.modes.key_loupe()
+
+def ThreesomeCompare():
+    threesome.modes.key_compare()
+
+def ThreesomePath():
+    threesome.modes.key_path()
+
+
+def ThreesomeDiff():
+    threesome.modes.current_mode.key_diff()
+
+def ThreesomeDiffoff():
+    threesome.modes.current_mode.key_diffoff()
+
+def ThreesomeScroll():
+    threesome.modes.current_mode.key_scrollbind()
+
+def ThreesomeLayout():
+    threesome.modes.current_mode.key_layout()
+
+def ThreesomeNext():
+    threesome.modes.current_mode.key_next()
+
+def ThreesomePrev():
+    threesome.modes.current_mode.key_prev()
+
+def ThreesomeUse():
+    threesome.modes.current_mode.key_use()
+
+def ThreesomeUse1():
+    threesome.modes.current_mode.key_use1()
+
+def ThreesomeUse2():
+    threesome.modes.current_mode.key_use2()
+

autoload/threesome.vim

+" ============================================================================
+" File:        threesome.vim
+" Description: vim global plugin for resolving three-way merge conflicts
+" Maintainer:  Steve Losh <steve@stevelosh.com>
+" License:     MIT X11
+" Notes:       Alpha.  Not ready for real use yet.
+"
+" ============================================================================
+
+"{{{ Init
+
+" Vim version check {{{
+
+if v:version < '703'
+    function! s:ThreesomeDidNotLoad()
+        echohl WarningMsg|echomsg "Threesome unavailable: requires Vim 7.3+"|echohl None
+    endfunction
+    command! -nargs=0 ThreesomeInit call s:ThreesomeDidNotLoad()
+    finish
+endif
+
+"}}}
+" Python version check {{{
+
+if has('python')
+    let s:has_supported_python = 2
+python << ENDPYTHON
+import sys, vim
+if sys.version_info[:2] < (2, 5):
+    vim.command('let s:has_supported_python = 0')
+ENDPYTHON
+else
+    let s:has_supported_python = 0
+endif
+
+if !s:has_supported_python
+    function! s:ThreesomeDidNotLoad()
+        echohl WarningMsg|echomsg "Threesome requires Vim to be compiled with Python 2.5+"|echohl None
+    endfunction
+    command! -nargs=0 ThreesomeInit call s:ThreesomeDidNotLoad()
+    finish
+endif
+
+"}}}
+" Configuration variables {{{
+
+if !exists('g:threesome_disable') " {{{
+    let g:threesome_disable = 0
+endif " }}}
+if !exists('g:threesome_initial_mode') " {{{
+    let g:threesome_initial_mode = 'grid'
+endif " }}}
+if !exists('g:threesome_initial_layout_grid') " {{{
+    let g:threesome_initial_layout_grid = 0
+endif " }}}
+if !exists('g:threesome_initial_layout_loupe') " {{{
+    let g:threesome_initial_layout_loupe = 0
+endif " }}}
+if !exists('g:threesome_initial_layout_compare') " {{{
+    let g:threesome_initial_layout_compare = 0
+endif " }}}
+if !exists('g:threesome_initial_layout_path') " {{{
+    let g:threesome_initial_layout_path = 0
+endif " }}}
+if !exists('g:threesome_initial_diff_grid') " {{{
+    let g:threesome_initial_diff_grid = 0
+endif " }}}
+if !exists('g:threesome_initial_diff_loupe') " {{{
+    let g:threesome_initial_diff_loupe = 0
+endif " }}}
+if !exists('g:threesome_initial_diff_compare') " {{{
+    let g:threesome_initial_diff_compare = 0
+endif " }}}
+if !exists('g:threesome_initial_diff_path') " {{{
+    let g:threesome_initial_diff_path = 0
+endif " }}}
+if !exists('g:threesome_initial_scrollbind_grid') " {{{
+    let g:threesome_initial_scrollbind_grid = 0
+endif " }}}
+if !exists('g:threesome_initial_scrollbind_loupe') " {{{
+    let g:threesome_initial_scrollbind_loupe = 0
+endif " }}}
+if !exists('g:threesome_initial_scrollbind_compare') " {{{
+    let g:threesome_initial_scrollbind_compare = 0
+endif " }}}
+if !exists('g:threesome_initial_scrollbind_path') " {{{
+    let g:threesome_initial_scrollbind_path = 0
+endif " }}}
+
+"}}}
+
+"}}}
+"{{{ Wrappers
+
+function! threesome#ThreesomeInit()"{{{
+    let python_module = fnameescape(globpath(&runtimepath, 'autoload/threesome.py'))
+    exe 'pyfile ' . python_module
+    python ThreesomeInit()
+endfunction"}}}
+
+function! threesome#ThreesomeGrid()"{{{
+    python ThreesomeGrid()
+endfunction"}}}
+function! threesome#ThreesomeLoupe()"{{{
+    python ThreesomeLoupe()
+endfunction"}}}
+function! threesome#ThreesomeCompare()"{{{
+    python ThreesomeCompare()
+endfunction"}}}
+function! threesome#ThreesomePath()"{{{
+    python ThreesomePath()
+endfunction"}}}
+
+function! threesome#ThreesomeOriginal()"{{{
+    python ThreesomeOriginal()
+endfunction"}}}
+function! threesome#ThreesomeOne()"{{{
+    python ThreesomeOne()
+endfunction"}}}
+function! threesome#ThreesomeTwo()"{{{
+    python ThreesomeTwo()
+endfunction"}}}
+function! threesome#ThreesomeResult()"{{{
+    python ThreesomeResult()
+endfunction"}}}
+
+function! threesome#ThreesomeDiff()"{{{
+    python ThreesomeDiff()
+endfunction"}}}
+function! threesome#ThreesomeDiffoff()"{{{
+    python ThreesomeDiffoff()
+endfunction"}}}
+function! threesome#ThreesomeScroll()"{{{
+    python ThreesomeScroll()
+endfunction"}}}
+function! threesome#ThreesomeLayout()"{{{
+    python ThreesomeLayout()
+endfunction"}}}
+function! threesome#ThreesomeNext()"{{{
+    python ThreesomeNext()
+endfunction"}}}
+function! threesome#ThreesomePrev()"{{{
+    python ThreesomePrev()
+endfunction"}}}
+function! threesome#ThreesomeUse()"{{{
+    python ThreesomeUse()
+endfunction"}}}
+function! threesome#ThreesomeUse1()"{{{
+    python ThreesomeUse1()
+endfunction"}}}
+function! threesome#ThreesomeUse2()"{{{
+    python ThreesomeUse2()
+endfunction"}}}
+
+"}}}

autoload/threesomelib/__init__.py

Empty file added.

autoload/threesomelib/init.py

+import vim
+import modes
+from settings import setting
+from util import buffers, keys, windows
+
+
+CONFLICT_MARKER_START = '<<<<<<<'
+CONFLICT_MARKER_MARK = '======='
+CONFLICT_MARKER_END = '>>>>>>>'
+
+def process_result():
+    windows.close_all()
+    buffers.result.open()
+
+    lines = []
+    in_conflict = False
+    for line in buffers.result.lines:
+        if in_conflict:
+            if CONFLICT_MARKER_MARK in line:
+                lines.append(line)
+            if CONFLICT_MARKER_END in line:
+                in_conflict = False
+            continue
+
+        if CONFLICT_MARKER_START in line:
+            in_conflict = True
+            continue
+
+        lines.append(line)
+
+    buffers.result.set_lines(lines)
+
+def bind_global_keys():
+    keys.bind('g', ':ThreesomeGrid<cr>')
+    keys.bind('l', ':ThreesomeLoupe<cr>')
+    keys.bind('c', ':ThreesomeCompare<cr>')
+    keys.bind('p', ':ThreesomePath<cr>')
+
+    keys.bind('o', ':ThreesomeOriginal<cr>')
+    keys.bind('1', ':ThreesomeOne<cr>')
+    keys.bind('2', ':ThreesomeTwo<cr>')
+    keys.bind('r', ':ThreesomeResult<cr>')
+
+    keys.bind('d', ':ThreesomeDiff<cr>')
+    keys.bind('D', ':ThreesomeDiffoff<cr>')
+    keys.bind('s', ':ThreesomeScroll<cr>')
+    keys.bind('n', ':ThreesomeNext<cr>')
+    keys.bind('N', ':ThreesomePrev<cr>')
+    keys.bind('<space>', ':ThreesomeLayout<cr>')
+    keys.bind('u', ':ThreesomeUse<cr>')
+
+    keys.bind('q', ':wa<cr>:qa<cr>')
+    keys.bind('CC', ':cq<cr>')
+
+def setlocal_buffers():
+    buffers.original.open()
+    vim.command('setlocal noswapfile')
+    vim.command('setlocal nomodifiable')
+    if setting('wrap'):
+        vim.command('setlocal ' + setting('wrap'))
+
+    buffers.one.open()
+    vim.command('setlocal noswapfile')
+    vim.command('setlocal nomodifiable')
+    if setting('wrap'):
+        vim.command('setlocal ' + setting('wrap'))
+
+    buffers.two.open()
+    vim.command('setlocal noswapfile')
+    vim.command('setlocal nomodifiable')
+    if setting('wrap'):
+        vim.command('setlocal ' + setting('wrap'))
+
+    buffers.result.open()
+    if setting('wrap'):
+        vim.command('setlocal ' + setting('wrap'))
+
+    buffers.hud.open()
+    vim.command('setlocal noswapfile')
+    vim.command('setlocal nomodifiable')
+    vim.command('setlocal nobuflisted')
+    vim.command('setlocal buftype=nofile')
+    vim.command('setlocal noundofile')
+    vim.command('setlocal nolist')
+    vim.command('setlocal ft=threesome')
+    vim.command('setlocal nowrap')
+    vim.command('resize ' + setting('hud_size', '3'))
+
+def create_hud():
+    vim.command('new __Threesome_HUD__')
+
+
+def init():
+    process_result()
+    create_hud()
+    setlocal_buffers()
+    bind_global_keys()
+
+    initial_mode = setting('initial_mode', 'grid').lower()
+    if initial_mode not in ['grid', 'loupe', 'compare', 'path']:
+        initial_mode = 'grid'
+
+    modes.current_mode = getattr(modes, initial_mode)
+    modes.current_mode.activate()
+
+

autoload/threesomelib/modes.py

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

autoload/threesomelib/settings.py

+import vim
+
+
+def setting(name, default=None):
+    full_name = 'g:threesome_' + name
+
+    if not int(vim.eval('exists("%s")' % full_name)):
+        return default
+    else:
+        return vim.eval(full_name)
+
+def boolsetting(name):
+    if int(setting(name, 0)):
+        return True
+    else:
+        False

autoload/threesomelib/util/__init__.py

+# This is kind of a dirty hack.  Feels bad, man.
+from bufferlib import buffers

autoload/threesomelib/util/bufferlib.py

+import os
+import vim
+import windows
+
+ap = os.path.abspath
+
+class Buffer(object):
+    def __init__(self, i):
+        self.number = i + 1
+        self._buffer = vim.buffers[i]
+        self.name = self._buffer.name
+
+    def open(self, winnr=None):
+        if winnr is not None:
+            windows.focus(winnr)
+        vim.command('%dbuffer' % self.number)
+
+    def set_lines(self, lines):
+        self._buffer[:] = lines
+
+    @property
+    def lines(self):
+        for line in self._buffer:
+            yield line
+
+
+    def __eq__(self, other):
+        return self.name == other.name
+
+    def __ne__(self, other):
+        return self.name != other.name
+
+
+class _BufferList(object):
+    @property
+    def original(self):
+        return Buffer(0)
+
+    @property
+    def one(self):
+        return Buffer(1)
+
+    @property
+    def two(self):
+        return Buffer(2)
+
+    @property
+    def result(self):
+        return Buffer(3)
+
+    @property
+    def hud(self):
+        return Buffer(int(vim.eval("bufnr('__Threesome_HUD__')")) - 1)
+
+
+    @property
+    def current(self):
+        bufname = ap(vim.eval('bufname("%")'))
+
+        if bufname == ap(self.original.name):
+            return self.original
+        elif bufname == ap(self.one.name):
+            return self.one
+        elif bufname == ap(self.two.name):
+            return self.two
+        elif bufname == ap(self.result.name):
+            return self.result
+
+    @property
+    def all(self):
+        return [self.original, self.one, self.two, self.result]
+
+
+    @property
+    def labels(self):
+        return { buffers.original.name: 'Original',
+                 buffers.one.name: 'One',
+                 buffers.two.name: 'Two',
+                 buffers.result.name: 'Result' }
+
+buffers = _BufferList()
+

autoload/threesomelib/util/io.py

+import sys
+
+
+def error(m):
+    sys.stdout.write(str(m) + '\n')

autoload/threesomelib/util/keys.py

+import vim
+
+
+def bind(key, to, options='', mode=None, leader='<localleader>'):
+    vim.command('nnoremap %s %s%s %s' % (options, leader, key, to))
+
+def unbind(key, options='', leader='<localleader>'):
+    vim.command('unmap %s %s%s' % (options, leader, key))
+

autoload/threesomelib/util/windows.py

+import vim
+
+
+def focus(winnr):
+    vim.command('%dwincmd w' % winnr)
+
+def close(winnr):
+    focus(winnr)
+    vim.command('wincmd c')
+
+def close_all():
+    for winnr in range(len(vim.windows) - 1):
+        close(winnr)
+
+def split():
+    vim.command('wincmd s')
+
+def vsplit():
+    vim.command('wincmd v')
+
+def currentnr():
+    return int(vim.eval('winnr()'))
+
+def pos():
+    return vim.current.window.cursor
+
+
+class remain:
+    def __enter__(self):
+        self.curwindow = currentnr()
+        self.pos = pos()
+
+    def __exit__(self, type, value, traceback):
+        focus(self.curwindow)
+        vim.current.window.cursor = self.pos
+

plugin/threesome.py

-import vim, os, sys
-
-
-# Add the library to the Python path.
-for p in vim.eval("&runtimepath").split(','):
-   plugin_dir = os.path.join(p, "plugin")
-   if os.path.exists(os.path.join(plugin_dir, "threesomelib")):
-      if plugin_dir not in sys.path:
-         sys.path.append(plugin_dir)
-      break
-
-
-# Wrapper functions
-threesome = None
-def ThreesomeInit():
-    global threesome
-    import threesomelib.init as init
-    init.init()
-    threesome = init
-
-
-def ThreesomeOriginal():
-    threesome.modes.current_mode.key_original()
-
-def ThreesomeOne():
-    threesome.modes.current_mode.key_one()
-
-def ThreesomeTwo():
-    threesome.modes.current_mode.key_two()
-
-def ThreesomeResult():
-    threesome.modes.current_mode.key_result()
-
-
-def ThreesomeGrid():
-    threesome.modes.key_grid()
-
-def ThreesomeLoupe():
-    threesome.modes.key_loupe()
-
-def ThreesomeCompare():
-    threesome.modes.key_compare()
-
-def ThreesomePath():
-    threesome.modes.key_path()
-
-
-def ThreesomeDiff():
-    threesome.modes.current_mode.key_diff()
-
-def ThreesomeDiffoff():
-    threesome.modes.current_mode.key_diffoff()
-
-def ThreesomeScroll():
-    threesome.modes.current_mode.key_scrollbind()
-
-def ThreesomeLayout():
-    threesome.modes.current_mode.key_layout()
-
-def ThreesomeNext():
-    threesome.modes.current_mode.key_next()
-
-def ThreesomePrev():
-    threesome.modes.current_mode.key_prev()
-
-def ThreesomeUse():
-    threesome.modes.current_mode.key_use()
-
-def ThreesomeUse1():
-    threesome.modes.current_mode.key_use1()
-
-def ThreesomeUse2():
-    threesome.modes.current_mode.key_use2()
-

plugin/threesome.vim

 "
 " ============================================================================
 
-
-"{{{ Init
-
-" Loading check {{{
+" Init {{{
 
 if !exists('g:threesome_debug') && (exists('g:threesome_disable') || exists('loaded_threesome') || &cp)
     finish
 endif
 let loaded_threesome = 1
 
-"}}}
-" Vim version check {{{
-
-if v:version < '703'
-    function! s:ThreesomeDidNotLoad()
-        echohl WarningMsg|echomsg "Threesome unavailable: requires Vim 7.3+"|echohl None
-    endfunction
-    command! -nargs=0 ThreesomeInit call s:ThreesomeDidNotLoad()
-    finish
-endif
-
-"}}}
-" Python version check {{{
-
-if has('python')
-    let s:has_supported_python = 2
-python << ENDPYTHON
-import sys, vim
-if sys.version_info[:2] < (2, 5):
-    vim.command('let s:has_supported_python = 0')
-ENDPYTHON
-else
-    let s:has_supported_python = 0
-endif
-
-if !s:has_supported_python
-    function! s:ThreesomeDidNotLoad()
-        echohl WarningMsg|echomsg "Threesome requires Vim to be compiled with Python 2.5+"|echohl None
-    endfunction
-    command! -nargs=0 ThreesomeInit call s:ThreesomeDidNotLoad()
-    finish
-endif
-
-"}}}
-" Configuration variables {{{
-
-if !exists('g:threesome_disable') " {{{
-    let g:threesome_disable = 0
-endif " }}}
-if !exists('g:threesome_initial_mode') " {{{
-    let g:threesome_initial_mode = 'grid'
-endif " }}}
-if !exists('g:threesome_initial_layout_grid') " {{{
-    let g:threesome_initial_layout_grid = 0
-endif " }}}
-if !exists('g:threesome_initial_layout_loupe') " {{{
-    let g:threesome_initial_layout_loupe = 0
-endif " }}}
-if !exists('g:threesome_initial_layout_compare') " {{{
-    let g:threesome_initial_layout_compare = 0
-endif " }}}
-if !exists('g:threesome_initial_layout_path') " {{{
-    let g:threesome_initial_layout_path = 0
-endif " }}}
-if !exists('g:threesome_initial_diff_grid') " {{{
-    let g:threesome_initial_diff_grid = 0
-endif " }}}
-if !exists('g:threesome_initial_diff_loupe') " {{{
-    let g:threesome_initial_diff_loupe = 0
-endif " }}}
-if !exists('g:threesome_initial_diff_compare') " {{{
-    let g:threesome_initial_diff_compare = 0
-endif " }}}
-if !exists('g:threesome_initial_diff_path') " {{{
-    let g:threesome_initial_diff_path = 0
-endif " }}}
-if !exists('g:threesome_initial_scrollbind_grid') " {{{
-    let g:threesome_initial_scrollbind_grid = 0
-endif " }}}
-if !exists('g:threesome_initial_scrollbind_loupe') " {{{
-    let g:threesome_initial_scrollbind_loupe = 0
-endif " }}}
-if !exists('g:threesome_initial_scrollbind_compare') " {{{
-    let g:threesome_initial_scrollbind_compare = 0
-endif " }}}
-if !exists('g:threesome_initial_scrollbind_path') " {{{
-    let g:threesome_initial_scrollbind_path = 0
-endif " }}}
-
-"}}}
-
-"}}}
-
-"{{{ Wrappers
-
-function! s:ThreesomeInit()"{{{
-    let python_module = fnameescape(globpath(&runtimepath, 'plugin/threesome.py'))
-    exe 'pyfile ' . python_module
-    python ThreesomeInit()
-endfunction"}}}
-
-function! s:ThreesomeGrid()"{{{
-    python ThreesomeGrid()
-endfunction"}}}
-function! s:ThreesomeLoupe()"{{{
-    python ThreesomeLoupe()
-endfunction"}}}
-function! s:ThreesomeCompare()"{{{
-    python ThreesomeCompare()
-endfunction"}}}
-function! s:ThreesomePath()"{{{
-    python ThreesomePath()
-endfunction"}}}
-
-function! s:ThreesomeOriginal()"{{{
-    python ThreesomeOriginal()
-endfunction"}}}
-function! s:ThreesomeOne()"{{{
-    python ThreesomeOne()
-endfunction"}}}
-function! s:ThreesomeTwo()"{{{
-    python ThreesomeTwo()
-endfunction"}}}
-function! s:ThreesomeResult()"{{{
-    python ThreesomeResult()
-endfunction"}}}
-
-function! s:ThreesomeDiff()"{{{
-    python ThreesomeDiff()
-endfunction"}}}
-function! s:ThreesomeDiffoff()"{{{
-    python ThreesomeDiffoff()
-endfunction"}}}
-function! s:ThreesomeScroll()"{{{
-    python ThreesomeScroll()
-endfunction"}}}
-function! s:ThreesomeLayout()"{{{
-    python ThreesomeLayout()
-endfunction"}}}
-function! s:ThreesomeNext()"{{{
-    python ThreesomeNext()
-endfunction"}}}
-function! s:ThreesomePrev()"{{{
-    python ThreesomePrev()
-endfunction"}}}
-function! s:ThreesomeUse()"{{{
-    python ThreesomeUse()
-endfunction"}}}
-function! s:ThreesomeUse1()"{{{
-    python ThreesomeUse1()
-endfunction"}}}
-function! s:ThreesomeUse2()"{{{
-    python ThreesomeUse2()
-endfunction"}}}
-
-"}}}
+" }}}
 
 "{{{ Commands
 
-command! -nargs=0 ThreesomeInit call s:ThreesomeInit()
+command! -nargs=0 ThreesomeInit call threesome#ThreesomeInit()
 
-command! -nargs=0 ThreesomeGrid call s:ThreesomeGrid()
-command! -nargs=0 ThreesomeLoupe call s:ThreesomeLoupe()
-command! -nargs=0 ThreesomeCompare call s:ThreesomeCompare()
-command! -nargs=0 ThreesomePath call s:ThreesomePath()
+command! -nargs=0 ThreesomeGrid call threesome#ThreesomeGrid()
+command! -nargs=0 ThreesomeLoupe call threesome#ThreesomeLoupe()
+command! -nargs=0 ThreesomeCompare call threesome#ThreesomeCompare()
+command! -nargs=0 ThreesomePath call threesome#ThreesomePath()
 
-command! -nargs=0 ThreesomeOriginal call s:ThreesomeOriginal()
-command! -nargs=0 ThreesomeOne call s:ThreesomeOne()
-command! -nargs=0 ThreesomeTwo call s:ThreesomeTwo()
-command! -nargs=0 ThreesomeResult call s:ThreesomeResult()
+command! -nargs=0 ThreesomeOriginal call threesome#ThreesomeOriginal()
+command! -nargs=0 ThreesomeOne call threesome#ThreesomeOne()
+command! -nargs=0 ThreesomeTwo call threesome#ThreesomeTwo()
+command! -nargs=0 ThreesomeResult call threesome#ThreesomeResult()
 
-command! -nargs=0 ThreesomeDiff call s:ThreesomeDiff()
-command! -nargs=0 ThreesomeDiffoff call s:ThreesomeDiffoff()
-command! -nargs=0 ThreesomeScroll call s:ThreesomeScroll()
-command! -nargs=0 ThreesomeLayout call s:ThreesomeLayout()
-command! -nargs=0 ThreesomeNext call s:ThreesomeNext()
-command! -nargs=0 ThreesomePrev call s:ThreesomePrev()
-command! -nargs=0 ThreesomeUse call s:ThreesomeUse()
-command! -nargs=0 ThreesomeUse1 call s:ThreesomeUse1()
-command! -nargs=0 ThreesomeUse2 call s:ThreesomeUse2()
+command! -nargs=0 ThreesomeDiff call threesome#ThreesomeDiff()
+command! -nargs=0 ThreesomeDiffoff call threesome#ThreesomeDiffoff()
+command! -nargs=0 ThreesomeScroll call threesome#ThreesomeScroll()
+command! -nargs=0 ThreesomeLayout call threesome#ThreesomeLayout()
+command! -nargs=0 ThreesomeNext call threesome#ThreesomeNext()
+command! -nargs=0 ThreesomePrev call threesome#ThreesomePrev()
+command! -nargs=0 ThreesomeUse call threesome#ThreesomeUse()
+command! -nargs=0 ThreesomeUse1 call threesome#ThreesomeUse1()
+command! -nargs=0 ThreesomeUse2 call threesome#ThreesomeUse2()
 
 "}}}
-
-" vim:se fdm=marker:sw=4:

plugin/threesomelib/__init__.py

Empty file removed.

plugin/threesomelib/init.py

-import vim
-import modes
-from settings import setting
-from util import buffers, keys, windows
-
-
-CONFLICT_MARKER_START = '<<<<<<<'
-CONFLICT_MARKER_MARK = '======='
-CONFLICT_MARKER_END = '>>>>>>>'
-
-def process_result():
-    windows.close_all()
-    buffers.result.open()
-
-    lines = []
-    in_conflict = False
-    for line in buffers.result.lines:
-        if in_conflict:
-            if CONFLICT_MARKER_MARK in line:
-                lines.append(line)
-            if CONFLICT_MARKER_END in line:
-                in_conflict = False
-            continue
-
-        if CONFLICT_MARKER_START in line:
-            in_conflict = True
-            continue
-
-        lines.append(line)
-
-    buffers.result.set_lines(lines)
-
-def bind_global_keys():
-    keys.bind('g', ':ThreesomeGrid<cr>')
-    keys.bind('l', ':ThreesomeLoupe<cr>')
-    keys.bind('c', ':ThreesomeCompare<cr>')
-    keys.bind('p', ':ThreesomePath<cr>')
-
-    keys.bind('o', ':ThreesomeOriginal<cr>')
-    keys.bind('1', ':ThreesomeOne<cr>')
-    keys.bind('2', ':ThreesomeTwo<cr>')
-    keys.bind('r', ':ThreesomeResult<cr>')
-
-    keys.bind('d', ':ThreesomeDiff<cr>')
-    keys.bind('D', ':ThreesomeDiffoff<cr>')
-    keys.bind('s', ':ThreesomeScroll<cr>')
-    keys.bind('n', ':ThreesomeNext<cr>')
-    keys.bind('N', ':ThreesomePrev<cr>')
-    keys.bind('<space>', ':ThreesomeLayout<cr>')
-    keys.bind('u', ':ThreesomeUse<cr>')
-
-    keys.bind('q', ':wa<cr>:qa<cr>')
-    keys.bind('CC', ':cq<cr>')
-
-def setlocal_buffers():
-    buffers.original.open()
-    vim.command('setlocal noswapfile')
-    vim.command('setlocal nomodifiable')
-    if setting('wrap'):
-        vim.command('setlocal ' + setting('wrap'))
-
-    buffers.one.open()
-    vim.command('setlocal noswapfile')
-    vim.command('setlocal nomodifiable')
-    if setting('wrap'):
-        vim.command('setlocal ' + setting('wrap'))
-
-    buffers.two.open()
-    vim.command('setlocal noswapfile')
-    vim.command('setlocal nomodifiable')
-    if setting('wrap'):
-        vim.command('setlocal ' + setting('wrap'))
-
-    buffers.result.open()
-    if setting('wrap'):
-        vim.command('setlocal ' + setting('wrap'))
-
-    buffers.hud.open()
-    vim.command('setlocal noswapfile')
-    vim.command('setlocal nomodifiable')
-    vim.command('setlocal nobuflisted')
-    vim.command('setlocal buftype=nofile')
-    vim.command('setlocal noundofile')
-    vim.command('setlocal nolist')
-    vim.command('setlocal ft=threesome')
-    vim.command('setlocal nowrap')
-    vim.command('resize ' + setting('hud_size', '3'))
-
-def create_hud():
-    vim.command('new __Threesome_HUD__')
-
-
-def init():
-    process_result()
-    create_hud()
-    setlocal_buffers()
-    bind_global_keys()
-
-    initial_mode = setting('initial_mode', 'grid').lower()
-    if initial_mode not in ['grid', 'loupe', 'compare', 'path']:
-        initial_mode = 'grid'
-
-    modes.current_mode = getattr(modes, initial_mode)
-    modes.current_mode.activate()
-
-

plugin/threesomelib/modes.py

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