Commits

Steve Borho committed 7916e1a

editfiles: split detecteditor into util/editor.py, add user configuration

This required duplicating quite a bit of logic from mercurial.filemerge so
I pulled it into its own module. This new module could be copied for
handling terminals.

  • Participants
  • Parent commits 0f7ddc9

Comments (0)

Files changed (2)

tortoisehg/hgqt/qtlib.py

 from mercurial.i18n import _ as hggettext
 from mercurial import commands, extensions, error, util
 
-from tortoisehg.util import hglib, paths
+from tortoisehg.util import hglib, paths, editor
 from tortoisehg.hgqt.i18n import _
 from hgext.color import _styles
 
         qurl = QUrl.fromLocalFile(path)
     return QDesktopServices.openUrl(qurl)
 
-def detecteditor(ui):
-    editor = ui.config('tortoisehg', 'editor')
-    if not editor:
-        editor = os.environ.get('HGEDITOR') or repo.ui.config('ui', 'editor') \
-                 or os.environ.get('EDITOR', 'vi')
-    return editor
-
 def openfiles(repo, files, parent=None):
     for filename in files:
         openlocalurl(repo.wjoin(filename))
         files = [os.path.basename(path)]
     else:
         cwd = repo.root
-    files = [util.shellquote(util.localpath(f)) for f in files]
-    assert len(files) == 1 or lineno == None
 
-    editor = detecteditor(repo.ui)
-    if os.path.basename(editor) in ('vi', 'vim', 'hgeditor'):
+    toolpath, args = editor.detecteditor(repo, files)
+    if os.path.basename(toolpath) in ('vi', 'vim', 'hgeditor'):
         res = QMessageBox.critical(parent,
                     _('No visual editor configured'),
                     _('Please configure a visual editor.'))
         dlg.exec_()
         return
 
-    cmdline = ' '.join([editor] + files)
+    files = [util.shellquote(util.localpath(f)) for f in files]
+    assert len(files) == 1 or lineno == None
+    cmdline = ' '.join([toolpath] + files)
+
     try:
         regexp = re.compile('\[([^\]]*)\]')
         expanded = []
         pos = 0
-        for m in regexp.finditer(editor):
-            expanded.append(editor[pos:m.start()-1])
-            phrase = editor[m.start()+1:m.end()-1]
+        for m in regexp.finditer(args):
+            expanded.append(args[pos:m.start()-1])
+            phrase = args[m.start()+1:m.end()-1]
             pos = m.end()+1
             if '$LINENUM' in phrase:
                 if lineno is None:
                 phrase = phrase.replace('$FILE', files[0])
                 files = []
             expanded.append(phrase)
-        expanded.append(editor[pos:])
-        cmdline = ' '.join(expanded + files)
+        expanded.append(args[pos:])
+        cmdline = ' '.join([toolpath] + expanded + files)
     except ValueError, e:
         # '[' or ']' not found
         pass

tortoisehg/util/editor.py

+import shlex
+import os
+from mercurial import util, match
+
+def _toolstr(ui, tool, part, default=""):
+    return ui.config("editor-tools", tool + "." + part, default)
+
+def _findtool(ui, tool):
+    for kn in ("regkey", "regkeyalt"):
+        k = _toolstr(ui, tool, kn)
+        if not k:
+            continue
+        p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
+        if p:
+            p = util.findexe(p + _toolstr(ui, tool, "regappend"))
+            if p:
+                return p
+    exe = _toolstr(ui, tool, "executable", tool)
+    return util.findexe(util.expandpath(exe))
+
+def _findeditor(repo, files):
+    '''returns tuple of editor name and editor path.
+
+    tools matched by pattern are returned as (name, toolpath)
+    tools detected by search are returned as (name, toolpath)
+    tortoisehg.editor is returned as         (None, tortoisehg.editor)
+    HGEDITOR or ui.editor are returned as    (None, ui.editor)
+
+    So first return value is an [editor-tool] name or None and
+    second return value is a toolpath or user configured command line
+    '''
+    ui = repo.ui
+
+    # first check for tool specified by file patterns.  The first file pattern
+    # which matches one of the files being edited selects the editor
+    for pat, tool in ui.configitems("editor-patterns"):
+        mf = match.match(repo.root, '', files)
+        toolpath = _findtool(ui, tool)
+        if mf(path) and toolpath:
+            return (tool, util.shellquote(toolpath))
+
+    # then editor-tools
+    tools = {}
+    for k, v in ui.configitems("editor-tools"):
+        t = k.split('.')[0]
+        if t not in tools:
+            tools[t] = int(_toolstr(ui, t, "priority", "0"))
+    names = tools.keys()
+    tools = sorted([(-p, t) for t, p in tools.items()])
+    editor = ui.config('tortoisehg', 'editor')
+    if editor:
+        if editor not in names:
+            # if tortoisehg.editor does not match an editor-tools entry, take
+            # the value directly
+            return (None, editor)
+        # else select this editor as highest priority (may still use another if
+        # it is not found on this machine)
+        tools.insert(0, (None, editor))
+    for p, t in tools:
+        toolpath = _findtool(ui, t)
+        if toolpath:
+            return (t, util.shellquote(toolpath))
+
+    # fallback to potential CLI editor
+    editor = os.environ.get('HGEDITOR') or repo.ui.config('ui', 'editor') \
+             or os.environ.get('EDITOR', 'vi')
+    return (None, editor)
+
+def detecteditor(repo, files):
+    'returns tuple of editor tool path and arguments'
+    name, pathorconfig = _findeditor(repo, files)
+    if name is None:
+        cmds = shlex.split(pathorconfig)
+        toolpath = cmds[0]
+        args = ' '.join(cmds[1:])
+    else:
+        toolpath = pathorconfig
+        args = _toolstr(repo.ui, name, "args")
+    return toolpath, args