]> git.neil.brown.name Git - edlib.git/commitdiff
Start git-mode: selection menu item to view git commit.
authorNeilBrown <neil@brown.name>
Sat, 30 Sep 2023 22:59:55 +0000 (09:59 +1100)
committerNeilBrown <neil@brown.name>
Sun, 1 Oct 2023 09:37:37 +0000 (20:37 +1100)
The selection menu now has a "git view" entry. If the seleciton is a git
commit hash which can be found in a visited directory, then show it.

Signed-off-by: NeilBrown <neil@brown.name>
DOC/TODO.md
data/modules.ini
mode-emacs.c
python/lib-git.py [new file with mode: 0644]
python/lib-shellcmd.py

index fdb26f7fd14adb044cfac9d251fa3d35f82c489b..9e9ddc017a4d46b691831c7362d3644538ee172e 100644 (file)
@@ -24,7 +24,7 @@ the file.
 - [X] Add menubar menu with recent documents?
 - [X] why does clicking on status line go to top-of-file?
 - [X] search hangs when seeking "^( *)"
-- [ ] selection-menu item to show git-commit from list of known git
+- [X] selection-menu item to show git-commit from list of known git
       trees
 - [ ] selection-menu item for word-count
 - [ ] selection-menu item for QR-code
@@ -762,6 +762,7 @@ Module features
 
 ### git-mode
 
+- [ ] configure list of known git repos
 - [ ] log view (:C-c l?) which uses --max-count and --skip to only
       collect enough log entries to fill the display.  Or better: have a
       shell mode which only reads from pipe if insertion position is
index dbe6e3c5ccf8c0e77a743e40ca670a512576bb55..f4cf1a2a0ad693d597639830bf3121f2ce139d5f 100644 (file)
@@ -168,3 +168,8 @@ lib-menubar =
 
 lib-rangetrack = rangetrack:new
 render-imageview = attach-render-imageview
+
+lib-git =
+       doc:appeared-git
+       selection-menu:add-02-git
+       git:view-selected-commit
index 947e05426993d692d67c067f0035284a55e0c0b6..8e570cc6bc7c69734d9a15900cb599cf00881e67 100644 (file)
@@ -2376,7 +2376,6 @@ DEF_CMD(emacs_selection_menu)
 {
        struct pane *p;
 
-       call("Message", ci->focus, 0, NULL, "So .... you want a menu do you?");
        p = call_ret(pane, "attach-menu", ci->focus, 0, NULL, "V", 0, NULL,
                     "emacs:selection-menu-action", ci->x, ci->y+1);
        if (!p)
@@ -2409,7 +2408,7 @@ DEF_CMD(emacs_selection_menu_add)
        call("menu-add", p, 0, NULL, "Cut", 0, NULL, ":C-W");
        call("menu-add", p, 0, NULL, "Copy", 0, NULL, ":A-w");
        call("menu-add", p, 0, NULL, "Paste-in", 0, NULL, ":C-Y");
-       return 1;
+       return Efallthrough;
 }
 
 DEF_CMD(emacs_goto_line)
diff --git a/python/lib-git.py b/python/lib-git.py
new file mode 100644 (file)
index 0000000..33572c6
--- /dev/null
@@ -0,0 +1,115 @@
+# -*- coding: utf-8 -*-
+# Copyright Neil Brown ©2023 <neil@brown.name>
+# May be distributed under terms of GPLv2 - see file:COPYING
+#
+# Various support for working with git repos.
+#
+# Maintain a list of known git repos.  These can be configured, or
+# added when a directory containing ".git" is added.  These are simply
+# directory docs (found by docs:foreach) with a "git-root" attribute set.
+#
+# Provide selection-menu item which treats selection as a git hash,
+# finds a repo which knowns of that hash, and shows it in a popup.
+#
+
+from edlib import *
+from subprocess import *
+import os.path
+import re
+
+def git_appeared(key, focus, **a):
+    t = focus['doc-type']
+    if not t or t != 'dir':
+        return Efallthrough
+    f = focus['filename']
+    if not f:
+        return Efallthrough
+    p = os.path.join(f, ".git")
+    if os.path.isdir(p):
+        focus['git-root'] = "yes"
+        return Efallthrough
+    if os.path.isfile(p):
+        try:
+            f = open(p)
+        except:
+            return Efallthrough
+        l = f.readlines()
+        if l and len(l) >= 1 and l[0].startswith("gitdir: "):
+            focus['git-root'] = l[0][8:].strip()
+
+    return Efallthrough
+
+def git_selection_menu(key, focus, **a):
+    focus.call("menu-add", "Git-view", " git:view-selected-commit")
+    return Efallthrough
+
+def git_view_commit(key, focus, mark, **a):
+    pt,mk = focus.call("doc:point", ret='marks')
+
+    if not pt or not mk:
+        return 1
+    focus.call("selection:claim")
+    focus.call("selection:discard")
+    cm = focus.call("doc:get-str", pt, mk, ret='str')
+    if not cm:
+        return 1;
+    if not re.match("g?[0-9a-fA-F]{5,}$", cm):
+        if '\n' in cm:
+            focus.call("Message:modal",
+                       "multi-line selection is not a valid git hash")
+        else:
+            focus.call("Message:modal", "\"%s\" is not a valid git hash" % cm)
+        return 1
+    if cm[0] == 'g':
+        cm = cm[1:]
+
+    choice = []
+    def choose(choice, a):
+        focus = a['focus']
+        root = focus['git-root']
+        if not root:
+            return 1
+        if root == "yes":
+            root = os.path.join(focus['filename'], ".git")
+        env = os.environ.copy()
+        env['GIT_DIR'] = root
+        p = Popen(["/usr/bin/git", "describe", "--always", cm], env=env,
+                         stdin=DEVNULL, stdout=DEVNULL, stderr=DEVNULL)
+        if not p:
+            return 1
+        try:
+            p.communicate(timeout=5)
+        except TimeoutExpired:
+            p.kill()
+            p.communicate()
+            return 1
+        if p.returncode != 0:
+            return 1
+        choice.append(focus)
+        # only need one - stop now
+        return False
+    focus.call("docs:byeach", lambda key,**a:choose(choice, a))
+    if len(choice):
+        pop = focus.call("PopupTile", "DM3sta", ret='pane')
+        if not pop:
+            focus.call("Message:modal", "popup failed")
+            return 1
+        doc = focus.call("doc:from-text", "*GIT view*", "", ret='pane')
+        if not doc:
+            pop.call("popup:close")
+            focus.call("Message:modal", "doc:from-text failed")
+            return 1
+        dir = choice[0]['filename']
+        doc.call("doc:replace", "In GIT repository: %s\n" % dir);
+        doc.call("attach-shellcmd", 2, "git show "+cm, dir)
+        doc['view-default'] = "diff"
+        doc.call("doc:attach-view", pop, 1)
+        focus.call("Message:modal", "Commit %s found in %s" % (cm, dir))
+    else:
+        focus.call("Message:modal", "Cannot find git commit " + cm)
+    return 1
+
+editor.call("global-set-command", "doc:appeared-git", git_appeared)
+editor.call("global-set-command", "selection-menu:add-02-git",
+                  git_selection_menu)
+editor.call("global-set-command", "git:view-selected-commit", git_view_commit)
index e98a4ad0cdd2cc981d7eb0e4b7d037075acdcef6..3a65df6a6dba4eeb24998244682904593437de37 100644 (file)
@@ -252,6 +252,8 @@ def shell_attach(key, focus, comm2, num, str, str2, **a):
     if not p:
         return edlib.Efail
     focus['view-default'] = 'shell-viewer'
+    if str2:
+        focus['dirname'] = str2
     try:
         p.call("shell-run", num&1, num & 16, str, str2)
     except edlib.commandfailed: