From: NeilBrown Date: Sat, 30 Sep 2023 22:59:55 +0000 (+1100) Subject: Start git-mode: selection menu item to view git commit. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=4d4a1af6b995578be5516f4cc36e6927eadb637f;p=edlib.git Start git-mode: selection menu item to view git commit. 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 --- diff --git a/DOC/TODO.md b/DOC/TODO.md index fdb26f7f..9e9ddc01 100644 --- a/DOC/TODO.md +++ b/DOC/TODO.md @@ -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 diff --git a/data/modules.ini b/data/modules.ini index dbe6e3c5..f4cf1a2a 100644 --- a/data/modules.ini +++ b/data/modules.ini @@ -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 diff --git a/mode-emacs.c b/mode-emacs.c index 947e0542..8e570cc6 100644 --- a/mode-emacs.c +++ b/mode-emacs.c @@ -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 index 00000000..33572c6d --- /dev/null +++ b/python/lib-git.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- +# Copyright Neil Brown ©2023 +# 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) diff --git a/python/lib-shellcmd.py b/python/lib-shellcmd.py index e98a4ad0..3a65df6a 100644 --- a/python/lib-shellcmd.py +++ b/python/lib-shellcmd.py @@ -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: