# Copyright (C) 2005 Canonical Ltd

# GNU GPL v2.

"""vimdiff plugin for bzr"""

from bzrlib.commands import Command, register_command, Option
from bzrlib.errors import BzrError, NotVersionedError, BzrCommandError

horizontal = Option('horizontal', 
                    help='Split the display horizontally, not vertically')
def orient(horizontal):
    if horizontal is True:
        return '-o2'
    else:
        return '-O2'

class cmd_vimdiff(Command):
    """Show changes to a file in vimdiff
    
    At present this is restricted to showing only the changes to the
    last-committed revision, and only for a single file.

    The working copy may be edited in vimdiff and the differences will
    be kept up to date.

    See also vimdiff.
    """
    takes_args = ['file_to_diff']
    takes_options = ['revision', horizontal]
    def run(self, file_to_diff, revision=None, horizontal=False):
        vimdiff_to_file(['vimdiff', orient(horizontal), '-f'], file_to_diff, 
                        revision)


class cmd_gvimdiff(Command):
    """Show changes to a file in gvimdiff
    
    At present this is restricted to showing only the changes to the
    last-committed revision, and only for a single file.

    The working copy may be edited in vimdiff and the differences will
    be kept up to date.

    See also vimdiff.
    """
    takes_args = ['file_to_diff']
    takes_options = ['revision', horizontal]
    def run(self, file_to_diff, revision=None, horizontal=False):
        vimdiff_to_file(['gvimdiff', orient(horizontal), '-f'], file_to_diff, 
                        revision)



def vimdiff_to_file(vimdiff_args, file_to_diff, revision=None):
    from bzrlib.workingtree import WorkingTree
    work_tree, rel_path = WorkingTree.open_containing(file_to_diff)
    branch = work_tree.branch
    file_id = work_tree.path2id(rel_path)
    if file_id is None:
        raise NotVersionedError(rel_path)
    if revision is None:
        basis_tree = work_tree.basis_tree()
    else:
        if len(revision) != 1:
            raise BzrCommandError("You can specify at most one revision.")
        revision_id = revision[0].in_store(branch).rev_id
        basis_tree = branch.repository.revision_tree(revision_id)
    # must call with -f to wait around, so we can delete the temp file
    # otherwise it gets killed first.
    run_vimdiff(vimdiff_args, file_id, basis_tree, file_to_diff)


def write_old_to_temp(basis_tree, file_id):
    # we want the same suffix as before so syntax highlighting works
    from tempfile import NamedTemporaryFile
    from os.path import splitext, basename
    if not basis_tree.has_id(file_id):
        raise BzrError("file {%s} wasn't in the basis version %s"
                       % (file_id, basis_tree))
    old_filename = basis_tree.id2path(file_id)
    name_base, name_suffix = splitext(basename(old_filename))
    basis_tmp = NamedTemporaryFile(suffix='.tmp.' + name_suffix,
                                   prefix=name_base)
    basis_tmp.write(basis_tree.get_file_text(file_id))
    basis_tmp.flush()
    return basis_tmp


def run_vimdiff(vimdiff_args, file_id, old_tree, new_file_path):
    import subprocess
    old_tmp = write_old_to_temp(old_tree, file_id)
    sub = subprocess.call(vimdiff_args + [old_tmp.name, new_file_path])


register_command(cmd_gvimdiff)
register_command(cmd_vimdiff)
