consult-gh icon indicating copy to clipboard operation
consult-gh copied to clipboard

An Interactive interface for "GitHub CLI" client inside GNU Emacs using Consult

#+include: ~/OrgFiles/armin/org-macros.setup #+OPTIONS: h:1 num:nil toc:nil d:nil

#+TITLE: Consult-GH - A [[https://cli.github.com/][GitHub CLI]] client inside GNU Emacs using [[https://github.com/minad/consult][Consult]] #+AUTHOR: Armin Darvish #+LANGUAGE: en

#+html: Armin Darvish #+html: GNU Emacs

NOTICE: Around Oct. 10th, 2023 there was a major update to use consult-async. This required reimplementing the package from scratch and may break old version. In the new version, there are many new features and functionalities inclduing:

  • async search, i.e. dynamic update of completion table as user enters an entry
  • dynamically add additional command line arguments in the minibuffer
  • search pull requests and codes
  • when searching codes, can open files and jump to the code in an emacs buffer
  • highlight relevant search terms, code snippets, etc. in preview buffers
  • transient menu to quickly find the desired interactive command or settings
  • ...

You can learn about all the new functionalities below. If you prefer to use the old version, you can find it under the branch "v0.12" or in this release: [[https://github.com/armindarvish/consult-gh/releases/tag/0.12][release v0.12]]

  • About Consult-GH

** Main Functions and Interactive Commands Consult-GH provides an interface to interact with GitHub repositories (search, view files and issues, clone, fork, ...) from inside Emacs. It uses the awesome package [[https://github.com/minad/consult][consult]] by [[https://github.com/minad][Daniel Mendler]] and [[https://cli.github.com/][GitHub CLI]] and optionally [[https://github.com/oantolin/embark][Embark]] by [[https://github.com/oantolin][Omar Antolín Camarena]], and provides an intuitive UI using minibuffer completion familiar to Emacs users.

Consult-GH offers the following "MAIN" interactive commands

List Repos, Issues or PRs:

  1. =consult-gh-repo-list=: Finds repositories for a given GitHub user/organization, similar to running =gh repo list= in the command line.
  2. =consult-gh-issue-list=: Lists issues of a given GitHub repository, similar to running =gh issue list= in the command line.
  3. =consult-gh-pr-list=: Lists pull requests of a given GitHub repository, similar to running =gh pr list= in the command line.

Search Functions:

  1. =consult-gh-search-repos=: Search github repositories, similar to running =gh search repos= in the command line.
  2. =consult-gh-search-issues=: Search github issues, similar to running =gh search issues= in the command line.
  3. =consult-gh-search-prs=: Search github pull requests, similar to running =gh search prs= in the command line.
  4. =consult-gh-search-code=: Search for code on github, similar to running =gh search code= in the command line.

Browse File Contents:

  1. =consult-gh-find-file=: Find files within any branch of any repository.

Quickly See Repositories of Favorite Users/Organizations:

  1. =consult-gh-default-repos=: This calls =consult-gh-repo-list= on a defined default list of orgs stored in variable =consult-gh-default-orgs-list= for quick access to frequently used repositories. This can for example be useful for accessing your own repositories (in multiple accounts) quickly.

Clone or Fork Repos:

  1. =consult-gh-repo-clone=: Quickly clone a repository with just typing the name of the repository. This function has a post-hook =consult-gh-repo-post-clone-hook= that cna be used for example to switch o appropriate directory, etc.
  2. =consult-gh-repo-fork=: Quickly fork one or more repositories. This function also has a post-hook =consult-gh-repo-post-fork-hook=, that cna be used for example to clone the forked repository.

Furthermore, Consult-GH, also provides a number of useful [[https://github.com/oantolin/embark][Embark]] actions (see examples below.)

** Why Use Consult-GH? While there are several packages for interacting with GitHub and GitHub API such as [[https://github.com/sigma/gh.el][gh.el]], [[https://github.com/magit/ghub][magit/ghub]] and [[https://github.com/magit/forge][magit/forge]], [[https://github.com/sshaw/git-link][git-link]], [[https://github.com/rmuslimov/browse-at-remote][browse-at-remote]], and ... in my opinion none of these packages provide an intuitive UI to interact with GitHub repositories. Some of these are a collection of low-level API calls without user-friendly interactive commands and others simply retrieve a URL in the browser instead of providing GitHub interface inside Emacs. As a result, the user either has to implement their own functions to use the API calls or simply jump to the browser to interact with GitHub. Consult-GH aims to fill this gap and provide a tool that allows the user to interact with GitHub from within Emacs.

Note that currently Consult-GH does not provide interactive commands to manage issues or pull request mainly because those functionalities are already available in other packages or tools. Personally, I like to use Consult-GH for searching repositories, browsing issues or view/download files without cloning entire repositories, etc. and use a package like [[https://github.com/magit/forge][magit/forge]] for managing issues, pull requests, etc. That said, I am open to including managing issues, pull requests or releases if there is a clear advantage in offering that as part of Consult-GH.

  • Getting Started ** Installation Before you start, make sure you understand that this is work in progress in its early stage and bugs and breaks are very much expected so use this at your own risk. *** Requirements In order to use Consult-GH, you need the following requirements:

**** [[https://github.com/cli/cli][GitHub CLI]] To install GitHub CLI, follow the official documentations here: [[https://github.com/cli/cli#installation][GitHub CLI Installation]]. Make sure you are logged in by running =gh auth login= and following the instructions. Refer to the official manual if you need further help, [[https://cli.github.com/manual/][GitHub CLI Manual]].

Why use gh instead of other Emacs packages? While there are other Emacs packages to interact with GitHub API, we use "gh" commandline tool as the backend instead of direct calls to REST API or GraphQL, and this is very much intentional. By leaving API functionalities to the official GitHub CLI tool, we simplify usage (no need to set up authentication within Emacs), reduce security risks (no risk of exposing authentication tokens, ...) and increase maintainability (no need to keep compatibility with API changes).

**** [[https://github.com/minad/consult][Consult]] To install consult follow the official instructions here: [[https://github.com/minad/consult#configuration][Configuration of Consult.]]

Also, make sure you review Consult's README since it recommends some other packages and useful configurations for different settings. Some of those may improve your experience of Consult-GH as well. In particular the section about [[https://github.com/minad/consult#asynchronous-search][asynchronous search]] is important for learning how to use inputs to search for result and narrow down in minibuffer.

**** [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Parsing-JSON.html][json library]] in Emacs As of Emacs 27, json is available as built-in if Emacs is compiled with json. You can run the command =json-available-p= to see if it is available in your version of Emacs. If json is not available you may still be able to use Consult-GH with limited functionality (for example you cannot view file contents).

*** Recommended (but not required) packages The following packages are not strictly required for Consult-GH to work, but it can improve your experience depending on your use-case.

**** [[https://github.com/jrblevin/markdown-mode][markdown-mode]] Since =gh= returns information in markdown, installing [[https://github.com/jrblevin/markdown-mode][markdown-mode]] can significantly improve your experience (e.g. readability of previews, etc.). When =markdown-mode= is available, by default Consult-GH will use it as major mode to show previews of READMEs, otherwise it will be in raw text in =fundamental mode=.

*** Installing Consult-GH Package Consult-GH is not currently on [[https://elpa.gnu.org/packages/consult.html][ELPA]] or [[https://melpa.org/#/consult][MELPA]]. Therefore, you need to install it using an alternative non-standard package managers such as [[https://github.com/radian-software/straight.el][straight.el]] or use manual installation.

**** straight.el To install Consult-GH with straight.el you can use the following command. Make sure you load consult-gh after loading consult (e.g. =require consult=)

#+begin_src emacs-lisp (straight-use-package '(consult-gh :type git :host github :repo "armindarvish/consult-gh" :branch "main")) #+end_src

or if you use =use-package= macro with straight, you can do:

#+begin_src emacs-lisp (use-package consult-gh :straight (consult-gh :type git :host github :repo "armindarvish/consult-gh" :after consult) ) #+end_src

You can also fork this repository and use your own repo.

**** manual installation Clone this repo and make sure the files are on your load path, as described on [[https://www.emacswiki.org/emacs/LoadPath][EmacsWiki]].

Make sure you load consult (e.g. =require consult=) before you load consult-gh.

** Configuration Consult-GH is built with the idea that the user should be able to customize everything based on their use-case. In fact, the default configurations are minimal and prioritize performance over usability, therefore the user is very much expected to configure Consult-GH according to their use case. For example, with the default configuration, when selecting a repository, Consult-GH opens the link in a browser, but you can configure the package to show the README inside Emacs or do something else (e.g. clone the repository). Therefore, I recommend you read through this section and understand how to configure the package according to your needs and for your specific use-case, but if you just want a drop-in minimal config, look at the snippet below and make sure you set the =consult-gh-default-orgs-list= to your own GitHub username instead of "armindarvish":

#+begin_src emacs-lisp (use-package consult-gh :straight (consult-gh :type git :host github :repo "armindarvish/consult-gh")

:config ;;add your main GitHub account (replace "armindarvish" with your user or org) (add-to-list 'consult-gh-default-orgs-list "armindarvish")

;;use "gh org list" to get a list of all your organizations and adds them to default list (setq consult-gh-default-orgs-list (append consult-gh-default-orgs-list (remove "" (split-string (or (consult-gh--command-to-string "org" "list") "") "\n"))))

;; set the default folder for cloning repositories, By default Consult-GH will confirm this before cloning (setq consult-gh-default-clone-directory "~/") )

#+end_src The configuration above adds "armindarvish" to the default orgs (used by =consult-gh-default-repos= so you can quickly see all your repositories.

*** Customization The following customizable variables are provided:

**** =consult-gh-tempdir= This is where temporary files are saved. By default, this is set to your system temporary directory (=temporary-file-directory= variable in Emacs). Consult-GH uses this folder to store temporary files (such as files you are previewing).

**** =consult-gh--repo-maxnum= This is the limit passed to =gh= as =--limit= argument to =gh repo list= or =gh search repos= commands and defines the number of repos shown when listing or searching repos. By default, it is set to 30 following the default values of =gh= itself, but it can be customized by the user to see more or fewer results.

Note that, this is a global setting, but since the update to v2, the user can add additional command line arguments in the minibuffer, and therefore adding the command line argument (e.g. =-- -L 100=) in the minibuffer will dynamically override this setting. See [[id:0AAC346E-481A-48AB-B7DA-1569EBA4A145][Features and Demos]] for screenshots and examples.

**** =consult-gh--issue-maxnum= This is the limit passed to =gh= as =--limit= argument to =gh issue list= or =gh search issues= commands and defines the number of issues shown when listing or searching for issues. By default, it is set to 30 following the default values of =gh= itself, but it can be customized by the user to see more or fewer results.

Similar to consult-gh--repo-maxnum, this can be overridden by passing command line arguments directly in the minibuffer (e.g. adding =-- -L 100= in the minibuffer entry).

**** =consult-gh--pr-maxnum= Similar to consult-gh--issue-maxnum but for pull requests. **** =consult-gh--code-maxnum= Similar to maxnum variables above but for codes (for example search results for code i.e. =gh search code=).

**** =consult-gh-large-file-warning-threshold= This is the maximum file size, above which =consult-gh= requests a confirmation for previewing, opening or saving the file. Default value is set by emacs built-in =large-file-warning-threshold= variable, but since =consult-gh= is downloading files from the internet, you may want to set this to a smaller value than =large-file-warning-threshold= depending on your network performance.

**** =consult-gh-prioritize-local-folder=

This varibale defines whther =gh= uses the git repo in the local folder to select/guess the repository for commands like =consult-gh-find-file= and =consult-gh-issue-list=, etc. Note that everything is still retrieved from the remote (for example =consult-gh-find-file= would fetch the contents of the repo from remote and not from the local folder) but the local repo name is used instead of querying the user. You can set this varibale to ='suggest=, =t=, or =nil=

  • 'suggest simply adds the local repo name as initial input in the minibuffer so you don't have to type it out.
  • t would skip the query and uses the local repo name, if any, otherwise it falls back to querying the user.
  • nil would not suggest the local repo name as initial-input but instead uses it as default value. That means the local repo is added to the end of history list (accessible by default keybinding =M-n=).

**** =consult-gh--issues-state-to-show= The state of issues shown when listing or searching for issues. This is the string passed as =--state= argument to =gh search issues= or =gh issue list= and can accept =open=, =closed= or =all= for open, closed or all issues, respectively.

Note that, this is a global setting, but since the update to v2, the user can add additional command line arguments in the minibuffer, and therefore adding the command line argument (e.g. =-- --state closed=) in the minibuffer will dynamically override this setting. See [[id:0AAC346E-481A-48AB-B7DA-1569EBA4A145][Features and Demos]] for screenshots and examples.

**** =consult-gh--issues-state-to-show= Similar to consult-gh--issues-state-to-show but for pull requests. This is the string passed as =--state= argument to =gh search prs= or =gh pr list= and can accept =open=, =merged=, =closed= or =all= for open, merged, closed or all pull requests, respectively.

**** =consult-gh-default-orgs-list= This is a list of default organizations you want to access frequently. I set this variable to organizations I am part of (a.k.a. to look at my own repositories) but you can add any account you want to look at frequently to this list. Here is an example of setting the default list to "alphapapa" and "systemcrafters":

#+begin_src emacs-lisp (setq consult-gh-default-orgs-list '("alphapapa" "systemcrafters")) #+end_src

or if you want to append to the list:

#+begin_src emacs-lisp (setq consult-gh-default-orgs-list (append consult-gh-default-orgs-list '("alphapapa" "systemcrafters"))) #+end_src

**** =consult-gh-preview-buffer-mode= This is the major-mode used to show repository previews. By default, it is set to =markdown-moe= because =gh repo view= returns the README contents (commonly in markdown syntax). But if you prefer to see the contents in =org-mode= format, you can set this variable to ='org-mode=. Be aware that currently, the org-mode conversion is done with some simple regex replacements and while the performance is decent and the converted version is perfectly understandable, the org conversion may cause some inaccuracies. If you want to try this you can do:

#+begin_src emacs-lisp (setq consult-gh-preview-buffer-mode 'org-mode) #+end_src

**** =consult-gh-show-preview= This variable is a boolean determining whether Consult-GH shows previews or not. By default, this is set to nil because loading repository views or file contents can be resource-heavy depending on the size of the content. Therefore, it is left to the user to intentionally turn this feature on if it is suitable for their use-case and their setup.

Note that getting previews makes an API call to GitHub and downloads contents of a file. When =consult-gh-show-preview= is set to =nil= (default setting), no API call is made (no resources used) and no preview will be available either. This might be a useful configuration if you only want to see the name of repositories or issues and do actions such as cloning, forking or getting links, or jumping to urls in the browser but not for viewing files or issues within Emacs.

If you want to be able to get a preview on demand without turning previews on globally, then look at =consult-gh-preview-key= below.

**** =consult-gh-preview-key= This is similar to =consult-preview-key= but only for =consult-gh=. By default, it is set to the value of consult-preview-key to keep consistent experience across different consult packages, but you can set this variable explicitly for consult-gh. For example, if you have turned preview on by setting =consult-gh-show-preview= to =t=, but you still only want to see previews on demand, you can set =consult-gh-preview-key= to the key binding that shows the preview. Here is an example using =M-o= as preview key. With this setting, previews are shown only when you hit =meta+o=.

#+begin_src emacs-lisp (setq consult-gh-show-preview t) (setq consult-gh-preview-key "M-o") #+end_src

Be aware that getting previews is resource heavy since it has to make an API call to GitHub and download contents of a file. If you set a specific key for =consult-gh-preview-key=, this API call and downloading the content is done only when you hit the key binding.

**** =consult-gh-confirm-name-before-fork= This is a boolean determining whether Consult-GH asks for a repo name before forking a repository. By default, it is set to =nil=, meaning that Consult-GH uses the same repo name when forking. **** =consult-gh-confirm-before-clone= This is a boolean determining whether Consult-GH asks for path and directory name before cloning a repository. By default, it is set to =t=, meaning that Consult-GH asks the user for the path to clone a repository and the name to give the directory. However, if you don't want consult-gh to ask you every time you clone a repository, you can set this variable to =nil=, in which case Consult-GH clones repositories at =consult-gh-default-clone-directory= (see below) with the default name of the repository itself. Note that setting this variable to =nil= along with setting =consult-gh-default-clone-directory= to a directory where you keep all your repositories, allows quick cloning of multiple repositories. **** =consult-gh-default-clone-directory= This variable points to the directory where repositories are cloned by default. In the default settings, this is set to ="~/"= (a.k.a. user's home directory), and the user is asked for confirmation before cloning. Therefore, in the default setting no matter what this variable is, you can still choose the right path to clone each repository, but this means that you have to do this for every each repository you clone. By setting this variable to a default convenient path where you keep all your repositories, for example ="~/code/"= or ="~/projects/"= , you can minimize the effort to navigate to the right path. Keep in mind that if you do clone multiple repositories at the same time, it would be convenient to have this variable set to the right path, so you don't have to navigate to it for each repository especially if you turn =consult-gh-confirm-before-clone= to nil (see above).

**** =consult-gh-ask-for-path-before-save= This is a boolean determining whether Consult-GH asks for a path before saving a file (for single files and not cloning entire repositories). By default, it is set to =t=, meaning that Consult-GH asks the user for the path to save a file. However, if you don't want consult-gh to ask you every time you save a file, you can set this variable to =nil=, in which case Consult-GH saves files at =consult-gh-default-save-directory= (see below) with the name of the file. Note that setting this variable to =nil= along with setting =consult-gh-default-save-directory=, allows quick saving of multiple files (possibly even from different repositories).

**** =consult-gh-default-save-directory= This variable stores the default path where files are saved and by default is set to =~/Downloads=. Keep in mind that This is used for saving individual files and not for cloning entire repositories, which uses =consult-gh-default-clone-directory= (see above).

**** =consult-gh-default-branch-to-load= This variable is used for choosing a branch when viewing files within a repository. By default, it is set to ="ask"= meaning that Consult-GH will ask the user which branch to clone. If you set this to =nil=, then Consult-GH will load the HEAD of the git repository. If you set this to =confirm=, Consult-GH will ask you if you want to view the HEAD of the repository and if not will ask you to choose a branch. If you set this to any other =string=, then Consult-GH uses that string as the name of the branch and will try to load this branch. Be aware that setting this to a string is probably not a good idea since this will be used for any repository and if the branch does not exist, will cause an error.

**** =consult-gh-repo-action= This variable stores the function that is called when a repository is selected. By default, it is bound to =#'consult-gh--repo-browse-url-action= which opens the homepage of the repository in a browser. You can change it to other provided functions such as =#'consult-gh--repo-view-action= which instead fetches the README of the repository within an Emacs buffer or =#' consult-gh--repo-browse-files-action= which shows the file tree of the repository (after choosing a branch). Other provided built-in actions include =#'consult-gh--repo-clone-action= and =#'consult-gh--repo-fork-action=. You can also set this variable to any custom function as long as it follows the patterns of the built-in functions (e.g. input ARGs,...)

**** =consult-gh-issue-action= Similar to =consult-gh-repo-action= but for issues. This variable stores the default function that is called, when an issue is selected. By default, it is bound to =#'consult-gh--issue-browse-url-action= which opens the issue page in a browser. Alternatively, you can bind it to =consult-gh--issue-view-action= if you want to see the issue inside an Emacs buffer. Note that this is only for viewing issues and not interacting (adding posts, filing new issues, etc.) with them. This is mainly due to the fact that the =gh= backend itself is also limited when it comes to managing issues (interactive command line queries are not that useful!). In the future, I may add more features here, but keep in mind that for managing issues (and pull requests), we can use other packages like [[https://github.com/magit/forge][magit/forge]]. In fact, consult-gh now provides support for integration with [[https://github.com/magit/forge][magit/forge]]. You can use it by setting this variable to =#'consult-gh-forge--issue-view-action= provided in in [[./consult-gh-forge.el]] (See below for more information). **** =consult-gh-pr-action= Similar to =consult-gh-issue-action= but for pull requests. This variable stores the default function that is called, when a pull request is selected; and by default, it is bound to =#'consult-gh--pr-browse-url-action= which opens the pull request page in a browser. Alternatively, you can bind it to =consult-gh--pr-view-action= if you want to see the issue inside an Emacs buffer. Alternatively, you can use [[https://github.com/magit/forge][magit/forge]] to view pull requests if you use =#'consult-gh-forge--pr-view-action= provided in [[./consult-gh-forge.el]] (See below for more information).

**** =consult-gh-code-action= Similar to other action variables above but for code snippets. This variable stores the default function that is called, when a code (search results from =gh search code=) is selected. By default, it is bound to =#'consult-gh--code-browse-url-action= which opens the url for the file containing the code snippet in a browser. Alternatively, you can bind it to =consult-gh--code-view-action= if you want to see the file inside an Emacs buffer. Note that when you open the file in an emacs buffer, consult-gh tries to put the cursor around the relevant code snippet in the file and highlights the snippet as well. (See below for screenshots and examples).

**** =consult-gh-file-action= Similar to =consult-gh-repo-action= and =consult-gh-issue-action= but for files. This variable stores the default function that is called, when a file is selected. By default, it is bound to =#' consult-gh--files-browse-url-action= which opens the file page in a browser. Alternatively, you can bind it to other provided action functions for files such as =consult-gh--files-view-action= which opens the file in an Emacs buffer (in the right major mode as well) or =consult-gh--files-save-file-action= which allows you to save a file without cloning the entire repository. If you select multiple files, using [[*=consult-gh-crm-separator=][=consult-gh-crm-separator=]], you can even save multiple files possibly from different repositories.

**** =consult-gh-highlight-matches= This variable determines if consult-gh highlights search terms, code snippets, etc. in minibuffer or preview buffers. By default it is set to t.

*** Example Customization for Good Performance and Functionality Here is a good customization for great performance as well as functionality:

#+begin_src emacs-lisp (use-package consult-gh :straight (consult-gh :type git :host github :repo "armindarvish/consult-gh") :custom (consult-gh-default-clone-directory "~/projects") (consult-gh-show-preview t) (consult-gh-preview-key "M-o") (consult-gh-repo-action #'consult-gh--repo-browse-files-action) (consult-gh-issue-action #'consult-gh--issue-view-action) (consult-gh-pr-action #'consult-gh--pr-view-action) (consult-gh-code-action #'consult-gh--code-view-action) (consult-gh-file-action #'consult-gh--files-view-action) (consult-gh-large-file-warning-threshold 2500000) (consult-gh-prioritize-local-folder 'suggest) :config ;;add your main GitHub account (replace "armindarvish" with your user or org) (add-to-list 'consult-gh-default-orgs-list "armindarvish") (require 'consult-gh-embark) #+end_src

  • Features and Demos :PROPERTIES: :ID: 0AAC346E-481A-48AB-B7DA-1569EBA4A145 :END:

For a detailed discussion and demo, see this blog post: [[https://www.armindarvish.com/en/post/consult-gh_working_with_github_inside_emacs_in_2023_/][consult-gh_working_with_github_inside_emacs_in_2023]]. If you prefer demo videos, you can watch this [[https://www.youtube.com/playlist?list=PLLKxLZdx_YyZdW4CidqbVPJjyo396Y1cx][YouTube Playlist]].

In the screenshots below, I am using vanilla emacs and a minimal config with [[https://github.com/protesilaos/modus-themes][modus-themes]], [[https://github.com/minad/vertico][vertico]], [[https://github.com/minad/marginalia][marginalia]], [[https://github.com/minad/consult][consult]], and [[https://github.com/oantolin/embark][embark]] and this repo with the following config:

#+begin_src emacs-lisp (use-package consult-gh :straight (consult-gh :type git :host github :repo "armindarvish/consult-gh") :custom (consult-gh-repo-maxnum 30) ;;set max number of repos to 30 (consult-gh-issues-maxnum 100) ;;set max number of issues to 100 (consult-gh-show-preview t) ;;show previews (consult-gh-preview-key "M-o") ;;show previews on demand by hitting "M-o" (consult-gh-preview-buffer-mode 'org-mode) ;;show previews in org-mode (consult-gh-repo-action #'consult-gh--repo-browse-files-action) ;;open file tree of repo on selection (consult-gh-issue-action #'consult-gh--issue-view-action) ;;open issues in an emacs buffer (consult-gh-pr-action #'consult-gh--pr-view-action) ;;open pull requests in an emacs buffer (consult-gh-code-action #'consult-gh--code-view-action) ;;open files that contain code snippet in an emacs buffer (consult-gh-file-action #'consult-gh--files-view-action) ;;open files in an emacs buffer :config (add-to-list 'consult-gh-default-orgs-list "armindarvish") ;;add your GitHub user (require 'consult-gh-embark) (add-to-list 'savehist-additional-variables 'consult-gh--known-orgs-list) ;;keep record of searched orgs (add-to-list 'savehist-additional-variables 'consult-gh--known-repos-list)) ;;keep record of searched repos #+end_src ** Search for Repositories In the screenshot below, I use =consult-gh-search-repos= to search for repositories. The screenshot shows the updated capabilities with consult-async:

  • The results are dynamically updated when the entry is changed.
  • Command line arguments to =gh= can be added on demand from the minibuffer. For example entering =magit -- -L 50= will change the max number of search results fetched to 50 or =magit -- --sort forks= sorts the repositories based on number of forks,...
  • Search keywords are highlighted inside minibuffer (a visual guide to see what matches the search term)
  • Search keywords are also highlighted inside preview buffers.
  • The results can be narrowed down by adding =#= after the search keyword and additional arguments. e.g. typing =magit -- -L 70 --sort updated --order asc#forge= in the minibuffer fetches repositories matching the keyword "magit" and sorts the results by the date that the repo was updated in the ascending order, then narrows the list to the ones that contain forge.
  • narrow down can be done based on info in the repo title but also marginalia info (e.g. visibility, update date, tags, ...)

#+ATTR_ORG: :width 800px #+ATTR_LATEX: :width 800px #+ATTR_HTML: :width 800px [[https://github.com/armindarvish/consult-gh/blob/screenshots/screenshots/consult-gh-search-repos.gif]]

** Looking at Repositories of User(s) In the screenshot below, I use =consult-gh-repo-list= to find repositories of a user/organization. I also show how to add command line arguments from the minibuffer. For example entering =alphapapa -- --limit 200 --cource= shows repositories belonging to "alphapapa" and limits the total number of results to 200, and then filters the results to only show the repositories that are a source (a.k.a. not a fork).

#+ATTR_ORG: :width 800px #+ATTR_LATEX: :width 800px #+ATTR_HTML: :width 800px [[https://github.com/armindarvish/consult-gh/blob/screenshots/screenshots/consult-gh-repo-list.gif]]

** Browsing Files in a Repository In the screenshot below, I use =consult-gh-find-file= to browse files of a repository. The command first uses =consult-gh-search-repos= to get a repo, then asks the user to select a branch before showing a list of files in that repo and branch.

#+ATTR_ORG: :width 800px #+ATTR_LATEX: :width 800px #+ATTR_HTML: :width 800px [[./screenshots/consult-gh-find-file.gif]]

** Searching/Viewing Issues or Pull Requests In the screenshot below, I use =consult-gh-search-issues= to search for issues and then view them inside Emacs. The screenshot shows the updated capabilities with consult-async:

  • The results are dynamically updated when the entry is changed.
  • Command line arguments to =gh= can be added on demand from the minibuffer. For example entering =consult-gh -- --assignee=@me= shows the search results for the keyword "consult-gh" and then filters the results to issues assigned to me. adding another command line argument to sort =consult-gh -- --assignee=@me --sort created= further sorts the issues by the date they were created.
  • Search keywords are highlighted inside minibuffer (a visual guide to see what matches the search term)
  • Search keywords are also highlighted inside preview buffers.

#+ATTR_ORG: :width 800px #+ATTR_LATEX: :width 800px #+ATTR_HTML: :width 800px [[https://github.com/armindarvish/consult-gh/blob/screenshots/screenshots/consult-gh-search-issues.gif

Pull requests can be searched similary by using =consult-gh-search-prs=.

** Searching for code In the screenshot below, I use =consult-gh-search-code= to search for some code on github. For example I search for =deque=, then I add some command line arguments to limit the search to python files only (e.g. =deque -- --language==python=). When a preview is opened, consult-gh open the file containing the code and tries to find the region where the code is. This enables the user to interactively use the github code search, find relevant files and jump right to where the relevant code is used in the file.

#+ATTR_ORG: :width 800px #+ATTR_LATEX: :width 800px #+ATTR_HTML: :width 800px [[https://github.com/armindarvish/consult-gh/blob/screenshots/screenshots/consult-gh-search-code.gif]]

** Embark Integration Consult-GH also provides embark integration defined in =consult-gh-embark.el= If you use [[https://github.com/oantolin/embark][Embark]], you can use these commands for additional actions on items in consult-gh menu. For example, you can set your default action for repos bound to =consult-gh-repo-browse-url-action= which opens the repo's url in a browser, but then call embark on any item for running alternative actions such as =consult-gh-repo-clone= or =consult-gh-repo-fork= etc. You can also call embark and select items with =embark-select= (by default bound to =SPC=) before running some commands on all of them, for example select multiple repos and run clone for all of them.

[[https://github.com/armindarvish/consult-gh/blob/screenshots/screenshots/consult-gh-embark.gif]]

** Magit/Forge Integration If you use [[https://github.com/magit/forge][forge]] to see issues of GitHub repositories, you can use the =consult-gh-forge= to directly open issues in a magit/forge buffer. In addition, you can edit issues in a forge buffer as you would normally do by =forge-edit-post=, =forge-create-post=, etc. Here it is in action:

#+ATTR_ORG: :width 800px #+ATTR_LATEX: :width 800px #+ATTR_HTML: :width 800px [[https://github.com/armindarvish/consult-gh/blob/screenshots/screenshots/consult-gh-forge.gif]]

*** Set Up and Customization of Forge Integration Warning: Before you decide to use =consult-gh-forge=, be aware that due the way magit/forge is implemented, it is deeply integrated with magit and its different components (like ghub) and everything is intended for a git repository with a =.git= folder path to work otherwise =magit= will show errors. As a result, I had to reimplement some of the functionalities in magit and forge, to ensure that =consult-gh-forge= works without those errors and also does not break magit or forge. But this is still highly experimental and you may experience bugs and issues with magit and forge if you decide to integrate =consult-gh= with magit/forge. Also, dependence on the =magit/forge= package may cuase maintainability issues down the road. So use this at your own risk.

To use =consult-gh-forge=, make sure that both [[https://github.com/magit/magit][magit]] and [[https://github.com/magit/forge][forge]] are installed and loaded before loading consult-gh and then add =require 'consult-gh-forge= to your config. An example of a minimal config:

#+begin_src emacs-lisp (use-package consult-gh :straight (consult-gh :type git :host github :repo "armindarvish/consult-gh") :after forge :config (require 'consult-gh-embark) (require 'consult-gh-forge) (setq consult-gh-preview-key "M-o") (setq consult-gh-repo-action #'consult-gh--repo-browse-files-action) (setq consult-gh-file-action #'consult-gh--files-view-action) (setq consult-gh-issue-action #'consult-gh-forge--issue-view-action) ;;this enables opening issues in magit/forge buffer (setq consult-gh-forge-timeout-seconds 20) ;;maximum time inseconds for consult-gh to try opening issuers in forge, and then reverts back to opening in normal emacs buffer with consult-gh-issue--view. ) #+end_src

Note that we are trying to keep =consult-gh-forge= edits of forge database transparent. Therefore a list of all the repositories that are added to =forge-database= is stored under the variable =consult-gh-forge-added-repositories= and interactive commands are provided to remove them from =forge-databse= either all at once (by using =consult-gh-forge-remove-added-repositories=) or by interactive selection through =consult-gh-forge-remove-repository=. This can still be done by =forge-remove-repository= as well, but consult-gh versions provide a transparent way to only remove the forge repositories added by consult-gh.

Keep in Mind: consult-gh adds temporary folders to =consult-gh-tempdir= in order to do magit/forge actions, and therefore you may face issues when those temporary folders are deleted on system restarts. In this case, you may want to use =consult-gh-forge-remove-added-repositories= to clean up forge-database and then you should be able to use =consult-gh-forge--issue-view= normally again.

With =consult-gh-forge=, you get one more "customization" variable as well:

**** =consult-gh-forge-timeout-seconds= This variable sets the maximum time in seconds that =consult-gh-forge= tries to load an issue in forge buffer, and if for some reason, it cannot do so, it reverts back to using =consult-gh-issue-=-view= function that opens the issue in a normal emacs buffer. This provides a fail safe mechanism in case there are issues with magit/forge. By default, it is set to 10 seconds, which should be sufficient for most issues to load but this depends on your network performance and the size of the content that needs to be downloaded. Some issues especially the ones with many comments and posts can take longer to load depending on your network performance. If you experience this often, you may want to consider adjusting this variable to even longer times. On the other hand, if there is an issue with magit/forge, consult-gh would not try to open the issue in a normal buffer before the reaching the timeout time!

** Transient Menu After the major update on October 2023, consult-gh now has a transient menu. It can be accessed by running =M-x consult-gh= after loading consult-gh-transient module. Just make sure that the transient package is installed before loading consult-gh-transient.

#+begin_src emacs-lisp (use-package consult-gh :straight (consult-gh :type git :host github :repo "armindarvish/consult-gh") :after forge transient :config (require 'consult-gh-embark) (require 'consult-gh-transient) ) #+end_src

#+ATTR_ORG: :width 800px #+ATTR_LATEX: :width 800px #+ATTR_HTML: :width 800px [[https://github.com/armindarvish/consult-gh/blob/screenshots/screenshots/consult-gh-transient.gif]]

  • Bug reports To report bug, first check if it is already reported in the [[https://github.com/armindarvish/consult-gh/issues][issue tracker]] and see if there is an existing solution or add relevant comments and discussion under the same issue. If not file a new issue following these steps:
  1. Make sure the dependencies are installed, and you are logged in by running =gh auth login= in the terminal.

  2. Make sure that dependencies (i.e. =consult= and =gh=) work properly independent of Consult-GH. You can for example run some other consult commands (e.g. =consult-buffer=) to make sure the problem is not form consult and run some =gh= commands in the shell (i.e. =gh repo list=) to see if they are working properly. If the problem is from consult or gh, please refer to their manuals and documentation.

  3. Remove the package and install the latest version (along with dependencies) and see if the issue persists.

  4. In a bare bone vanilla Emacs (>=28) (e.g. =emacs -Q=), install the latest version of Consult-GH (and its dependencies) without any configuration or other packages and see if the issue still persists.

  5. File an issue and provide important information and context in as much detail as possible in your bug report. Important information can include:

  • Your operating system, version of Emacs (or the version of emacsen you are using), version of gh (run =gh --version= in a shell), version of consult (see [[https://github.com/emacsorphanage/pkg-info][pkg-info]]).
  • The installation method and the configuration you are using with your Consult-GH.
  • If there is an error message, turn debug-on-error on (by =M-x toggle-debug-on-error=) and include the backtrace content in your report.
  • If the error only exists when you have some other packages installed, list those packages (e.g. problem happens when evil is installed)
  • Contributions This is an open source package, and I appreciate feedback, suggestions, ideas, etc.

If you want to contribute to the code, please note that the main branch is currently stable (as stable as a work in progress like this can be) and the develop branch is the current work in progress. So, start from the develop branch to get the latest work-in-progress updates and create a new branch with names such as feature/name-of-the-feature or fix/issue, ... Do the edits and then create a new pull request to merge back with the develop branch when you are done with your edits. Importantly, keep in mind that I am using a literate programming approach (given that this is a small project with very limited number of files) where everything goes into consult-gh.org and then gets tangled to appropriate files (for now that includes consult-gh.el and consult-gh-embark.el). If you open a pull-request where you directly edited the .el files, I will likely not approve it because that will then get overwritten later when I tangle from the .org file. In other words, Do Not Edit The .el Files! only edit the .org file and tangle to .el files.

  • Acknowledgments Obviously this package would not have been possible without the fabulous [[https://github.com/minad/consult][Consult]] package. It also took inspiration from other packages related to consult as well as [[https://github.com/sigma/gh.el][gh.el]], [[https://github.com/magit/forge][magit/forge]] and some other GitHub related work. Special thanks to the maintainer of consult package, [[https://github.com/minad][Daniel Mendler]], for useful advice, feedback and discussion.