110 lines
7.1 KiB
Plaintext
110 lines
7.1 KiB
Plaintext
<h2>You Ain't Emacs-ing if You Ain't Always Hacking Your Config</h2>
|
||
<p><time datetime="2021-11-05" title="2021-11-05">Earlier</time> I wrote <span><cite><a class="u-url" href="https://takeonrules.com/2021/11/05/emacs-function-to-open-magit-log-pr-at-point/">Emacs Function to Open Magit Log PR at Point</a></cite></span>. Over on <a href="https://www.reddit.com/r/emacs/comments/qlpvgu/weekly_tips_tricks_c_thread/hk2wnv1/?context=3">Reddit</a>, a user asked about not requiring <code>git-link</code> dependency nor <code>browse-url-default-macosx-browser</code>.</p>
|
||
<p>Since then, I’ve split apart the functions and added another use case. First and foremost, the magic “open the pull request associated with a commit” relies on an implementation feature of Github’s “Squash and merge” command. That command creates a commit with a summary (e.g., the first line of the commit message) that is the pull request’s title and the associated pull request.</p>
|
||
<h2 id="functions">Functions</h2>
|
||
<p>With that as a caveat, there are five functions that I’ve written to help jump to pull requests on Github:</p>
|
||
<ul>
|
||
<li><code>jnf/git-current-remote-url</code></li>
|
||
<li><code>jnf/open-pull-request-for</code></li>
|
||
<li><code>jnf/magit-browse-pull-request</code></li>
|
||
<li><code>jnf/open-pull-request-for-current-line</code></li>
|
||
<li><code>jnf/git-messenger-popup</code></li>
|
||
</ul>
|
||
<h3 id="jnfgit-current-remote-url">jnf/git-current-remote-url</h3>
|
||
<p>The following <span>
|
||
<span>Elisp: dialect of Lisp used in GNU Emacs</span> (<abbr title="Elisp: dialect of Lisp used in GNU Emacs">Elisp</abbr> <small><a class="ref" href="https://takeonrules.com/site-map/glossary/#abbr-dfn-ELISP" rel="tag opener" title="Other site-wide references of “Elisp: dialect of Lisp used in GNU Emacs”">🔍</a></small>)</span> code defines the <code>jnf/git-current-remote-url</code> function which gets the current remote url (for the given branch).<span class="sidenote-number"><small class="side">
|
||
It’s usually “origin.”
|
||
</small></span>
|
||
</p>
|
||
<pre><code>
|
||
(defun jnf/git-current-remote-url ()
|
||
"Get the current remote url."
|
||
(s-trim
|
||
(shell-command-to-string
|
||
(concat
|
||
"git remote get-url "
|
||
(format "%s" (magit-get-current-remote))))))
|
||
</code></pre>
|
||
<h3 id="jnfopen-pull-request-for">jnf/open-pull-request-for</h3>
|
||
<p>The following elsip code defines <code>jnf/open-pull-request-for</code>, which takes the named parameter <code>:summary</code>. If that <code>:summary</code> contains a pull request number, opens the pull request in an external browser.</p>
|
||
<pre><code>
|
||
(cl-defun jnf/open-pull-request-for (&key summary)
|
||
"Given the SUMMARY open the related pull request."
|
||
(let ((remote-url (jnf/git-current-remote-url)))
|
||
(save-match-data
|
||
(and (string-match "(\\#\\([0-9]+\\))$" summary)
|
||
(eww-browse-with-external-browser
|
||
(concat
|
||
;; I tend to favor HTTPS and the
|
||
;; repos end in ".git"
|
||
(s-replace ".git" "" remote-url)
|
||
"/pull/"
|
||
(match-string 1 summary)))))))
|
||
</code></pre>
|
||
<h3 id="jnfmagit-browse-pull-request">jnf/magit-browse-pull-request</h3>
|
||
<p>The following <abbr title="Elisp: dialect of Lisp used in GNU Emacs">Elisp</abbr> code defines <code>jnf/magit-browse-pull-request</code>, which will open the associate pull request when your point is on a <span>
|
||
<span>Magit</span> <small><a class="ref" href="https://takeonrules.com/site-map/glossary/#abbr-dfn-MAGIT" rel="tag opener" title="Other site-wide references of “Magit”">🔍</a></small></span> log entry.<span class="sidenote-number"><small class="side">
|
||
I’ve mapped that to <code>s-6</code> (or <kbd>Cmd</kbd>+<kbd>6</kbd>)
|
||
</small></span>
|
||
</p>
|
||
<pre><code>
|
||
(defun jnf/magit-browse-pull-request ()
|
||
"In `magit-log-mode' open the associated pull request
|
||
at point.
|
||
|
||
Assumes that the commit log title ends in the PR #, which
|
||
is the case when you use the Squash and Merge strategy.
|
||
|
||
This implementation is dependent on `magit' and `s'."
|
||
(interactive)
|
||
(let* ((beg (line-beginning-position))
|
||
(end (line-end-position))
|
||
(summary
|
||
(buffer-substring-no-properties
|
||
beg end)))
|
||
(jnf/open-pull-request-for :summary summary)))
|
||
</code></pre>
|
||
<h3 id="jnfopen-pull-request-for-current-line">jnf/open-pull-request-for-current-line</h3>
|
||
<p>The following <abbr title="Elisp: dialect of Lisp used in GNU Emacs">Elisp</abbr> code defines <code>jnf/open-pull-request-for-current-line</code>. When invoked, this function will open the pull request for the commit associated with the current line.<span class="sidenote-number"><small class="side">
|
||
It does that by using <code>git annotate</code> on the current line, and pulling the commit’s summary via <code>ripgrep</code>.
|
||
</small></span>
|
||
</p>
|
||
<pre><code>
|
||
(defun jnf/open-pull-request-for-current-line ()
|
||
"For the current line open the applicable pull request."
|
||
(interactive)
|
||
(let ((summary
|
||
(s-trim
|
||
(shell-command-to-string
|
||
(concat "git --no-pager annotate "
|
||
"-L "
|
||
(format "%s" (line-number-at-pos))
|
||
",+1 "
|
||
"--porcelain "
|
||
buffer-file-name
|
||
" | rg \"^summary\"")))))
|
||
(jnf/open-pull-request-for :summary summary)))
|
||
</code></pre>
|
||
<h3 id="jnfgit-messenger-popup">jnf/git-messenger-popup</h3>
|
||
<p>The following <abbr title="Elisp: dialect of Lisp used in GNU Emacs">Elisp</abbr> code defines <code>jnf/git-messenger-popup</code>. When invoked it launches the <a href="https://github.com/emacsorphanage/git-messenger">git-messenger</a> popup.</p>
|
||
<pre><code>
|
||
(defun jnf/git-messenger-popup ()
|
||
"Open `git-messenger' or github PR.
|
||
|
||
With universal argument, open the github PR for
|
||
current line.
|
||
|
||
Without universal argument, open `git-messenger'."
|
||
(interactive)
|
||
(if (equal current-prefix-arg nil) ; no C-u
|
||
(git-messenger:popup-message)
|
||
(jnf/open-pull-request-for-current-line)))
|
||
</code></pre>
|
||
<p>I have mapped the function to <code>s-6</code> (e.g., <kbd>Cmd</kbd>+<kbd>6</kbd> on <span><abbr title="Macintosh Operating System X">OS X</abbr> <small><a class="ref" href="https://takeonrules.com/site-map/glossary/#abbr-dfn-OSX" rel="tag opener" title="Other site-wide references of “Macintosh Operating System X”">🔍</a></small></span>).</p>
|
||
<p>If I first pass the universal argument, that is I first type <code>C-u</code> then <code>s-6</code> (or <kbd>Ctrl</kbd>+<kbd>u</kbd> then <kbd>Cmd</kbd>+<kbd>6</kbd> in <abbr title="Macintosh Operating System X">OS X</abbr>) I will open that line’s pull request.<span class="sidenote-number"><small class="side">
|
||
When in the git-messenger’s popup, I can type <kbd>p</kbd> to go to that line’s pull request.
|
||
</small></span>
|
||
</p>
|
||
<h2 id="conclusion">Conclusion</h2>
|
||
<p>I wrote these functions to better help me better understand <a href="https://github.com/forem/forem">Forem’s codebase</a>. It was also a chance to continue practicing coding and learning.</p>
|
||
<p>If you’re interested, you can see more of <a href="https://github.com/jeremyf/dotemacs/blob/main/jnf-emacs-packages/jnf-git.el">my git configuration on Github</a></p> |