[qt] open real file in editor if working directory is selected

Usecase:
  1. User up on a changeset then opens a file for a fix, saves the file, amends the change set, etc.
  2. User is currently on a dirty working directory and opens a file that is already modified, etc.

There are 2 cases:

  • clean working directory: selection should be on the working changeset
  • dirty working direction: selection should be on the row that display the dirty working changeset
authorAlain Leufroy <alain@leufroy.fr>
changeset3cdd94671228
branchdefault
phasedraft
hiddenyes
parent revision#a7113e4f1787 [qt4] add an icon for open in editor
child revision#76990eea5bcd [qt4] change some toolbar names (closes #103375)
files modified by this revision
hgviewlib/qt4/hgfileview.py
# HG changeset patch
# User Alain Leufroy <alain@leufroy.fr>
# Date 1369781489 -7200
# Wed May 29 00:51:29 2013 +0200
# Node ID 3cdd946712285b00fdc1043b2a2f5477a152b63d
# Parent a7113e4f178711e1c7bbec1f0d8806b5ee310046
[qt] open real file in editor if working directory is selected

Usecase:
1. User up on a changeset then opens a file for a fix, saves the file, amends the change set, etc.
2. User is currently on a dirty working directory and opens a file that is already modified, etc.

There are 2 cases:

- clean working directory: selection should be on the working changeset

- dirty working direction: selection should be on the row that display
the dirty working changeset

diff --git a/hgviewlib/qt4/hgfileview.py b/hgviewlib/qt4/hgfileview.py
@@ -393,16 +393,17 @@
1          return True
2 
3      def openEditor(self):
4          """Open the editor with the content of the selected file at
5          the selected revision"""
6 -        _, content = self._model.graph.filedata(self._filename, self._ctx.rev(),
7 -                                                'file', maxfilesize=-1)
8 -        suffix = '_%s-%s-%s' % (self._ctx.rev(), str(self._ctx),
9 -                               os.path.basename(self._filename))
10 -        open_tempfile_in_editor(self, self.cfg.getEditor(), content,
11 -                                suffix=suffix)
12 +        # We open the current file if the selected revision is the dirty working
13 +        # directory or if it is the working directory without any modification.
14 +        # Else we use a temporary file.
15 +        content_getter = lambda: self._model.graph.filedata(
16 +            self._filename, self._ctx.rev(), 'file', maxfilesize=-1)[1]
17 +        _open_in_editor(self, self.cfg, self._ctx.filectx(self._filename),
18 +                        content_getter)
19 
20      def updateDiffDecorations(self):
21          """
22          Recompute the diff and starts the timer
23          responsible for filling diff decoration markers
@@ -655,13 +656,13 @@
24          """Open the editor with the content of the selected file at
25          the selected revision"""
26          index = self.currentIndex()
27          sel_file = self.model().fileFromIndex(index)
28          from_rev = self.model().current_ctx.rev()
29 -        content = self.model().repo[from_rev].filectx(sel_file).data()
30 -        open_tempfile_in_editor(self, HgConfig(self.model().repo.ui).getEditor(),
31 -                                content, suffix=os.path.basename(sel_file))
32 +        filectx = self.model().repo[from_rev].filectx(sel_file)
33 +        _open_in_editor(self, HgConfig(self.model().repo.ui),
34 +                        filectx, filectx.data)
35 
36      def navigate(self, filename=None):
37          self._navigate(filename, FileViewer, self._nav_dialogs)
38 
39      def diffNavigate(self, filename=None):
@@ -738,14 +739,52 @@
40      def prevFile(self):
41          row = self.currentIndex().row()
42          self.setCurrentIndex(self.model().index(max(row - 1, 0), 0))
43 
44 
45 -def open_tempfile_in_editor(parent, editor, content, suffix=None):
46 -    """Open the editor with the given content in a temporary file."""
47 +def _open_in_editor(parent, cfg, filectx, content_getter):
48 +    """Open the editor on the file at the context ``filectx``.
49 +
50 +    If the selected revision is the working directory then the original file
51 +    opened else a temporary file is created.
52 +    """
53 +    editor = cfg.getEditor()
54 +    if filectx.rev() is None: # dirty wd is selected
55 +        return _open_originalfile_in_editor(parent, editor, filectx)
56 +    if ((not filectx._repo[None].dirty()) and                    # the wd is clean and
57 +        (filectx.changectx() in filectx._repo[None].parents())): # a wd parent is selected
58 +        return _open_originalfile_in_editor(parent, editor, filectx)
59 +    content = content_getter()
60 +    suffix = '_%s-%s-%s' % (filectx.rev(), str(filectx.changectx()),
61 +                            os.path.basename(filectx.path()))
62 +    _open_tempfile_in_editor(parent, editor, content, suffix=suffix)
63 +
64 +
65 +def _open_originalfile_in_editor(parent, editor, filectx):
66 +    """Open the ``editor`` on the original file from filectx"""
67 +    filepath = os.path.join(
68 +        os.path.abspath(filectx._repo.root),
69 +        filectx.path()
70 +        )
71 +    return _open_file_in_editor(parent, editor, filepath)
72 +
73 +
74 +def _open_tempfile_in_editor(parent, editor, content, suffix=None):
75 +    """Open the ``editor`` with the given ``content`` in a temporary file.
76 +
77 +    ``suffix`` is the suffix for the temporary file name.
78 +    ``parent`` is a Qt component that gets a reference to the editor process.
79 +    """
80      fid, filepath = tempfile.mkstemp(suffix=suffix)
81      os.close(fid)
82      with open(filepath, 'w') as fid:
83          fid.write(content)
84 +    process = _open_file_in_editor(parent, editor, filepath)
85 +    process.finished.connect(lambda rt, st: os.remove(filepath))
86 +
87 +def _open_file_in_editor(parent, editor, filepath):
88 +    """Open the ``filepath`` using the ``editor``.
89 +    ``parent`` is a Qt component that get a reference to the editor process.
90 +    """
91      process = QtCore.QProcess(parent)
92      process.start(editor, [filepath])
93 -    process.finished.connect(lambda rt, st: os.remove(filepath))
94 +    return process